Zombies

Date: 1981
Type: Cassette
Platform(s): TS 1000
Tags: Game

Zombies is a real-time maze-avoidance game in which the player navigates an island grid using the numeric keys 1–8 (representing eight compass directions) while trying to lure blind, sound-detecting zombies into potholes. The playing field is a 10×32 grid of border characters, randomly populated with “Z” zombie characters and at least one “O” pothole during setup, and the display file base address is obtained via PEEKs of system variables 16396–16397 for direct screen manipulation. Zombie movement uses a simple Manhattan-distance heuristic: each zombie shifts one cell horizontally and/or vertically toward the player’s current position each turn. The player’s position and all zombie positions are tracked as linear offsets into the display file, with each screen row being 33 bytes wide (32 characters plus a newline). PAUSE 55555 followed by POKE 16437,255 and INKEY$ forms the standard interrupt-driven keypress detection idiom for this platform.


Program Analysis

Program Structure

The program is organized into a main initialization block, a game loop, and a subroutine for the title/instructions screen:

  1. Lines 0–9: Declarations, variable initialization, and array allocation (DIM Z(40) for up to 40 zombie positions).
  2. Lines 10–181: Screen construction — draws the border wall of O characters, randomly scatters zombies (Z) and potholes (O), and prints the movement key legend.
  3. Lines 188–246: Player turn — places the player character (61 = =) at a random empty cell, waits for a valid key (1–8), computes the target cell, and moves or triggers a collision.
  4. Lines 300–435: Zombie AI turn — iterates over all live zombies, moves each one step toward the player using a coordinate-difference heuristic.
  5. Lines 500–610: Collision resolution — distinguishes player capture, zombie–zombie collision, and zombie-into-pothole events.
  6. Lines 700–750: End-of-game screen, replay prompt, and CLEAR/restart loop.
  7. Lines 1000–1150: Title screen and instructions subroutine, called once at startup via GOSUB 1000.

Display File Manipulation

Rather than using PRINT AT for every game element, the program obtains the display file base address at line 189:

LET DF=PEEK 16396+256*PEEK 16397

System variables at addresses 16396–16397 hold the low and high bytes of the display file pointer. All subsequent player and zombie movement is done with PEEK and POKE directly into this address space, which is considerably faster than interpreted PRINT AT calls and essential for a real-time game.

Each screen row is treated as 33 bytes wide (32 character cells plus a newline byte), so a zombie’s or player’s screen position is stored as a single linear offset. Row and column are recovered by integer division and modulo with 33 (lines 300–340).

Character Encoding Used as Game State

The program exploits the numeric values of display-file character codes to distinguish game objects without a separate state array:

PEEK valueCharacterGame object
0(space)Empty cell
52O (rendered)Pothole / border wall
61=Player
63ZZombie

Note that the border walls and potholes share the same character code (52 for O), so the collision handler at line 250 checks specifically for code 63 (zombie) to distinguish zombie-mouth from pothole collisions; anything else is assumed to be a wall or pothole.

Zombie AI Heuristic

Lines 350–390 implement a step-by-step pursuit algorithm. For each zombie, the row offset B is set to +33, −33, or 0 depending on whether the zombie is above, below, or level with the player. Then the column delta (+1, −1, or 0) is added. This produces a diagonal step toward the player in one move, making zombies aggressive and fast. The algorithm is deterministic — every zombie always moves toward the player with no randomness or pathfinding around obstacles.

Eight-Directional Movement Encoding

Line 241 computes the target offset B from the current offset Q using a compact Boolean arithmetic expression:

LET B=Q+(A=1 OR A=2 OR A=3)-(A=7 OR A=6 OR A=5)+33*(A=5 OR A=4 OR A=3)-33*(A=7 OR A=8 OR A=1)

On this platform, Boolean expressions evaluate to 1 (true) or 0 (false), so this single line simultaneously computes the column delta (±1) and row delta (±33) for all eight directions from the numpad layout printed on screen. This avoids a lookup table or multi-line conditional block.

