MICROMOUSE is a maze-navigation simulation in which a cursor character wanders through a randomly generated obstacle field, trying to reach a fixed goal at screen position (20,30). The maze is built using a combination of inverse-video block characters and block graphics printed at randomised AT positions during a setup loop (lines 30–60). The mouse’s movement logic tests eight compass directions by issuing a PRINT AT to the candidate cell, then reading the display RAM address stored in system variables G (16398) and H (16399) to determine whether that cell is blank (character code 0), implementing a collision-detection technique entirely through PEEK of the display file pointer. A move counter Q accumulates attempts, and on reaching the goal the score is displayed briefly before the maze is regenerated.
Program Analysis
Program Structure
The program divides into four logical phases:
- Initialisation (lines 1–6): Stores the display-file pointer address in
G(16398) andH(16399). - Maze generation (lines 10–68): Draws top and bottom border rows of inverse spaces, then randomises wall segments and block graphics across the interior in a
FOR A=1 TO 20loop. A second short loop (lines 61–68) animates the goal marker at (20,30) by flashing it. - Movement engine (lines 70–390): Places the mouse at a random starting position, then repeatedly probes adjacent cells in up to eight directions using the display-RAM PEEK technique. A counter
Qrecords total moves. - Win condition & restart (lines 2000–2070): On reaching (20,30), prints the move count, pauses with a
FOR/NEXTdelay, redraws the border, and branches back to line 30 to regenerate the maze.
Display-RAM Collision Detection
The most technically interesting feature is the use of system variables at addresses 16398–16399, which together form the two-byte pointer to the current cursor position in the display file. The idiom used throughout is:
PRINT AT A+1,B;— moves the display cursor to a candidate cell without printing anything visible.IF PEEK (PEEK G+256*PEEK H)=0 THEN LET T=1— dereferences the cursor pointer to read the character code at that cell. A value of 0 means a space (empty), so the move is valid.
This avoids the need for any array-based map representation; the screen itself is the maze data structure. The technique exploits the ZX81/TS1000 system variable DF_CC (display file current character address), held at 16398–16399 in little-endian format, making PEEK G + 256*PEEK H the full 16-bit address.
Movement Logic
Eight candidate directions are attempted, selected partly randomly via Y=RND*7+1 and partly through a fallback chain. The direction codes and their target lines are:
| Y value | Direction | Line | Delta (row,col) |
|---|---|---|---|
| 1 / default | Down | 120 | (+1, 0) |
| 2 | Up-right diagonal | 154 | (−1,+1) |
| 3 | Down-right diagonal | 200 | (+1,+1) |
| 4 | Up | 250 | (−1, 0) |
| 5 | Left | 290 | (0,−1) |
| 6 | Right | 169 | (0,+1) |
| 7 | Up-left diagonal | 330 | (−1,−1) |
If none of the tested directions is free, T remains 0 and the engine loops back to line 110 to retry with a new random direction. The previous position E,F is erased with a space at line 1000 before stamping the mouse character at the new position.
Key BASIC Idioms
- RND scaling:
RND*N+1is used throughout for integer ranges, relying on ZX81 BASIC’s 0–0.9999… RND range truncated via multiplication without an explicit INT call — valid because PRINT AT accepts fractional row/column arguments by truncating internally. - Delay loop:
FOR N=1 TO 3000: NEXT Nat lines 2010–2020 provides a pause after the win message without using PAUSE. - Flicker animation: The goal marker at (20,30) is toggled between a space and
%*(inverse asterisk) six times in lines 61–68 to draw attention to the target before the mouse is released.
Maze Generation Technique
The maze interior is built entirely from random PRINT AT statements placing inverse spaces (% ), block graphics (\##, \;;\!!), and short wall segments (% % ). There is no guarantee of solvability; the mouse may occasionally become fully trapped. The left and right borders are drawn per-row inside the setup loop (lines 42 and 50), while top and bottom solid borders are printed before the loop (lines 10 and 20).
Bugs and Anomalies
- Line 106 tests
IF RND>-2476, which is always true (RND is never negative). This means the random-direction branch at line 110 is never skipped, and the “straight down” default at line 120 is never taken as a direct fall-through from line 95. The conditional is effectively dead code. - Similarly, lines 152 (
RND>-2), 165 (RND<-2), 195 (RND<-6), and 245 (RND<-1) use impossible RND values (always positive), making those fallback branches either always-taken or never-taken. The movement priorities are therefore fixed rather than truly probabilistic. - Line 2050
CLEARand lines 2060–2070 are unreachable dead code following theGOTO 30at line 2040. - The boundary check at line 154 tests
B=30(the goal column) rather thanB=31, which could prevent rightward diagonal moves unnecessarily near the right edge.
Content
Source Code
1 REM **MICROMOUSE**
5 LET G=16398
6 LET H=G+1
10 PRINT AT 0,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
20 PRINT AT 21,0;"% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % "
30 FOR A=1 TO 20
35 PRINT AT 2+RND**18,1+RND**27;" "
36 PRINT AT 2+RND**18,1+RND**27;" "
37 PRINT AT 2+RND**18,1+RND**27;" "
42 PRINT AT A,0;"% "
43 PRINT AT 3+RND**15,2+RND**22;"% % "
44 PRINT AT 2+RND**18,1+RND**27;" "
45 PRINT AT 2+RND**18,2+RND**24;"% "
46 PRINT AT 3+RND**15,2+RND**27;"\##"
47 PRINT AT 2+RND**15,2+RND**24;" \;;\!!"
50 PRINT AT A,31;"% "
57 PRINT AT 2+RND**16,2+RND**26;" "
60 NEXT A
61 FOR Z=1 TO 13
62 PRINT AT 20,30;" "
63 PRINT AT 20,30;"%*"
64 PRINT AT 20,30;"%*"
65 PRINT AT 20,30;" "
66 PRINT AT 20,30;"%*"
67 PRINT AT 20,30;" "
68 NEXT Z
70 LET A=RND**6+1
75 LET Q=0
80 LET B=RND**15+1
85 PRINT AT 20,30;" "
90 LET E=A
95 LET Q=Q+1
100 LET F=B
101 IF A=20 AND B=30 THEN GOTO 2000
105 LET T=0
106 IF RND>-2476 THEN GOTO 120
110 LET Y=RND**7+1
111 IF Y=1 THEN GOTO 120
112 IF Y=6 THEN GOTO 169
113 IF Y=3 THEN GOTO 200
114 IF Y=4 THEN GOTO 250
115 IF Y=5 THEN GOTO 290
116 IF Y=2 THEN GOTO 154
117 IF Y=7 THEN GOTO 330
120 PRINT AT A+1,B;
130 IF PEEK (PEEK G+256*PEEK H)=0 THEN LET T=1
140 IF T=1 THEN LET A=A+1
150 IF T=1 THEN GOTO 1000
152 IF RND>-2 THEN GOTO 169
154 IF A=0 OR B=30 THEN GOTO 169
155 PRINT AT A-1,B+1;
156 IF PEEK (PEEK G+256*PEEK H)=0 THEN LET T=1
157 IF T=1 THEN LET B=B+1
158 IF T=1 THEN LET A=A-1
159 IF T=1 THEN GOTO 1000
165 IF RND<-2 THEN GOTO 110
169 PRINT AT A,B+1;
170 IF PEEK (PEEK G+256*PEEK H)=0 THEN LET T=1
180 IF T=1 THEN LET B=B+1
190 IF T=1 THEN GOTO 1000
195 IF RND<-6 THEN GOTO 290
200 PRINT AT A+1,B+1;
210 IF PEEK (PEEK G+256*PEEK H)=0 THEN LET T=1
220 IF T=1 THEN LET A=A+1
230 IF T=1 THEN LET B=B+1
240 IF T=1 THEN GOTO 1000
245 IF RND<-1 THEN GOTO 110
250 PRINT AT A-1,B;
260 IF PEEK (PEEK G+256*PEEK H)=0 THEN LET T=1
270 IF T=1 AND A>0 THEN LET A=A-1
280 IF T=1 THEN GOTO 1000
290 PRINT AT A,B-1;
300 IF PEEK (PEEK G+256*PEEK H)=0 THEN LET T=1
310 IF T=1 AND B>0 THEN LET B=B-1
320 IF T=1 THEN GOTO 1000
330 IF B=0 OR A=0 THEN GOTO 110
340 PRINT AT A-1,B-1;
350 IF PEEK (PEEK G+256*PEEK H)=0 THEN LET T=1
360 IF T=1 THEN LET A=A-1
370 IF T=1 THEN LET B=B-1
380 IF T=1 THEN GOTO 1000
390 GOTO 110
\n1000 PRINT AT E,F;" "
\n1010 PRINT AT A,B;"%*"
\n1020 GOTO 90
\n2000 PRINT AT 0,15;"% ";Q;"% "
\n2010 FOR N=1 TO 3000
\n2020 NEXT N
\n2030 PRINT AT 0,15;"% % % % % % "
\n2040 GOTO 30
\n2050 CLEAR
\n2060 SAVE "1032%4"
\n2070 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
