0
votes

This might be a more mathematical question, but I'm trying to get my head around how I can program an unbeatable AI for a ping pong game. From what I have read so far, it would be to simulate the trajectory of a ball when it is moving in the direction towards the AI Paddle.

In this game I have a ball and I can read its x and y position on the board, and then read it again in the next iteration which will allow me to calculate the velocity in the x and y direction.

But I'm not sure how to program how and where the ball will reach the AI paddle's goal position, and consider how many times the ball will bounce off the walls will requires me to use some geometry. But I can't get my head around it and how I will be programming it.

So far what I have thought of is the variables I've been given: the size of the table in x and y direction, the position of the ball "currently" and before in order to get its velocity in x and y direction. My first assumption is to find out a way to calculate whether the ball will hit the walls or the AI goal side instead?

1
This looks like a fun project, but you need to be a bit further along before anyone here can help. Start programming it, and when you have a specific code problem, post it in here for assistance!Alan

1 Answers

2
votes

There is a more direct way of doing this instead of repeated "raycasting":

def predict(x, y, vx, vy, h, b):
    """
    :param x: ball x position
    :param y: ball y position
    :param vx: ball x velocity
    :param vy: ball y velocity
    :param h: the field height
    :param b: the y position the prediction is for
    :return: ball x position at y = b
    """
    m = vy / vx # slope
    c = -x * m + y # y-intercept
    val = (m * b + c) % (2 * h)
    return min(val, 2 * h - val)

Now, step by step

m = vy / vx # slope
c = -x * m + y # y-intercept
val = (m * b + c)

A simple linear function showing the ball's current path.

This works, but only if the ball never hits a side wall.

A Model

Imagine there were fields with the same height on both sides of the original one, stretching into infinity.

Now 'the number of bounces' has become 'the number of cells the ball travels'.

Additionally, if the number of bounces is even, the distance from the lower border of the cell it hits to the point of impact is the same as the height the actual ball would hit at in the real cell.

Therefore

(m * b + c) % (2 * h)

To cover odd bounces as well, you need to mirror the graph around h.

Here is a graphic explanation:

A graphic explanation

And since the irrelevant graph is the one with values above h, you take the minimum.

Possible Problems

In some languages, the % is a remainder operator, though not python.

If the predictions are negative in some cases add this.

val = ((m * b + c) % (2 * h) + 2 * h) % (2 * h)

This function depends on 'accurate' collision.

So if the bounces are handled in a way similar to this,

if y not in range(0, y_max):
    vy *= -1

the predictions will be slightly off.

If you can change the core game, use

if y < 0:
    y *= -1
    vy *= -1
elif y > y_max:
    y = 2 * y_max - y
    vy *= -1

A divide by zero exception will be thrown if vx is 0, but since the ball will never hit a wall in this case, this should be handled by the ball movement logic.