Keypress Detection Idiom

Lines 220–231 and 710–720 use the standard pattern: PAUSE 55555 (a very long pause, effectively waiting for a keypress interrupt), followed by POKE 16437,255 to re-enable the keyboard, then INKEY$ to read the key. The PAUSE 55555 returns early when any key is pressed, making the sequence an efficient blocking key-read without a busy loop.

Zombie Position Array

The array Z(40) stores each zombie’s current display-file offset. Dead zombies (eliminated by falling into a pothole) are flagged with Z(A)=-1 at line 510, and line 325 skips negative entries during the movement loop. The counter N tracks surviving zombies; when N=0, the player wins (lines 545–560).

Random Grid Population

Lines 80–110 use Q=INT(RND*2000) to randomly decide the content of each interior cell. Values in the range 1795–1849 place a zombie; values ≥1850 place a pothole (O). This gives approximately a 2.75% chance of a zombie and a 7.5% chance of a pothole per cell, with the remaining ~89.75% left empty. The zombie’s display-file offset is stored as A*33+B+1, consistent with the 33-bytes-per-row convention.

Notable Anomalies

  • Line 11 defines A$ as the splash string “SPLASH GOES A ZOMBIE” (using inverse-video block characters for spaces), but this variable is immediately overwritten at line 1140 by the INKEY$ result from the title screen. The intended A$ splash message is only restored to the correct string if the game is restarted via GOTO 3, which does not re-run the GOSUB 1000 subroutine — so after the first playthrough, A$ at line 535 correctly prints the splash message set at line 11 on restart.
  • Line 610 POKEs the zombie’s destination cell with code 63 (zombie) after the player has been eaten, which is cosmetically redundant since the game ends immediately after.
  • The movement key “9” (center / no-move) is absent; the guard at line 231 rejects keys outside “1”–”8″, so the player must always move.
  • Border walls share character code 52 with potholes, making it impossible to distinguish walking into a wall from falling into a pothole by PEEK alone — both trigger the “OOPS INTO A POTHOLE” message at line 266, which is technically incorrect for wall collisions.

Content

Appears On

Related Products

In Sword Of Peace, free yourself from a dungeon to prove yourself worthy of becoming the Monarch of Oz. Zombies:...

Related Articles

Related Content

Image Gallery

