# Imperfect pong AI

So I'm starting to learn Java and some OpenGL while using the LWJGL. To start off easy, I'm writing a clone of the Atari Pong. I got set up correctly the game screen, collision detection, and all the game is mostly working, actually, if it were a 2 player game I'd be done by now, but as I'm planning on doing this a single player game, I have to come up with a simple AI to control the second player.

Knowing where the ball will hit seems fairly trivial, and creating an AI which always hits the ball seems like an easy thing to do, but I want the game to be able to be won, so I can't always make the IA hit the ball.

So here's my question, how should I code this to add human-like imperfections to the AI. Should I randomly decide if the AI is going to fail at a given point? Or there's an smarter (or maybe just obvious) thing I'm missing here?

Thank you very much.

• Well generally you make the AI bat only move a certain speed so if the ball is well placed by the player the AI can't reach it.. – The Cat Jun 13 '13 at 14:03
• I'd start by limiting the speed at which the AI can move the paddle, and/or building in a random (short) lag time before the AI begins to respond to a hit. – Henry Keiter Jun 13 '13 at 14:03
• possible duplicate of What makes a computer opponent feel alive? – MichaelHouse Jun 13 '13 at 14:59
• @byte56 I wouldn't really call it a dupe of that question. It feels like the example given here blog.stackoverflow.com/2011/01/… under "If you’re going to close a user’s question as a duplicate, it has to be a real duplicate". That question is a good resource (and somebody could probably use that question to derive an answer themselves given the content there), but it doesn't really answer the specifics of this question, I don't think. – Tetrad Jun 13 '13 at 21:26
• @Tetrad I think the answers end up being very similar, but, you're right, the questions are different. I think this question is kind of a more specific version of the linked question. Had the OP seen the other one first, I'm not sure if this question would have been asked. When I voted, I was undecided so I both upvoted the question and answers and voted as a duplicate. It could go either way for me. – MichaelHouse Jun 13 '13 at 21:41

My favourite imperfect pong AI is brutally simple, yet lets one do some rather nice AI failure.

# Invisible Ball AI

AI Setup: When the ball reflects off your paddle, you know where it is and how fast it is going. Spawn an invisible ball at that point but at a greater speed. It will wind up where the visible ball is going. Each frame, have the AI move towards the location of the invisible ball. Stop the invisible ball once it reaches the AI's side, so it is where the AI should move its paddle.

Results: The AI looks like it's trying to predict the path of the ball. Say the player has reflected the ball at a steep angle so that it will bounce off a wall. The AI will track the ball down a little ways, and then -- being slower than the ball -- will fail to track it back up fast enough. You have tricked the AI, and it looks fairly logical from a human point of view. You can see the computer trying to predict where the ball will go, and then -- oh, it missed, it was too slow, and you have won a point.

This is significantly better than inserting randomness, since it makes the AI look relatively intelligent. A worthy opponent. It also lets the AI play by the exact same rules as the human, which looks better to the player and makes your job easier.

Settings: You can also tweak the speed of the invisible ball, since that will determine how far ahead the AI will plan. The faster the invisible ball, the more time the paddle will have to move to block, and the better the player will have to aim.

• All the answers given provided really good info, but as I had to mark one to be the right answer, I chose this one as I really like your approach. This, combined with some other things said in other answers (like playing with the reaction time) might get a really human-like AI, and with an easy adjustable difficulty – Setzer22 Jun 17 '13 at 18:22
• This worked perfectly for my setup because I have variable angles, velocity, and acceleration based on certain special moves, so the ball can potentially be all over the place. The AI was getting owned, but now it's much better. I can see why this method isn't the best for locked speed and 45deg angles, but that's not my game at all. – jackrugile Jul 31 '16 at 0:11
• While I do like this approach, I did have issues with my implementation. The problem being that since the tracer ball moves faster than the ball it represents, it might miss some collisions that will happen to the ball it represents. Reason being, of course, that the tracer ball will move a greater distance between frames. – Wolfgang Schreurs Nov 16 '16 at 11:25
• If you want greater fidelity, you could recalculate the tracer ball position twice per frame and halve the speed for each calculation. – DDR Nov 19 '16 at 11:58

The Pong games I've played seem to behave the following way: the AI-controlled paddle knows where the ball will hit but is limited in how fastly it can reach that position. So sometimes it misses. I think this is the most obvious way to do that.

• This. Doesn't help the AI to know where the ball will hit if it can only move, say, 3px per frame and it has to move from the top to the bottom. – KeithS Jun 13 '13 at 19:46

When I created an oh-so-awesome almost-pacman clone on my TI83? calculator, the biggest problem I ran into was that the "ghosts" were far too fast. I had to slow them down somehow. So, I put in a big old sin(cos(tan(x-coordinate))) in there. Easier levels would do that calculation a few times, and harder levels would do only one of the operations.

The point is, REACTION TIME. Research what a typical human reaction time is, and add 10ms onto it. Use that as a starting point. As the levels get harder, remove time from the reaction time...which can be a simple Thread.sleep(time); for the AI. Wait that amount of time before the AI starts moving.

