pong: make computer perfect
Stefan Schuermans

Stefan Schuermans commited on 2019-06-15 14:24:14
Showing 2 changed files, with 88 additions and 45 deletions.

... ...
@@ -126,74 +126,99 @@ void Pong::timeCall()
126 126
   planTimeCall();
127 127
 }
128 128
 
129
-/// computer player for left pad
130
-void Pong::computerLeft()
129
+/**
130
+ * @brief computation of ideal pad position for computer players
131
+ * @param[in] padBallX x coordinate of position of ball when hitting the pad
132
+ * @param[in] padY current y coordinate of pad
133
+ * @param[out] padYmin minimum ideal y position of pad
134
+ * @param[out] padYmax maximum ideal y position of pad
135
+ */
136
+void Pong::computerComputePadPos(int padBallX, int padY,
137
+                                 int &padYmin, int &padYmax) const
131 138
 {
132
-  // ball not moving towards pad: do not move
133
-  if (m_ballDirX >= 0) {
139
+  // ball not moving towards pad
140
+  if ((padBallX - m_ballPosX) * m_ballDirX <= 0) {
141
+    // do not move if ball is still close to pad
142
+    if (abs(padBallX - m_ballPosX) <= 2) {
143
+      padYmin = padY;
144
+      padYmax = padY;
145
+      return;
146
+    }
147
+    // move pad to middle (might be 2 pixels wide)
148
+    padYmin = (m_height - m_padSize) / 2;
149
+    padYmax = (m_height - m_padSize + 1) / 2;
134 150
     return;
135 151
   }
136 152
 
137 153
   // compute expected ball position at pad
138
-  int expectedY = m_ballPosY + (m_ballPosX - 1) * m_ballDirY;
139
-
140
-  // compute pad position to hit ball with center of pad
141
-  int padY = expectedY - m_padSize / 2;
142
-
143
-  // do not move pad out of field
144
-  if (padY < 0) {
145
-    padY = 0;
154
+  int ballPosX = m_ballPosX; // simulate were ball is going
155
+  int ballPosY = m_ballPosY;
156
+  int ballDirY = m_ballDirY;
157
+  while ((padBallX - ballPosX) * m_ballDirX > 0) { // while moving to pad
158
+    int deltaX = padBallX - ballPosX;
159
+    int deltaY = deltaX * m_ballDirX * ballDirY;
160
+    if (deltaY < -ballPosY) {
161
+      deltaY = -ballPosY;
162
+      ballPosX += deltaY * m_ballDirX * ballDirY;
163
+      ballPosY = 0;
164
+      ballDirY = 1;
165
+    }
166
+    else if (deltaY > m_height - 1 - ballPosY) {
167
+      deltaY = m_height - 1 - ballPosY;
168
+      ballPosX += deltaY * m_ballDirX * ballDirY;
169
+      ballPosY = m_height - 1;
170
+      ballDirY = -1;
171
+    } else {
172
+      ballPosX += deltaX;
173
+      ballPosY += deltaY;
146 174
     }
147
-  if (padY > m_height - m_padSize) {
148
-    padY = m_height - m_padSize;
149 175
   }
150 176
 
151
-  // move pad
152
-  if (m_leftPosY < padY) {
153
-    ++m_leftPosY;
154
-  }
155
-  else if (m_leftPosY > padY) {
156
-    --m_leftPosY;
157
-  }
177
+  // compute pad position to hit ball with center of pad
178
+  padYmin = ballPosY - m_padSize / 2;
179
+  padYmax = ballPosY - (m_padSize - 1) / 2;
158 180
 }
159 181
 
160
-/// computer player for right pad
161
-void Pong::computerRight()
182
+/**
183
+ * @brief move pad for computer players
184
+ * @param[in] padYmin minimum desired y position of pad
185
+ * @param[in] padYmax maximum desired y position of pad
186
+ * @param[in,out] padPosY y position of pad
187
+ */
188
+void Pong::computerMovePad(int padYmin, int padYmax, int &padPosY) const
162 189
 {
163
-  // ball not moving towards pad: do not move
164
-  if (m_ballDirX <= 0) {
165
-    return;
190
+  // move pad, do not move pad out of field
191
+  if (padPosY > padYmax && padPosY > 0) {
192
+    --padPosY;
166 193
   }
167
-
168
-  // compute expected ball position at pad
169
-  int expectedY = m_ballPosY + (m_width - 2 - m_ballPosX) * m_ballDirY;
170
-
171
-  // compute pad position to hit ball with center of pad
172
-  int padY = expectedY - m_padSize / 2;
173
-
174
-  // do not move pad out of field
175
-  if (padY < 0) {
176
-    padY = 0;
194
+  else if (padPosY < padYmin && padPosY < m_height - m_padSize) {
195
+    ++padPosY;
177 196
   }
178
-  if (padY > m_height - m_padSize) {
179
-    padY = m_height - m_padSize;
180 197
 }
181 198
 
182
-  // move pad
183
-  if (m_rightPosY < padY) {
184
-    ++m_rightPosY;
185
-  }
186
-  else if (m_rightPosY > padY) {
187
-    --m_rightPosY;
199
+/// computer player for left pad
200
+void Pong::computerLeft()
201
+{
202
+  int padYmin, padYmax;
203
+  computerComputePadPos(1, m_leftPosY, padYmin, padYmax);
204
+  computerMovePad(padYmin, padYmax, m_leftPosY);
188 205
 }
206
+
207
+/// computer player for right pad
208
+void Pong::computerRight()
209
+{
210
+  int padYmin, padYmax;
211
+  computerComputePadPos(m_width - 2, m_rightPosY, padYmin, padYmax);
212
+  computerMovePad(padYmin, padYmax, m_rightPosY);
189 213
 }
190 214
 
191 215
 /// bounce ball
192 216
 void Pong::bounceBall()
193 217
 {
194
-  bounceBallSide();
218
+  bounceBallSide(); // must be done before player bounce to be safe
195 219
   bounceBallLeft();
196 220
   bounceBallRight();
221
+  bounceBallSide(); // must also be done after player bounce to be safe
197 222
 }
198 223
 
199 224
 /// bounce ball at sides
... ...
@@ -61,6 +61,24 @@ protected:
61 61
   /// callback when requested time reached
62 62
   virtual void timeCall();
63 63
 
64
+  /**
65
+   * @brief computation of ideal pad position for computer players
66
+   * @param[in] padBallX x coordinate of position of ball when hitting the pad
67
+   * @param[in] padY current y coordinate of pad
68
+   * @param[out] padYmin minimum ideal y position of pad
69
+   * @param[out] padYmax maximum ideal y position of pad
70
+   */
71
+  void computerComputePadPos(int padBallX, int padY,
72
+                             int &padYmin, int &padYmax) const;
73
+
74
+  /**
75
+   * @brief move pad for computer players
76
+   * @param[in] padYmin minimum desired y position of pad
77
+   * @param[in] padYmax maximum desired y position of pad
78
+   * @param[in,out] padPosY y position of pad
79
+   */
80
+  void computerMovePad(int padYmin, int padYmax, int &padPosY) const;
81
+
64 82
   /// computer player for left pad
65 83
   void computerLeft();
66 84
 
67 85