Source Code

   0 REM (C)1981 ARTIC COMPUTING
   1 GOSUB 1000
   3 CLS
   4 LET P2=0
   5 LET Z2=0
   6 LET Z1=0
   8 DIM Z(40)
   9 LET Z=0
  10 FAST
  11 LET A$="[S][P][L][A][S][H]█[G][O][E][S]█[A]█[Z][O][M][B][I][E]"
  16 LET P1=0
  18 FOR A=1 TO 32
  20 PRINT "O";
  30 NEXT A
  40 PRINT 
  50 FOR A=1 TO 10
  60 PRINT "O";
  70 FOR B=1 TO 30
  80 LET Q=INT (RND*2000)
  90 IF Q<1795 THEN GOTO 120
 100 IF Q>=1850 THEN GOTO 110
 102 PRINT AT A,B;"Z"
 103 LET Z=Z+1
 104 LET Z(Z)=A*33+B+1
 110 IF Q>=1850 THEN PRINT AT A,B;"O"
 120 NEXT B
 130 PRINT AT A,31;"O"
 140 NEXT A
 150 FOR A=1 TO 32
 160 PRINT "O";
 170 NEXT A
 171 PRINT 
 172 PRINT 
 173 PRINT 
 178 PRINT "MOVEMENT"
 179 PRINT "7 8 1"
 180 PRINT "6 X 2"
 181 PRINT "5 4 3"
 182 SLOW
 188 LET N=Z
 189 LET DF=PEEK 16396+256*PEEK 16397
 190 LET Q=INT (RND*320+1)
 200 IF PEEK (DF+Q)<>0 THEN GOTO 190
 210 POKE DF+Q,61
 220 PAUSE 55555
 221 POKE 16437,255
 230 LET B$=INKEY$ 
 231 IF B$<"1" OR B$>"8" THEN GOTO 220
 240 LET A=VAL B$
 241 LET B=Q+(A=1 OR A=2 OR A=3)-(A=7 OR A=6 OR A=5)+33*(A=5 OR A=4 OR A=3)-33*(A=7 OR A=8 OR A=1)
 242 IF PEEK (DF+B)<>0 THEN GOTO 250
 243 POKE DF+Q,0
 244 POKE DF+B,61
 246 LET Q=B
 247 GOTO 300
 250 IF PEEK (DF+B)=63 THEN GOTO 280
 260 POKE DF+B,52
 265 POKE DF+Q,0
 266 PRINT AT 18,5;"OOPS INTO A POTHOLE"
 270 GOTO 700
 280 PRINT AT 18,1;"STRAIGHT INTO A ZOMBIES MOUTH"
 285 POKE DF+Q,0
 290 GOTO 700
 300 LET P1=INT (Q/33)
 310 LET P2=Q-P1*33
 312 PRINT AT 12,0;"                           "
 320 FOR A=1 TO Z
 325 IF Z(A)<0 THEN GOTO 435
 330 LET Z1=INT (Z(A)/33)
 340 LET Z2=Z(A)-Z1*33
 350 IF Z1<P1 THEN LET B=33
 360 IF Z1>P1 THEN LET B=-33
 370 IF Z1=P1 THEN LET B=0
 380 IF Z2<P2 THEN LET B=B+1
 390 IF Z2>P2 THEN LET B=B-1
 400 POKE DF+Z(A),0
 410 IF PEEK (DF+Z(A)+B)<>0 THEN GOTO 500
 420 POKE DF+Z(A)+B,63
 430 LET Z(A)=Z(A)+B
 435 NEXT A
 440 GOTO 220
 500 IF PEEK (DF+Z(A)+B)=61 THEN GOTO 600
 510 LET Z(A)=-1
 520 LET N=N-1
 530 IF PEEK (DF+Z(A)+B)=63 THEN GOTO 435
 535 PRINT AT 12,0;A$
 545 IF N=0 THEN GOTO 560
 550 GOTO 435
 560 PRINT AT 18,5;"WELL DONE"
 562 PRINT "ZOMBIES ARE KILLED"
 570 GOTO 700
 600 PRINT AT 18,1;"YUM YUM YOU HAVE BEEN EATEN"
 610 POKE DF+Z(A)+B,63
 700 PRINT 
 701 PRINT "PRESS N/L TO PLAY AGAIN"
 710 PAUSE 55555
 711 POKE 16437,255
 720 LET B$=INKEY$ 
 721 IF CODE B$<>118 THEN STOP
 730 CLEAR
 750 GOTO 3
 1000 PRINT AT 0,9;"█[Z][O][M][B][I][E][S]█"
 1010 PRINT 
 1015 PRINT 
 1020 PRINT "YOU HAVE CRASHED ON A ISLAND"
 1025 PRINT 
 1030 PRINT "THE ISLAND IS INHABITED BY"
 1035 PRINT 
 1045 PRINT "MAN EATING ZOMBIES."
 1050 PRINT 
 1055 PRINT 
 1060 PRINT "THE ZOMBIES ARE BLIND BUT THEY"
 1065 PRINT 
 1070 PRINT "DETECT YOU BY THE SOUND OF YOUR"
 1075 PRINT 
 1080 PRINT "HEART BEAT. YOUR ONLY HOPE IS"
 1085 PRINT 
 1090 PRINT "LURE THEM INTO THE POTHOLES."
 1100 PRINT 
 1105 PRINT 
 1110 PRINT "PRESS ANY KEY WHEN READY"
 1120 PAUSE 55555
 1130 POKE 16437,255
 1140 LET A$=INKEY$ 
 1150 RETURN

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top