On this page
  1. Related
  2. Mechanics
  3. References
  4. Sources

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

MechanicKindHow
Enemy targetingTarget tileeach ghost steers toward its own target tile, picking the move that brings it closest
Random number generatorROM as tablea pointer stepped by 5p + 1 mod 8192 reads the game's own ROM as its table
Difficulty rampLevel tableeach level advances one entry along a DIP-selected table until it reads 20
Extra lifeOnceone life at 10,000 points, or 15,000 or 20,000 by DIP switch
High scoreSingleone six-digit high score, checked after every score change
Kill screenDraw overflowon level 256 the fruit row's loop count wraps to 0 and runs 256 times
Every claim about this game, by concept (8)
Difficulty rampEach new level advances a pointer one entry along a difficulty table until the entry reads $14 (20). The DIP switch picks the table: one runs 0, 1, 2, … 20 and reaches 20 on level 21; the other, which the comment calls hard, runs 1, 3, 4, 6, 7, 8, … 17, 20 and reaches 20 on level 16. Each entry selects a 6-byte record at $0796 that sets, among other things, the movement pattern and the ghosts' counters for leaving the house.Code
Enemy targetingIn 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's pacman set, Midway's release.Code
findBestOrientation_2966 turns 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.Code
A mode counter at $4DC1 runs from 0 to 7: on even values the ghosts head for fixed scatter tiles, on odd values they chase. ghostsChangeOrientation_0e36 counts 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.Code
Extra lifePac-Man awards one extra life when the score reaches the DIP-switch setting: 10,000, 15,000, or 20,000 points, or never. The table holds BCD thousands (10, 15, 20, and $FF for none). After each score change the code compares the score's ten-thousands and thousands digits with the setting, and a flag bit stops a second award.Code
High scorePac-Man keeps one high score, three BCD bytes at $4E88. After every change to a player's score it compares the score with it from the top byte down and, if the score is higher, copies the 3 bytes over and redraws it.Code
Kill screenThe level byte at $4E13 starts at 0 and gains 1 per level, so on level 256 it holds 255. The routine that draws the fruit row loads it and adds 1, and that inc a wraps to 0; 0 passes the "fewer than 8" test, and the draw loop, a djnz counted by that 0, makes 256 passes instead of at most 7. Each pass draws a fruit at HL, writes its color $400 higher, and moves HL on 2 bytes, so from $4004 the loop steps across about 512 bytes of the 1 KB video RAM at $4000 and the matching span of color RAM at $4400.Code
Random number generatorA frightened ghost picks a random direction from random_2a23, which steps a pointer as p←(5p+1)mod8192 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.Code

References

  1. ^ 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's pacman set, Midway's release.Codemburkley/pacman-crevised
    How 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.

    In the claim ledger

  2. ^findBestOrientation_2966 turns 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-c
    How 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.

    In the claim ledger

  3. ^A mode counter at $4DC1 runs from 0 to 7: on even values the ghosts head for fixed scatter tiles, on odd values they chase. ghostsChangeOrientation_0e36 counts 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-c
    How 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.

    In the claim ledger

  4. ^A frightened ghost picks a random direction from random_2a23, which steps a pointer as p←(5p+1)mod8192 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-crevised
    How 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.

    In the claim ledger

Sources

Code