algorithmartificial-intelligenceheuristicspong

How to improve Pong AI with limited game state checks?


I'm currently developing a Pong game for a school project. One rule I have is that the AI can only check the game state once every second.

Currently, the AI operates on two simple rules:

The physics of the game is pretty simple, if the ball hits a wall the velocity in x is reversed. If the ball hits a paddle, the ball is given a new velocity based on how far from the center of the paddle the collision occurred. The ball always travel at a constant speed.

    /* Update the angle of the ball based on where it hits the paddle */
    update_ball_velocity(paddle, normal) {
        const expanded =
            new physics.Rectangle(
                paddle.position.x - this.ball.size.x / 2,
                paddle.position.y - this.ball.size.y / 2,
                paddle.size.x + this.ball.size.x,
                paddle.size.y + this.ball.size.y,
                0,
                0
            );
        const ball_center =
            new physics.Vector(
                this.ball.position.x + this.ball.size.x / 2,
                this.ball.position.y + this.ball.size.y / 2
            );
        const paddle_center =
            new physics.Vector(
                expanded.position.x + expanded.size.x / 2,
                expanded.position.y + expanded.size.y / 2
            );

        if (normal.x != 0) {
            let c = ((ball_center.y - paddle_center.y) / (expanded.size.y / 2)) * g.BALL_MAX_ANGLE;
            this.ball.velocity.x = normal.x * Math.cos(c) * g.BALL_SPEED_MAX;
            this.ball.velocity.y = Math.sin(c) * g.BALL_SPEED_MAX;
        } else if (normal.y != 0) {
            let c = ((ball_center.x - paddle_center.x) / (expanded.size.x / 2)) * g.BALL_MAX_ANGLE;
            this.ball.velocity.x = Math.sin(c) * g.BALL_SPEED_MAX;
            this.ball.velocity.y = normal.y * Math.cos(c) * g.BALL_SPEED_MAX;
        }
    }

I am looking for algorithms / strategies / techniques to make the AI more capable. I don't want to use machine learning. More specifically, I would like to improve rule A, so that the AI does not just go back to the center of the board but maybe try to predict where the player will send the ball and start going towards that area.


Solution

  • Unless you are creating a Pong version that includes special physics you could use simple maths instead of a complete simulation...

    The movement of the ball is linear and constant, it will just bounce off the walls but bounces only create a change in the horizontal direction. This can be expressed using a simple Triangle Wave.

    y = abs( (freq*x + phase) % 2 - 1) * scale - offset
    

    With this, we can substitute some variables already.

    Now we also need to calculate the frequency, at what rate will the ball bounce... For this we calculate how much Y will it have to traverse to travel a full board's width. We can also simplify by just using the ratio they produce and divide them by the scale.

    freq = ballVelocityX / ballVelocityY / scale
    

    Last but not least we need to change the phase to get the origin perfectly aligned with the position of the ball. This will be between -1 and 1 depending on the direction and we'll convert to between 0 and 2.

    phase = ballX / BOARD_WIDTH
    

    The final result, in one formula by inverting X and Y:

    x = abs( ((ballVelocityX / ballVelocityY / BOARD_WIDTH)* y + ballX / BOARD_WIDTH) % 2 - 1) * BOARD_WIDTH
    

    Now to use it, we just need to use the Y distance between the ball and the paddle and we'll receive the X where the ball will end.

    EDIT:

    I was writing this answer while you changed your question. Since the ball's X will not change direction when a paddle is hit, it is very easy to figure out no matter the number of paddle hits it will have. Basically, you just sum the total distance and pass that to the formula. So if the board is 100 long and the balls is 10 away from the player's paddle, simple calculate for a distance of 110.

    Here's the graph I played with to see it in action. https://www.desmos.com/calculator/zr3g9wumrn

    function getTargetX(){
        let distance = this.game.ball.velocity.y <0 ? this.game.player1.position.y-this.game.ball.position.y + g.BOARD_HEIGHT : this.game.ball.position.y -this.game.player2.position.y;
        return Math.abs( ((this.game.ball.velocity.x / this.game.ball.velocity.y / BOARD_WIDTH)* distance + this.game.ball.position.x / g.BOARD_WIDTH) % 2 - 1) * g.BOARD_WIDTH
    }
    

    EDIT 2:

    To be able to account for the change of direction when hitting a paddle, which in this answer was considered a simple Y inversion, you could calculate where the ball will be when hitting the paddle and calculate the min-max range of the paddles length that can possibly hit the ball when considering the remaining time the paddle has to move before hit.

    Since we do not know if the paddle movement is a force applied or a constant vector I can't really tell the strategy to calculate it. The min-max will then allow you to calculate the min/max angle at which the ball will bounce the paddle.

    The AI could then make sure to cover the most dangerous angle, which will be 90degrees since that would make the ball hit the paddle the fastest. That degree can then be used to create the possible new ball vector to use in the formula. This will provide the fastest collision point.

    You could also use the min-max angles to calculate let's say 10 different degrees in that arc and average the collision points. That would provide with the most probable position of the collision. The AI would then adjust the next second but would already be somewhat close.

    You can combine the two and use a weighted average to give better importance to a position according to a ratio between time for paddle to get there VS time for ball to get there. That would make a ball go almost horizontally have way less impact on the calculated average, because it will certainly take multiple seconds to reach de collision point, so adjustments will have time to happen.