AI – Aritificial Idiocy

Work continues on my Pong clone. Over the past few days I’ve managed to fix the collision detection on the bats and have been looking at simple AI for the computer’s bat.

Not really knowing what to do, I had a bit of a Google and came across all sorts of complex looking ways to make the bat chase the ball, but after trying a few I came to the realisation I was doing it all wrong…You see, Pong was originally created using discrete electronic components – basic logic gates, counters and that sort of thing. At best the machine could probably count, add and test if certain conditions were true or not. No fancy branching logic, or clever AI techniques since that’d mean adding more chips and wiring. The AI was a small part of the game, so all it had to do was work well enough and be convincing. It also had to be beatable, because who wants to play against an opponent who never loses?

I’d recently finished reading the excellent book Racing the Beam which explains in detail how various Atari 2600 (VCS) games worked, one of them being Pong. I’d read this book, enjoyed it, and then totally forgotten it explained the logic behind Pong’s AI.

Feeling a bit confused and wondering just how simple this AI routine must be, I asked for help on the YakYak forum. Amongst some useful ideas was this from Korruptor

When the ball is served, the top of the AI bat is aligned with the ball. The AI bat tracks the ball’s Y movement once it’s served, but skips every 8th update. It’ll reset itself and recover from the drift when the ball hits the top or bottom of the screen, as long as the ball is aligned with part of the bat. Otherwise it’ll carry on drifting and eventually miss.

This is really clever, but also really simple. After a bit of coding and testing I produced the following bit of code which while not totally perfect is good enough.

void Bat::Think(int x, int y, void *userData)
{
	static int skip = 0;
	if (userID == 1) {
		if (skip == MISS_FACTOR) {
			skip = 0;
		} else if (skip < MISS_FACTOR) {
 			if ((y == 0 || y == 192) &&
 (ypos == y || ypos+width == y)){
 				ypos = y;
 			} else {
 				int dy = ypos-y;
 				if (dy > 0) {ypos--;}
				if (dy < 0) {ypos++;}
			}

			skip++;
		}
	}
}

The ‘MISS_FACTOR’ is used to control how badly the computer plays. Setting it to 1 guarantees it’ll mostly miss, setting it to 8 makes it beatable, but only just. 4 seems a good compromise at the moment.

Now I need to add little touches that make the game fun and less mechanical. Things like altering the ball’s angle depending on where it touches the bats, and making the ball speed up if nobody misses for a while.

About James

I'm just a person who likes writing software in their spare time. I'm not an "indie games developer" and am not trying to escape my day job and live in the happy world of games dev. I'm more like one of those people that used to write games in their spare time in the 80s. My stuff would be PD or Shareware if this were the 80s or 90s. It's good to comment on the posts in here :)