Gulp is a Pac-Man-style maze game in which the player steers a character (O) through a maze, eating food dots (.) while being chased by a hunter (X). The program uses machine code via RAND USR calls at addresses 17116, 16514, and 17030 for performance-critical operations such as game logic and display rendering. Five selectable mazes are stored as encoded strings within the M$ array, with maze data packed into LET M$(MK TO ) assignments using embedded BASIC keyword tokens as compressed graphical data. Menu-driven options allow the player to adjust speed (1–9), grade/acceleration (1–9), reset the best score, save the game to tape, and view instructions across two screens.
Program Analysis
Program Structure
The program is organized into several functional blocks:
- Lines 1–80: Initialization — REM block containing machine code, inverse-video title REM, dimension of
M$, and constant setup. - Lines 310–350: Header display and string initialization for
M$andS$. - Lines 500–665: Main menu loop — displays options, reads a key A–G, and dispatches via computed GOTO.
- Lines 550–582: Maze selection (B), speed selection (C), grade selection (D), score reset (E), save (F).
- Lines 860–890: Subroutine at
RN=860— reads a numeric keypress (1–9) and converts it toN. - Lines 900–910: Subroutine at
SE=900— prints “SELECT ” prompt. - Lines 1000–1170: Two-page instructions screen, reached via menu option G.
Machine Code Integration
The machine code payload is stored in the REM statement at line 1 as raw bytes. Three distinct entry points are called via RAND USR:
| Address (decimal) | Address (hex) | Usage |
|---|---|---|
| 17116 | 0x42DC | Screen/display initialization, called at menu entry and instruction screens |
| 16514 | 0x4082 | Game-over handler, triggered when player occupies same cell as hunter |
| 17030 | 0x4286 | Post-game-over reset/restart routine |
The machine code occupies the REM at line 1, which begins at address 0x4009 (the standard ZX81 program area start). The loader noted in the program metadata transfers this block to the correct working addresses before execution. The REM data is 379 bytes long and contains a full Z80 routine including subroutine calls, block moves (ED B0 = LDIR), and conditional branching.
Maze Storage and Encoding
Five mazes are stored as long string assignments into M$(MK TO ), where MK=14, within lines 574–582. The maze strings use a mix of printable characters and embedded BASIC keyword tokens (represented as single bytes in the tokenized string), allowing compact storage of maze layout data within a 101-character DIM’d string M$. Each maze string begins and ends with " COPY COPY COPY COPY " padding, which serves as sentinel or boundary markers readable by the machine code.
The string contains tokens such as COPY, CLEAR, PRINT, UNPLOT, STR$, RND, LN, AT, and others — these are not executed as BASIC commands but rather stored as their single-byte token values, providing a dense encoding of maze cell types or directions recognizable by the machine code game engine.
Menu Dispatch Technique
Line 540 uses a computed GOTO to dispatch menu choices:
540 GOTO 550+20*(CODE K$-38)
Since valid keys are A–G (BASIC codes 38–44 after subtracting the offset used internally), this maps:
| Key | CODE K$ | CODE K$-38 | Target line |
|---|---|---|---|
| A | 38 | 0 | 550 |
| B | 39 | 1 | 570 |
| C | 40 | 2 | 590 |
| D | 41 | 3 | 610 |
| E | 42 | 4 | 630 |
| F | 43 | 5 | 650 |
| G | 44 | 6 | 670 |
Constant Definitions Using PI
Lines 20 and 30 define the frequently used integer constants without embedding numeric literals directly:
LET O=PI/PI— setsO=1LET Z=O-O— setsZ=0
This avoids storing floating-point number representations in variables and is a common memory/token-count optimization in ZX81 BASIC.
Speed and Grade Encoding
Speed is stored into M$(5) via:
602 LET M$(5)=CHR$ (X*X-X*N)
With X=10, this gives CHR$(100-10*N), mapping speed keys 1–9 to character codes 90–10. Grade is stored into M$(X+O+O) (i.e., M$(12)) via:
615 LET M$(X+O+O)=CHR$ (96-X*N)
Both values are single bytes within M$ that the machine code reads directly as control parameters for game pacing and chaser acceleration.
Numeric Input Subroutine
The subroutine at line 860 (RN=860) polls INKEY$ in a tight loop until a character in the range “1”–”9″ is detected, then computes N=CODE K$-28 (mapping “1”–”9″ to 21–29) and returns. This integer N is subsequently used in the arithmetic that encodes speed and grade into M$.
Save Functionality
Line 660 uses SAVE Z$ with a user-supplied name, followed by SLOW at line 662 before returning to the menu. This saves the entire program — including the current maze, speed, and grade settings embedded in M$ — allowing a configured game state to be preserved to tape.
Notable Anomalies
- Line 553 checks
IF INKEY$<>CHR$ 118in a loop — CHR$ 118 is the NEWLINE character, so this waits for NEWLINE to be pressed after game over before proceeding. - Line 340 initializes
M$with".\##O%XBH \ ' E0 "— this string contains the character set used by the machine code to render maze elements (food dot, wall segments, player, hunter, spaces, and block graphics). - The variable
ME=500serves as a “return to menu” jump target used pervasively throughout the program in place of a GOTO 500 literal, saving bytes and making the menu entry point easy to relocate.
Content
Source Code
1 REM 2A1040 1 6 0 9113C40 E DEDB0EB2A C40 E43 9 616C5 6 4C5 6 81A4F3A3C40CB2130 33A3D40772310F213C110E923C110E2 17C 1CDD3403A3E4077225040 1F5 2CDD3403A3F407722524018 C2A C40 93A3D40BEC02B18FB 0 0 0 0 0 0CDBB 297CB6520 3CB4CC8CB6C20 6CB5D20 23EFFCB6520 6CB6C20 23E21CB6420 23EDFCB5C20 23E 1CB5420 197B728 03244403A404047F5F110FC21454035202936202A50403A444036 0 6 04F1730 1 5 93A3D40BE20 32A50403A3C40BECC36423A3E4077225040CD5A422143403520 93A414077CD6841CD5A42C3E5403A4640B728143A5540CD F4228 597324640C93A4640CD F42C02A5040CDF541424B2A5240CDF541973246407BB930 63E 1CD F42C079BB30 63EFFCD F42C07AB830 63E21CD F42C078BA30 63EDFCD F42C078BA20 D7BB93E 138 23EFF21EF4118 93EDF38 23E2121F14156235E722B73325540 6 4E57E324640CD F42E1C02310F3C921DF 1FF21DFE5C516 0ED4B C4037ED42 121 0ED4238 31418F9 95DC1E1C9C52A5240 6 04F1730 1 5 9C13A3D40BEC8E52A52403A564077E17E3256403A3F4077225240C9E52148403520 83A474077214140352A C40 140 0 97E3C77FE2630 2E1C9361C2B18F22A5040ED4B5240B7ED42C02A C40 134 0 97E3D 6 AC68077CDD04210F8E1FE1CC83A3C40325640C3C440402A C40 127 0 9E5D1 E16 9E5D5 6 51ABE38 8202A231310F61824D1E1 6 AC5 6 5D51AC680121310F9D1CDD042D5E5 1 5 0EDB0E1D1CDD042C110E218 2D1E1 6 5361C2310FBC9C5 620 E 0 D20FD10F9C1C92A C40 143 0 91616 62036 02310FB231520F5C91B1B1B
10 REM %G%U%L%P% % %C%A%M%P%B%E%L%L% %S%Y%S%T%E%M%S
15 DIM M$(101)
20 LET O=PI/PI
30 LET Z=O-O
40 LET X=10
50 LET ME=500
60 LET SE=900
70 LET MK=14
80 LET RN=860
310 PRINT "%>%G%U%L%P%<% % %M%A%Z%E%= % %S%P%E%E%D%=5% %G%R%A%D%E%=5% % BEST=00000 LIVES=5 SCORE=00000"
340 LET M$=".##O%XBH ' E0 "
350 LET S$=" "
500 RAND USR 17116
510 PRINT AT 3,Z;S$;" MENU",,,,S$;"A...PLAY",,,S$;"B...MAZE",,,S$;"C...SPEED",,,S$;"D...GRADE",,,S$;"E...RESET",,,S$;"F...SAVE"
515 PRINT ,," PRESS G...INSTRUCTIONS"
520 LET K$=INKEY$
530 IF K$<"A" OR K$>"G" THEN GOTO 520
540 GOTO 550+20*(CODE K$-38)
550 IF M$(MK+O)=" " THEN GOTO 570
552 RAND USR 16514
553 PRINT AT O+O,X;"% %G%A%M%E% %O%V%E%R% "
555 IF INKEY$<>CHR$ 118 THEN GOTO 555
560 RAND USR 17030
565 PRINT AT 1,18;"5"
567 GOTO ME
570 GOSUB SE
571 PRINT "MAZE 1 TO 5"
572 GOSUB RN
573 PRINT AT Z,MK-O;K$
574 IF K$="1" THEN LET M$(MK TO )=" COPY COPY COPY COPY % ( ' %Z TO 7B CLEAR %4 : %J TO 7F PRINT %C50RND: %F*5FSTR$ % 50RND)%F575FSTR$ %CRND +%F5F TO VAL %C : %55F7D55%H50: 55;;555551%F555555%C)54+%JNOT 77 PRINT %4= ' %ZNOT %Y COPY % ' COPY COPY COPY COPY "
576 IF K$="2" THEN LET M$(MK TO )=" COPY COPY COPY COPY % ' %Z COPY 7F CLEAR %4 : %J COPY 7F PRINT %C +%F COPY 7FSTR$ %E 55%E COPY 7F55%E% ' 55% Z UNPLOT ' %E%Z CLEAR 55%E% ' 55%E COPY 7F55%E 55%F COPY 7FSTR$ %C +%J COPY 7F PRINT %4 : %Z COPY 7F CLEAR % ' COPY COPY COPY COPY "
578 IF K$="3" THEN LET M$(MK TO )=" COPY COPY COPY COPY % ' %4 ' %J COPY COPY CLEAR % : %Z COPY COPY PRINT %4 ' %J COPY COPY CLEAR % : %Z COPY COPY PRINT %4 ' %J COPY COPY CLEAR % : %Z COPY COPY PRINT %4 ' %J COPY COPY CLEAR % : %Z COPY COPY PRINT %4 ' %J COPY COPY COPY % ' COPY COPY COPY COPY "
580 IF K$="4" THEN LET M$(MK TO )=" COPY COPY COPY COPY %7 PRINT ,,%C: %4+ RETURN %5%ZUSR '%X% 57 REM .:%Z50~~ CLEAR .:5F REM : %X ~~ PRINT :STR$ %+ RETURN %455%= '%Z55%* REM .:51%(~~ CLEAR 5D%3 REM ' INKEY$% F CLEAR 7D%Z%C: ' % %J PRINT CLEAR % (' COPY COPY COPY COPY "
582 IF K$="5" THEN LET M$(MK TO )=" COPY COPY COPY COPY % ' %Z%N60 CLEAR %Z%N60 CLEAR %L%N60LN %L%N60LN %KN60LN %KN60LN %KN60LN %KN60LN %KN60LN %KN60LN %N%N60<>%N%N60<>%L%N60AT %L%N60AT %L%N60AT %L%N60AT %Z%Z% ' COPY COPY COPY COPY "
586 GOTO ME
590 GOSUB SE
592 PRINT "SPEED 1 TO 9"
595 GOSUB RN
600 PRINT AT Z,X+X+O;K$
602 LET M$(5)=CHR$ (X*X-X*N)
605 GOTO ME
610 GOSUB SE
611 PRINT "GRADE 1 TO 9"
612 GOSUB RN
615 LET M$(X+O+O)=CHR$ (96-X*N)
620 PRINT AT Z,29;K$
625 GOTO ME
630 PRINT AT O,5;"00000"
635 GOTO ME
650 GOSUB SE
652 PRINT "NAME AND START TAPE"
655 INPUT Z$
660 SAVE Z$
662 SLOW
665 GOTO ME
670 GOTO 1000
860 LET K$=INKEY$
870 IF K$<"1" OR K$>"9" THEN GOTO 860
880 LET N=CODE K$-28
890 RETURN
900 PRINT AT X+X,Z;"SELECT ";
910 RETURN
1000 RAND USR 17116
1005 PRINT AT 3,Z;"%I%N%S%T%R%U%C%T%I%O%N%S"
1010 PRINT "IN GULP YOU STEER YOURSELF (O) THROUGH A MAZE, EATING FOOD (.) AS YOU GO. USE KEYS 5-8 FOR LEFT, DOWN, UP, RIGHT."
1020 PRINT "YOU GET POINTS AS YOU MOP UP THEFOOD, BUT LOOK OUT FOR YOU SHARETHE MAZE WITH A HUNTER (%X) AND IF HE CATCHES YOU, A LIFE IS LOST."
1030 PRINT "WORSE, THE MORE YOU EAT THE FASTER HE CHASES. AFTER EACH CAPTURE, CHASER STARTS AGAIN FROM BOTTOM RIGHT."
1040 PRINT "GAME ENDS WHEN LIVES=0 OR YOU PRESS ""0"" KEY. THEN NEWLINE TO UPDATE ""BEST"" SCORE IF DUE, AND YOU GET BACK TO THE MENU."
1050 PRINT "%N%E%W%L%I%N%E% %T%O% %C%O%N%T"
1060 INPUT K$
1061 RAND USR 17116
1065 PRINT AT 3,Z;"%I%N%S%T%R%U%C%T%I%O%N%S%,% %C%O%N%T%.",
1070 PRINT "USE THE MENU TO CONTROL THUS..."
1080 PRINT """A"" TO PLAY A GAME"
1090 PRINT """B"" TO SELECT ONE OF 5 MAZES"
1100 PRINT """C"" TO SELECT SPEED OR PACE OF THE GAME."
1110 PRINT """D"" TO SELECT GRADE, WHICH IS"
1120 PRINT " THE CHASER ACCELERATION."
1130 PRINT """E"" RESETS ""BEST"" TO 00000."
1140 PRINT """F"" SAVES GULP GAME ON TAPE."
1150 PRINT """G"" DISPLAYS THESE INSTRUCTIONS."
1160 PRINT "%N%E%W%L%I%N%E% %B%A%C%K% %T%O% %M%E%N%U"
1165 INPUT K$
1170 GOTO ME
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.




