Pac-Man
Namco's 1980 arcade maze game, read through Mark Burkley's C translation of Midway's release.
On this page
The atlas reads Pac-Man through Mark Burkley’s C translation of the ROM, which keeps every Z80 instruction as a comment and loads the program ROMs of MAME’s pacman set, Midway’s release1. Function names and comments cited here are his. Where a result hangs on 8-bit arithmetic, the atlas cites the kept Z80.
Each ghost chases a target tile of its own. Blinky targets Pac-Man, Pinky a tile ahead of him, Inky a point set by both Pac-Man and Blinky, and Clyde Pac-Man only from far away1. At each step a ghost takes the open direction that leaves it closest to its target and never reverses on its own2. Scatter and chase phases alternate, four of each, and the last chase phase never ends3.
Frightened ghosts wander by a random number generator whose table is the game’s own program ROM4.
Mechanics
| Mechanic | Kind | How |
|---|---|---|
| Enemy targeting | Target tile | each ghost steers toward its own target tile, picking the move that brings it closest |
| Random number generator | ROM as table | a pointer stepped by 5p + 1 mod 8192 reads the game's own ROM as its table |
| Difficulty ramp | Level table | each level advances one entry along a DIP-selected table until it reads 20 |
| Extra life | Once | one life at 10,000 points, or 15,000 or 20,000 by DIP switch |
| High score | Single | one six-digit high score, checked after every score change |
| Kill screen | Draw overflow | on level 256 the fruit row's loop count wraps to 0 and runs 256 times |
Every claim about this game, by concept (8)
References
- ^ abIn chase mode each Pac-Man ghost steers toward its own target tile. Blinky targets Pac-Man's tile. Pinky targets Pac-Man's tile plus 4 times his direction vector, and Inky takes Pac-Man's tile plus twice the vector, doubles it, and subtracts Blinky's tile. The Z80 does both sums as 16-bit adds of a packed two-byte tile and vector (
add hl,hl,add hl,de), so a carry out of the low byte's axis spills into the other axis; away from such a carry, Pinky's target is 4 tiles ahead of Pac-Man and Inky's starts 2 ahead. Clyde targets Pac-Man's tile while the squared distance between them is 64 or more, that is 8 tiles or farther, and otherwise heads for his scatter corner. The translation reads MAME'spacmanset, Midway's release.Codemburkley/pacman-crevisedHow we know
11479 BLINKY_VECTOR2 = findBestOrientation_2966 (BLINKY_TILE, PACMAN_TILE2, &BLINKY_ORIENTATION);pacman.c line 11479 at 3277e56 · upstream ↗ 11525 /* Make a target tile for pinky that is 4 times pacman's current direction 11526 * of travel plus pacman's current tile */ ⋮ 11539 PINKY_VECTOR2 = findBestOrientation_2966 (PINKY_TILE, target, &PINKY_ORIENTATION);
pacman.c lines 11516–11539 at 3277e56 · upstream ↗ 11584 /* Inky tries to get pacman in a pincer movement with blinky so he targets 11585 * a tile that is 2 tiles ahead of pacman's current vector and then twice 11586 * the vector between that tile and blinky's tile */ ⋮ 11597 target.y = target.y * 2 - BLINKY_TILE.y; ⋮ 11605 target.x = target.x * 2 - BLINKY_TILE.x;
pacman.c lines 11576–11617 at 3277e56 · upstream ↗ 11637 random: ⋮ 11648 XYPOS target = { 0x40, 0x3b }; ⋮ 11661 uint16_t dist = computeDistance_29ea (PACMAN_TILE2, CLYDE_TILE); ⋮ 11669 if (dist < 0x40) 11670 goto random; ⋮ 11682 findBestOrientation_2966 (CLYDE_TILE, PACMAN_TILE2, &CLYDE_ORIENTATION);
pacman.c lines 11637–11682 at 3277e56 · upstream ↗ 12131uint16_t computeDistance_29ea(XYPOS ix, XYPOS iy) ⋮ 12139 int b = ix.y - iy.y; ⋮ 12152 uint16_t hl = calcSquare_2a12(b); ⋮ 12161 b = ix.x - iy.x; ⋮ 12178 hl += calcSquare_2a12(b);
pacman.c lines 12131–12178 at 3277e56 · upstream ↗ 20pacman.6e \ 21pacman.6f \ 22pacman.6h \ 23pacman.6j \
Makefile lines 20–23 at 3277e56 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^
findBestOrientation_2966turns a target into a move: it tries the four directions in turn, skips the reverse of the ghost's current one and any that points into a maze wall, and keeps the one whose next tile has the smallest squared distance to the target; on a tie the later direction wins.Codemburkley/pacman-cHow we know
11993XYPOS findBestOrientation_2966 (XYPOS hl, XYPOS de, uint8_t *a) ⋮ 12008 OPPOSITE_ORIENTATION = *a ^ 2; ⋮ 12014 MIN_DISTANCE_FOUND = 0xffff; ⋮ 12032 if (OPPOSITE_ORIENTATION != TRIAL_ORIENTATION) ⋮ 12054 /* If the trial orientation points us at a maze wall then ⋮ 12067 uint16_t dist = computeDistance_29ea (DEST_TILE_POS, TMP_RESULT_POS); ⋮ 12079 if (MIN_DISTANCE_FOUND >= dist) ⋮ 12106 while (++TRIAL_ORIENTATION < 4);
pacman.c lines 11993–12106 at 3277e56 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^A mode counter at
$4DC1runs from 0 to 7: on even values the ghosts head for fixed scatter tiles, on odd values they chase.ghostsChangeOrientation_0e36counts time and steps the counter when the count meets a 16-bit entry for the current mode, then flags all four ghosts to reverse. At 7 it stops, so the game holds four scatter phases and leaves the fourth chase phase on for good. The count pauses while Pac-Man is powered up.Codemburkley/pacman-cHow we know
4167void ghostsChangeOrientation_0e36 (void) ⋮ 4174 if (PACMAN_POWEREDUP) 4175 return; ⋮ 4182 if (NONRANDOM_MOVEMENT == 7) 4183 return; ⋮ 4191 ORIENTATION_CHANGE_COUNT++; ⋮ 4206 if (ORIENTATION_CHANGE_COUNT != DIFFICULTY_TABLE[NONRANDOM_MOVEMENT]) 4207 return; ⋮ 4214 NONRANDOM_MOVEMENT++; ⋮ 4222 BLINKY_ORIENT_CHG_FLAG = 4223 PINKY_ORIENT_CHG_FLAG = 4224 INKY_ORIENT_CHG_FLAG = ⋮
pacman.c lines 4167–4225 at 3277e56 · upstream ↗ 11434 if ((NONRANDOM_MOVEMENT & 1) == 0) ⋮ 11460 XYPOS target = { 0x1d, 0x22 }; 11461 BLINKY_VECTOR2 = ⋮ 11479 BLINKY_VECTOR2 = findBestOrientation_2966 (BLINKY_TILE, PACMAN_TILE2, &BLINKY_ORIENTATION);
pacman.c lines 11434–11479 at 3277e56 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^A frightened ghost picks a random direction from
random_2a23, which steps a pointer as and returns the byte at that address, so the game's own first 8 KB of ROM serve as the random table. The direction is the low 2 bits; a reversal or a wall sends it on to try the next one.Codemburkley/pacman-crevisedHow we know
12227/* Generates a random number by reading a byte from a randomised ROM address ⋮ 12246 RND_VAL_PTR = (RND_VAL_PTR * 5 + 1) & 0x1fff; 12247 return MEM[RND_VAL_PTR];
pacman.c lines 12227–12247 at 3277e56 · upstream ↗ 11905XYPOS randomDirection_291e (XYPOS hl, uint8_t *orientation) ⋮ 11921 BEST_ORIENTATION_FOUND = random_2a23() & 3; ⋮ 11942 /* Prohibit ghosts from doing u-turns */ ⋮ 11952 /* Ensure this direction is not into a wall */ ⋮ 11980 BEST_ORIENTATION_FOUND = (BEST_ORIENTATION_FOUND + 1) & 3;
pacman.c lines 11905–11980 at 3277e56 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
Sources
Code
- Burkley, Mark. 2025. “pacman-c: a C translation of the Pac-Man ROM.” Commit 3277e56. mburkley/pacman-c @ 3277e56 · licence, all uses