Murgatroyds is a top-down chase game in which the player navigates a character across a grid arena while being hunted by eight enemies called Murgatroyds, luring them into a minefield to destroy them. The arena is drawn using block graphics characters for walls, with mines represented by CHR$ 8 and enemies by CHR$ 139 (the inverse-video character used on this platform). Screen memory is read directly via PEEK of the display file address obtained from system variable at address 16396/16397, allowing the program to detect tile contents (wall, mine, player, or enemy) without maintaining a separate map array. The player inputs compass bearings (e.g., “NW”, “SOUTHEAST”) to move, and a one-time “PANIC” jump teleports them to a random open cell. Difficulty increases across waves by reducing the number of mines (F1 decreases by 5 each wave), making later waves progressively harder.
Program Analysis
Program Structure
The program is organized into a clear linear flow with a few major sections:
- Lines 5–50: REMs, initialization of string arrays.
- Lines 60–160: Player name input, sanitization, and extraction of first initial.
- Lines 170–470: Instructions prompt and display.
- Lines 480–776: Game board initialization — draw arena, place mines, place Murgatroyds, place player.
- Lines 780–1360: Main game loop: player input, movement, enemy AI, mine collision, scoring.
- Lines 1370–1430: PANIC jump handler.
- Lines 1440–1560: Death handling.
- Lines 1520–1550: Victory handling.
- Lines 1560–1700: Replay prompt.
- Lines 1710–1890: Next-wave setup and animation.
- Lines 1900–1950: Exit/credits screen.
- Lines 2000–2010: SAVE line with auto-run.
Arena Drawing and Display File Inspection
The arena is rendered entirely with PRINT AT statements using block graphic characters. Lines 552–600 fill the screen with solid blocks first, then overwrite with the border frame (top: ▛▀…▀▜, sides: ▌…▐, bottom: ▙▄…▄▟) and dots for open space. Mines are printed as CHR$ 8 (a cursor-left character that renders as a block on this platform).
A key technique is the use of PEEK to read the display file directly, avoiding the need for a separate map array. Line 500 retrieves the display file base address from system variables at 16396 and 16397: LET D9=PEEK 16396+256*PEEK 16397. Cell contents are then read as PEEK (D9+1+P(I)+(L(I)*33)), using the formula where each screen row is 33 bytes wide (32 characters plus one attribute byte on this platform). This allows collision detection simply by checking the character code at the target cell.
Player Name Handling
The player name is stored in T$ (14 characters). Line 82 checks whether the first character is CHR$ 139 (an inverse-space, which can result from pressing a function key or entering blank input in certain ways) and ejects the player. Line 88 catches an all-spaces name and substitutes “NAMELESS ONE”. Lines 90–130 scan backwards through the name to find the last non-space character and append a “?” immediately after it — a neat way to add a suffix without knowing the name length in advance. The first letter of the name, stored in N$, is used as the player’s on-screen token.
Enemy AI
Eight Murgatroyds are tracked with row array L(8) and column array P(8). Each turn, for each live enemy, the program computes the delta to the player (L9, P9). Two movement modes are used:
- Simple mode (lines 1090–1120): Moves independently in row and column toward the player, chosen when
RND*3 < 1(roughly 1/3 of the time). - Dominant-axis mode (lines 1140–1170): Moves only along whichever axis has the larger distance, chosen the remaining 2/3 of the time.
Line 1330 contains the “rogue Murgatroyd” mechanic mentioned in the instructions: IF INT(RND*8)=4 AND C1>1 THEN LET I=I-1. This causes a random enemy to take a second move in the same turn, making it unpredictable and more dangerous.
Enemies that hit a mine (D8=8) are killed: their position is marked with “*” (an explosion indicator), the mine cell is cleared, score increases by 10, and L(I) is set to 0 to flag the enemy as dead. Dead enemies are skipped at line 1030 (IF L(I)=0 THEN GOTO 1330). Enemies that encounter another Murgatroyd (D8=139) at lines 1230–1260 are blocked and stay put for that move.
Movement Input Parsing
Player movement is parsed from the 9-character string D$ using substring checks. The horizontal component checks D$(1 TO 2) for “NW”, “SW”, “NE”, “SE” and D$(1) for “W” or “E”. The vertical component checks D$(1) for “N” or “S”. Full-word forms like “NORTHWEST” and “SOUTHEAST” are also accepted. This means diagonal moves correctly update both row and column variables L2 and P2 from their initial values of L1 and P1.
Scoring and Difficulty
Score (S1) decreases by 1 per move when many mines remain (F1 > 15) and the score is positive, but increases by 1 per move when mines are sparse (F1 <= 15). Killing a Murgatroyd with a mine adds 10 points. Between waves, F1 is decremented by 5 (line 1710), reducing the number of mines placed in the next wave and making each successive wave harder. The PANIC teleport can only be used once per game (C3 counter), though line 1780 offers the player a fresh panic if they had used it in a wave they won.
Wave Transition Animation
Lines 1790–1880 animate a scrolling text display of Murgatroyd figures (represented as ["] patterns) and the player’s initial moving across the screen using a FOR loop over TAB positions, giving a simple marching effect before the next wave begins.
Notable Anomalies
- Line 1440 prints a dot at the player’s old position before death is determined, meaning the player’s marker is erased even if the game ends. This is cosmetically minor but technically a sequencing quirk.
- Line 1480 prints a Murgatroyd character at the enemy’s new position and line 1490 clears its old position — this is the “caught by Murgatroyd” sequence, but the enemy display update happens before the death message, which is correct.
- The PRINT AT statement at line 1340 appends
CHR$ 128after the score — this is a space character (128 is a block graphic space on this platform) used to clear any leftover digit from a previously higher score value. - Line 85 (
GOTO 60) is unreachable because line 84 is a STOP.
Content
Image Gallery
Source Code
5 REM MURGATROYDS - ZX81 VERSION - OCCUPIES <7K BYTES.
7 REM CGM01 COPYRIGHT COLLINS COMPUTING 1981.
8 RAND
10 DIM G$(2)
20 DIM T$(14)
30 DIM N$(1)
40 DIM D$(9)
50 LET F1=25
60 PRINT "WHAT""S YOUR NAME?"
70 PRINT
80 INPUT T$
82 IF T$(1)<>CHR$ 139 THEN GOTO 88
83 PRINT "YOU DON""T LOOK RELIABLE TO ME.GET OUT - LET SOMEONE ELSE PLAY."
84 STOP
85 GOTO 60
88 IF T$=" " THEN LET T$="NAMELESS ONE"
90 FOR I=13 TO 1 STEP -1
100 IF T$(I)=" " THEN GOTO 130
110 LET T$(I+1)="?"
120 LET I=1
130 NEXT I
140 LET N$=T$(1)
150 IF N$<"A" OR N$>"Z" THEN LET N$="X"
160 PRINT
170 PRINT "WOULD YOU LIKE ME TO GIVE YOU INSTRUCTIONS, ";T$
180 INPUT D$
190 CLS
200 IF D$(1)="N" THEN GOTO 460
210 PRINT "OK, YOUR POSITION WILL BE SHOWN"
220 PRINT "BY A LETTER """;N$;""" ON THE PLAN."
230 PRINT "THE MURGATROYDS ARE CLOSING IN"
240 PRINT "BUT YOU CAN LURE THEM TO THEIR"
250 PRINT "DEATHS IN THE MINEFIELD (MINES"
260 PRINT "ARE MARKED """;CHR$ 8;"""). BE CAREFUL TO"
270 PRINT "AVOID THE ELECTRIFIED PERIMETER"
300 PRINT "FENCE. YOU MOVE BY GIVING THE"
310 PRINT "COMPASS BEARING OF THE DIRECTION"
320 PRINT "YOU WANT TO MOVE IN (EG. ""NW"" OR"
330 PRINT """SOUTH"")."
340 PRINT
350 PRINT "IF THERE IS NO WAY OUT, YOU CAN"
360 PRINT "SAY ""PANIC"" (OR ""P"") TO MAKE"
370 PRINT "A RANDOM (BUT VERY DANGEROUS)"
380 PRINT "JUMP."
382 PRINT
384 PRINT "AND WATCH OUT FOR THE ROGUE"
386 PRINT "MURGATROYD WHO CHEATS."
390 PRINT
400 PRINT "SAY ""GO"" WHEN YOU ARE"
410 PRINT "READY TO START."
420 INPUT G$
430 CLS
440 IF G$<>"GO" THEN GOTO 400
450 GOTO 480
460 PRINT "OK, SMARTYPANTS, HERE WE GO."
470 PAUSE 99
480 DIM P(8)
490 DIM L(8)
500 LET D9=PEEK 16396+256*PEEK 16397
510 LET M1=0
520 LET C1=8
530 LET F1=25
540 LET S1=0
550 LET C3=0
552 FOR I=0 TO 19
554 PRINT AT I,0;"████████████████████████████████"
556 NEXT I
560 PRINT AT 0,0;"▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜"
570 FOR I=1 TO 18
580 PRINT AT I,0;"▌.......................▐"
590 NEXT I
600 PRINT AT 19,0;"▙▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▟"
610 FOR I=1 TO F1
620 PRINT AT INT ((RND*17)+2),INT ((RND*22)+2);CHR$ 8
630 NEXT I
640 FOR I=1 TO 8
650 LET L(I)=INT ((RND*17)+2)
660 LET P(I)=INT ((RND*22)+2)
670 LET D8=PEEK (D9+1+P(I)+(L(I)*33))
680 IF CHR$ D8<>"." THEN GOTO 650
710 PRINT AT L(I),P(I);CHR$ 139
720 NEXT I
730 LET L1=INT ((RND*17)+2)
740 LET P1=INT ((RND*22)+2)
750 LET L2=L1
760 LET P2=P1
772 LET D8=PEEK (D9+1+P1+(L1*33))
774 IF CHR$ D8<>"." THEN GOTO 730
776 PRINT AT L1,P1;N$
780 PRINT AT 6,26;"SCORE"
790 PRINT AT 9,28;S1
800 PRINT AT 21,0;"MAKE YOUR MOVE"
810 INPUT D$
820 PRINT AT 20,0;" "
830 PRINT AT 21,0;" "
840 LET M1=M1+1
850 IF F1>15 AND S1>0 THEN LET S1=S1-1
860 IF F1<=15 THEN LET S1=S1+1
870 IF D$(1 TO 2)="NW" OR D$="NORTHWEST" THEN LET P2=P1-1
880 IF D$(1)="W" THEN LET P2=P1-1
890 IF D$(1 TO 2)="SW" OR D$="SOUTHWEST" THEN LET P2=P1-1
900 IF D$(1 TO 2)="NE" OR D$="NORTHEAST" THEN LET P2=P1+1
910 IF D$(1)="E" THEN LET P2=P1+1
920 IF D$(1 TO 2)="SE" OR D$="SOUTHEAST" THEN LET P2=P1+1
930 IF D$(1)="N" THEN LET L2=L1-1
940 IF D$(1)="S" THEN LET L2=L1+1
950 IF D$(1)="P" THEN GOTO 1370
960 LET D8=PEEK (D9+1+P2+(L2*33))
970 IF CHR$ (D8)<>"." AND CHR$ (D8)<>N$ THEN GOTO 1440
980 PRINT AT L1,P1;"."
990 LET L1=L2
1000 LET P1=P2
1010 PRINT AT L2,P2;N$
1020 FOR I=1 TO 8
1030 IF L(I)=0 THEN GOTO 1330
1040 LET L8=L(I)
1050 LET P8=P(I)
1060 LET L9=L1-L(I)
1070 LET P9=P1-P(I)
1080 IF RND*3>=1 THEN GOTO 1140
1090 IF P9<0 THEN LET P(I)=P(I)-1
1100 IF P9>0 THEN LET P(I)=P(I)+1
1110 IF L9>0 THEN LET L(I)=L(I)+1
1120 IF L9<0 THEN LET L(I)=L(I)-1
1130 GOTO 1180
1140 IF ABS (P9)>=ABS (L9) AND P9<0 THEN LET P(I)=P(I)-1
1150 IF ABS (P9)>=ABS (L9) AND P9>0 THEN LET P(I)=P(I)+1
1160 IF ABS (L9)>=ABS (P9) AND L9<0 THEN LET L(I)=L(I)-1
1170 IF ABS (L9)>=ABS (P9) AND L9>0 THEN LET L(I)=L(I)+1
1180 LET D8=PEEK (D9+1+P(I)+(L(I)*33))
1190 IF D8=8 THEN PRINT AT L(I),P(I);"*"
1200 IF D8=8 THEN PRINT AT L8,P8;"."
1210 IF D8=8 THEN LET S1=S1+10
1220 IF CHR$ (D8)=N$ THEN GOTO 1480
1230 IF D8<>139 THEN GOTO 1270
1240 LET L(I)=L8
1250 LET P(I)=P8
1260 GOTO 1330
1270 IF D8=27 THEN PRINT AT L8,P8;"."
1280 IF D8=27 THEN PRINT AT L(I),P(I);CHR$ 139
1290 IF D8<>8 THEN GOTO 1330
1300 LET C1=C1-1
1310 PRINT AT L(I),P(I);"."
1320 LET L(I)=0
1330 IF INT (RND*8)=4 AND C1>1 THEN LET I=I-1
1335 NEXT I
1340 PRINT AT 9,28;S1;CHR$ 128
1350 IF C1=0 THEN GOTO 1520
1360 GOTO 800
1370 LET C3=C3+1
1380 IF C3=1 THEN GOTO 1420
1390 PRINT AT 20,0;"SORRY, YOU CAN ONLY PANIC ONCE."
1400 LET M1=M1-1
1410 GOTO 800
1420 PRINT AT L1,P1;"."
1422 LET L1=INT ((RND*17)+2)
1424 LET P1=INT ((RND*22)+2)
1425 LET L2=L1
1426 LET P2=P1
1428 PRINT AT L1,P1;N$
1430 GOTO 1020
1440 PRINT AT L1,P1;"."
1450 IF D8=139 THEN GOTO 1500
1460 PRINT AT 20,0;"YOU HAVE BEEN KILLED - BAD LUCK."
1470 GOTO 1560
1480 PRINT AT L(I),P(I);CHR$ 139
1490 PRINT AT L8,P8;"."
1500 PRINT AT 20,0;"PITY - A MURGATROYD GOT YOU."
1510 GOTO 1560
1520 PRINT AT 20,0;"GOOD - THE MURGATROYDS ARE DEAD."
1530 PRINT AT 4,26;"FINAL"
1540 PRINT AT 21,0;"THAT TOOK YOU ";M1;" MOVES."
1550 GOTO 1710
1560 PRINT AT 21,0;"YOU LASTED ";M1;" MOVES."
1570 PRINT AT 4,1;" "
1580 PRINT AT 5,1;" HOW ABOUT "
1590 PRINT AT 6,1;" "
1600 PRINT AT 7,1;" ANOTHER GAME ? "
1610 PRINT AT 8,1;" "
1620 INPUT D$
1630 IF D$(1)="N" THEN GOTO 1900
1640 IF D$(1)="Y" THEN GOTO 1690
1650 PRINT AT 5,1;" DO YOU WANT "
1660 PRINT AT 6,1;" ANOTHER GAME ? "
1670 PRINT AT 7,1;" YES OR NO "
1680 GOTO 1620
1690 CLS
1700 GOTO 510
1710 LET F1=F1-5
1720 LET C1=8
1740 PAUSE 200
1750 CLS
1760 PRINT "THE NEXT WAVE OF MURGATROYDS"
1770 PRINT "WILL NOT BE SO EASILY DEALT WITH"
1780 IF C3>1 THEN PRINT "- BUT YOU CAN PANIC AGAIN."
1785 LET C3=0
1790 FOR F=0 TO 20
1800 PRINT AT 7,0+F;" ["] ["] ["]"
1810 PRINT
1820 PRINT TAB 0+F;" ["] ["] ["]"
1830 PRINT
1840 PRINT TAB 0+F;" ["] ["] ["]"
1850 PRINT
1860 PRINT TAB 0+F;" ["] ["]"
1870 PRINT AT 10,9+F;" ";N$
1880 NEXT F
1890 GOTO 552
1900 CLS
1920 PRINT AT 5,8;"COPYRIGHT 1981"
1930 PRINT AT 7,6;"COLLINS COMPUTING"
1950 STOP
2000 SAVE "[M]"
2010 GOTO 8
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.