You can also control how fast the paddle moves, or, if you REALLY wanted to get complicated, determine where the ball will be based upon varying degrees of information...say only 2 pixels rather than a vector. Add angle modifiers to the walls to add a degree of randomness, forcing the AI to recalculate.

• Could you explain why exactly you used sin(cos(tan(x)))? – nullpotent Jun 13 '13 at 15:49
• cause i was young, stupid, and on a TI83, sin(cos(tan(x))) created a good unit of lag in the AI. Also because, to the best of my knowledge, the calculator did not have a wait command that could use milliseconds. Perhaps some clarity: I did not use the assembly or micro script or whatever language you can compile to run on those things. I used the in-firmware programming code (the prgm button). I had MAXIMUM 8 lines of code on screen at any given moment. I couldn't remember anything more complicated for a lagtime. – Russell Uhl Jun 13 '13 at 16:08
• I learned to program on the TI83's in-firmware code. Then I had to re-learn structured programing in C++. I'd say the TI83 taught me what spaghetti string code is, and why its bad. I haven't used a goto statement since. Good times though. – ContextSwitch Jun 13 '13 at 19:37
• oh good lord, the gotos. I revisit the code every now and then....and quickly give up. I have no idea how i managed to program this thing over a period of weeks during my math classes. – Russell Uhl Jun 13 '13 at 19:56
• No need to be defensive about your trig delay. Floating point math in a loop was a common way to do a pause in programs written several decades ago and your calculators performance/capabilities are in line with an early 80s era computer. – Dan is Fiddling by Firelight Jun 13 '13 at 20:53

If you simply slow down the paddle, then any time you hit the ball at an acute angle (i.e. moving up and down a lot instead of straight to the other side), the computer would almost always miss because the ball is moving up/down faster than the paddle can compensate.

Instead, what I would do is play with the speed of the paddle, and the point at which the AI reacts. For example:

• when the user hits the ball
• the AI can react immediately and go to where the ball will be. If it is fast enough, it will get there in time
• when the ball crosses the middle of the field
• the AI must wait until it crosses the middle of the field before reacting

Another thing to change is how the AI reacts. You've highlighted a strategy where the paddle always moves to the position where the ball will be. A person cannot always do that. They are more likely to follow the ball up and down, not knowing where exactly the ball will be when it gets to them due to all the bounces.

Thus, a more human method for reaction is to always move towards the ball. For example, if the ball is moving up, then the paddle moves up. If the paddle is fast enough, it can react to the bounces off the top and bottom. If it paddle is not fast enough, then it will over compensate by moving up when the ball moves up, but then when it bounces, the paddle may not be able to move down quick enough.

Lastly, you could play with the paddle size as well to increase/decrease the difficulty.

One factor to consider is randomness - human players always have some degree of variation in their play, so if you want your AI to seem human-like then you'll also want to have some variation in their play.

You can set up ranges for:

• Reaction time (how quickly the AI starts moving)
• Speed (how quickly the AI moves the paddle)
• Accuracy (how close the AI will get to where it actually wants to move their paddle, giving a chance to undershoot or overshoot where they want to be)

Then on each hit by the opponent, the AI can pick a value within those ranges and make its decisions (and movements) based on that. For easier AI opponents, you can make those ranges all rather poor, but also have wide ranges to give the AI some "lucky shots". For more difficult opponents, you can tighten those ranges and put them all in the "good" range.

I'm going to suggest a more general solution that isn't specific to just pong. I believe this could be applied to any game - not just pong. You want human like behavior, right? So that a human can feel like they're playing a human... and therefore by extension hope to win. So, what do you do?

Observe a human! How can a player lose at pong? Well, if we watch two pong players it's quite obvious. Usually, the loss is because the ball is simply too fast and the players reaction time was delayed. That's two parameters, one of which is adjustable. The other is the players ability to press the right direction. So you have an error frequency and a reaction frequency - both can be tuned depending on difficulty.

An easy AI would have higher input lag and more tendency to make random mistakes - where as a more difficult AI would be tuned to have these parameters geared to be difficult.

This can be applied to nearly any game - even one such as tic tac toe or even more complex models. This approach breaks down in more complicated scenarios but it is plenty sufficient where games in which the numbers of parameters and scope is narrow.

Here's a list of a few options, some of which have been covered already:

• Make smarter computer players aim the ball so that it's harder for the player to reach with lots of bounces, and do the opposite for easy opponents.
• A smart player will move their paddle towards the middle while the ball is on it's way to the opponent and they don't know where it will come back to.
• Before the final bounce it's harder for a human to predict where the ball will end up. Make the AI have a similar inaccuracy.
• Limit the speed of the paddle so it's slower than the ball. It needs to be less than half the vertical speed to miss with perfect play.
• Increase the speed of the ball based on difficulty, match duration, etc.
• Humans don't react instantaneously. AI players shouldn't either.
• Give the AI a random chance of making a mistake and missing the ball.

I did a small Pong clone too (in LUA).

My AI is very simple but it is not that bad, imho.

I just check for the y position of the ball and if lower I move the paddle down, if higher I move the paddle up.

Then, to fine tune difficulty, I increase or decrease the distance from the ball from which the computer paddle starts to move.