The player can deliver the crate. Now the program needs to recognise that delivery. We will first display a count, then use it to finish the room.
Count what is left
Add lines 85, 475, 476, 2505, 6000, 6010, 6015, 6020.
85 GO SUB 6000
475 IF v=4 THEN LET left=left+1
476 IF bv=2 THEN LET left=left-1
2505 PRINT AT 1,18; INK 5;"GOALS ";total-left;"/";total
6000 LET left=0: LET total=0: FOR r=1 TO 8: FOR c=1 TO 8
6010 IF g(r,c)=2 THEN LET left=left+1
6015 IF g(r,c)=2 OR g(r,c)=4 THEN LET total=total+1
6020 NEXT c: NEXT r: RETURNComplete program for this step
10 GO SUB 7000: LET h$=""
15 LET room=1
20 DIM g(8,8)
30 FOR r=1 TO 8: FOR c=1 TO 8
40 IF r=1 OR r=8 OR c=1 OR c=8 THEN LET g(r,c)=1
50 NEXT c: NEXT r
60 LET g(3,4)=1: LET g(4,4)=1
70 LET g(3,5)=2: LET g(5,4)=3
80 LET pr=6: LET pc=3: LET moves=0: LET won=0
85 GO SUB 6000
100 GO SUB 1000
110 GO SUB 3000
120 IF k$="q" OR k$="Q" THEN GO TO 9000
130 IF k$="r" OR k$="R" THEN GO TO 20
150 LET dr=0: LET dc=0
160 IF k$="i" OR k$="I" THEN LET dr=-1
170 IF k$="k" OR k$="K" THEN LET dr=1
180 IF k$="j" OR k$="J" THEN LET dc=-1
190 IF k$="l" OR k$="L" THEN LET dc=1
200 IF dr=0 AND dc=0 THEN GO TO 110
210 LET nr=pr+dr: LET nc=pc+dc
220 IF nr<1 OR nr>8 OR nc<1 OR nc>8 THEN GO TO 700
230 LET v=g(nr,nc)
240 IF v=1 THEN GO TO 700
250 IF v=3 OR v=4 THEN GO TO 400
260 GO TO 500
400 LET br=nr+dr: LET bc=nc+dc
410 IF br<1 OR br>8 OR bc<1 OR bc>8 THEN GO TO 700
420 LET bv=g(br,bc)
430 IF bv<>0 AND bv<>2 THEN GO TO 700
440 LET g(nr,nc)=0
450 IF v=4 THEN LET g(nr,nc)=2
460 LET g(br,bc)=3
470 IF bv=2 THEN LET g(br,bc)=4
475 IF v=4 THEN LET left=left+1
476 IF bv=2 THEN LET left=left-1
480 LET r=br: LET c=bc: GO SUB 2000
500 LET oldr=pr: LET oldc=pc
510 LET pr=nr: LET pc=nc: LET moves=moves+1
520 LET r=oldr: LET c=oldc: GO SUB 2000
530 LET r=pr: LET c=pc: GO SUB 2000
600 GO SUB 2500
610 GO TO 110
700 GO TO 110
1000 BORDER 0: PAPER 0: INK 7: CLS
1010 PRINT AT 0,2; INK 5;"CRATES";AT 0,24; INK 7;"ROOM 0";room
1020 PRINT AT 20,2; INK 7;"I up J left K down L right"
1030 PRINT AT 21,6; INK 5;"R restart Q quit";
1040 FOR r=1 TO 8: FOR c=1 TO 8
1050 GO SUB 2000
1060 NEXT c: NEXT r
1070 GO SUB 2500
1080 RETURN
2000 LET y=3 +2 *(r-1): LET x=8 +2 *(c-1)
2010 LET z=g(r,c)+1
2020 IF r=pr AND c=pc THEN LET z=6
2025 IF z=6 AND g(r,c)=2 THEN LET z=7
2030 PRINT AT y,x; INK a(z);t$(z,1 TO 2);AT y+1,x;t$(z,3 TO 4)
2040 RETURN
2500 PRINT AT 1,2; INK 7;"STEPS ";moves;" "
2505 PRINT AT 1,18; INK 5;"GOALS ";total-left;"/";total
2540 RETURN
3000 LET k$=INKEY$
3010 IF k$=h$ THEN GO TO 3000
3020 LET h$=k$
3025 IF k$="" THEN GO TO 3000
3030 RETURN
6000 LET left=0: LET total=0: FOR r=1 TO 8: FOR c=1 TO 8
6010 IF g(r,c)=2 THEN LET left=left+1
6015 IF g(r,c)=2 OR g(r,c)=4 THEN LET total=total+1
6020 NEXT c: NEXT r: RETURN
7000 RESTORE 7200: FOR n=0 TO 159: READ b: POKE USR "a"+n,b: NEXT n
7010 DIM t$(7,4): DIM a(7)
7020 LET t$(1)=" ": LET t$(2)=CHR$ 144 +CHR$ 145 +CHR$ 146 +CHR$ 147
7030 LET t$(3)=CHR$ 148 +CHR$ 149 +CHR$ 150 +CHR$ 151
7040 LET t$(4)=CHR$ 152 +CHR$ 153 +CHR$ 154 +CHR$ 155: LET t$(5)=t$(4)
7050 LET t$(6)=CHR$ 156 +CHR$ 157 +CHR$ 158 +CHR$ 159
7055 LET t$(7)=CHR$ 160 +CHR$ 161 +CHR$ 162 +CHR$ 163
7060 LET a(1)=0: LET a(2)=1: LET a(3)=5: LET a(4)=6: LET a(5)=4: LET a(6)=7: LET a(7)=5: RETURN
7200 DATA 0,254,129,129,129,129,129,0
7210 DATA 0,254,2,2,2,2,2,0
7220 DATA 127,64,64,64,64,64,127,0
7230 DATA 127,129,129,129,129,129,127,0
7240 DATA 0,0,0,3,12,8,16,17
7250 DATA 0,0,0,192,48,16,8,136
7260 DATA 17,16,8,12,3,0,0,0
7270 DATA 136,8,16,48,192,0,0,0
7280 DATA 0,127,64,95,88,84,82,81
7290 DATA 0,254,2,250,26,42,74,138
7300 DATA 81,82,84,88,95,64,127,0
7310 DATA 138,74,42,26,250,2,254,0
7320 DATA 3,7,7,3,1,15,31,27
7330 DATA 192,224,224,192,128,240,248,216
7340 DATA 27,3,3,7,6,6,14,0
7350 DATA 216,192,192,224,96,96,112,0
7360 DATA 3,7,7,3,13,15,31,27
7370 DATA 192,224,224,192,176,240,248,216
7380 DATA 27,19,11,15,7,6,14,0
7390 DATA 216,200,208,240,224,96,112,0
9000 PAPER 0: INK 7
9010 PRINT AT 21,0;"Finished. RUN to try again. ";
9020 STOPThe routine at 6000 scans the starting room once. left counts cells containing an uncovered target, code 2. total counts all targets, including code 4, a target already covered by a crate. Line 85 calls it whenever the room is rebuilt.
During play we already know the two cells involved in a push. If the crate leaves a target, line 475 adds one to left. If it enters a target, line 476 subtracts one. Walking changes neither. This avoids scanning the whole array after each step.
The GOALS readout prints total - left, the number filled, followed by the total. Room one starts at 0/1 and a delivery makes it 1/1. This gives delivery a textual cue as well as the green crate.
A crate leaves one target and enters another in the same push. What happens to left?
Show the explanation
Leaving adds one uncovered target; entering removes one. The net change is zero. Both tests must run: making the second an alternative to the first would lose half of the update.
Run and deliver with I, L, K, L, I, I. The readout should become 1/1, but movement is still allowed. Push the crate off using the route from the previous lesson and it should return to 0/1. R resets the room and its count.
Make a complete visit
Replace line 10.
Add lines 140, 590, 2510, 5000, 5010, 5020, 5030, 5040, 5050, 5060, 5070, 5080, 5090, 5100, 5110, 5120.
10 GO SUB 7000: GO SUB 5000
140 IF won=1 THEN GO TO 110
590 IF left=0 THEN LET won=1
2510 IF won=1 THEN PRINT AT 19,2; INK 4;"Delivered! R replay / Q quit"
5000 BORDER 0: PAPER 0: INK 7: CLS : LET h$=""
5010 PRINT AT 2,12; INK 5;"CRATES"
5020 PRINT AT 5,2; INK 7;"A small warehouse puzzle."
5030 PRINT AT 7,1;"I up, J left, K down, L right."
5040 PRINT AT 9,1;"Push crates onto the targets."
5050 PRINT AT 11,1;"You can push, but never pull."
5060 PRINT AT 13,1;"R restarts the room. Q quits."
5070 PRINT AT 15,1;"One step per press. Take time."
5080 PRINT AT 18,1;"S starts. Q quits."
5090 GO SUB 3000
5100 IF k$="q" OR k$="Q" THEN GO TO 9000
5110 IF k$<>"s" AND k$<>"S" THEN GO TO 5090
5120 RETURNComplete program for this step
10 GO SUB 7000: GO SUB 5000
15 LET room=1
20 DIM g(8,8)
30 FOR r=1 TO 8: FOR c=1 TO 8
40 IF r=1 OR r=8 OR c=1 OR c=8 THEN LET g(r,c)=1
50 NEXT c: NEXT r
60 LET g(3,4)=1: LET g(4,4)=1
70 LET g(3,5)=2: LET g(5,4)=3
80 LET pr=6: LET pc=3: LET moves=0: LET won=0
85 GO SUB 6000
100 GO SUB 1000
110 GO SUB 3000
120 IF k$="q" OR k$="Q" THEN GO TO 9000
130 IF k$="r" OR k$="R" THEN GO TO 20
140 IF won=1 THEN GO TO 110
150 LET dr=0: LET dc=0
160 IF k$="i" OR k$="I" THEN LET dr=-1
170 IF k$="k" OR k$="K" THEN LET dr=1
180 IF k$="j" OR k$="J" THEN LET dc=-1
190 IF k$="l" OR k$="L" THEN LET dc=1
200 IF dr=0 AND dc=0 THEN GO TO 110
210 LET nr=pr+dr: LET nc=pc+dc
220 IF nr<1 OR nr>8 OR nc<1 OR nc>8 THEN GO TO 700
230 LET v=g(nr,nc)
240 IF v=1 THEN GO TO 700
250 IF v=3 OR v=4 THEN GO TO 400
260 GO TO 500
400 LET br=nr+dr: LET bc=nc+dc
410 IF br<1 OR br>8 OR bc<1 OR bc>8 THEN GO TO 700
420 LET bv=g(br,bc)
430 IF bv<>0 AND bv<>2 THEN GO TO 700
440 LET g(nr,nc)=0
450 IF v=4 THEN LET g(nr,nc)=2
460 LET g(br,bc)=3
470 IF bv=2 THEN LET g(br,bc)=4
475 IF v=4 THEN LET left=left+1
476 IF bv=2 THEN LET left=left-1
480 LET r=br: LET c=bc: GO SUB 2000
500 LET oldr=pr: LET oldc=pc
510 LET pr=nr: LET pc=nc: LET moves=moves+1
520 LET r=oldr: LET c=oldc: GO SUB 2000
530 LET r=pr: LET c=pc: GO SUB 2000
590 IF left=0 THEN LET won=1
600 GO SUB 2500
610 GO TO 110
700 GO TO 110
1000 BORDER 0: PAPER 0: INK 7: CLS
1010 PRINT AT 0,2; INK 5;"CRATES";AT 0,24; INK 7;"ROOM 0";room
1020 PRINT AT 20,2; INK 7;"I up J left K down L right"
1030 PRINT AT 21,6; INK 5;"R restart Q quit";
1040 FOR r=1 TO 8: FOR c=1 TO 8
1050 GO SUB 2000
1060 NEXT c: NEXT r
1070 GO SUB 2500
1080 RETURN
2000 LET y=3 +2 *(r-1): LET x=8 +2 *(c-1)
2010 LET z=g(r,c)+1
2020 IF r=pr AND c=pc THEN LET z=6
2025 IF z=6 AND g(r,c)=2 THEN LET z=7
2030 PRINT AT y,x; INK a(z);t$(z,1 TO 2);AT y+1,x;t$(z,3 TO 4)
2040 RETURN
2500 PRINT AT 1,2; INK 7;"STEPS ";moves;" "
2505 PRINT AT 1,18; INK 5;"GOALS ";total-left;"/";total
2510 IF won=1 THEN PRINT AT 19,2; INK 4;"Delivered! R replay / Q quit"
2540 RETURN
3000 LET k$=INKEY$
3010 IF k$=h$ THEN GO TO 3000
3020 LET h$=k$
3025 IF k$="" THEN GO TO 3000
3030 RETURN
5000 BORDER 0: PAPER 0: INK 7: CLS : LET h$=""
5010 PRINT AT 2,12; INK 5;"CRATES"
5020 PRINT AT 5,2; INK 7;"A small warehouse puzzle."
5030 PRINT AT 7,1;"I up, J left, K down, L right."
5040 PRINT AT 9,1;"Push crates onto the targets."
5050 PRINT AT 11,1;"You can push, but never pull."
5060 PRINT AT 13,1;"R restarts the room. Q quits."
5070 PRINT AT 15,1;"One step per press. Take time."
5080 PRINT AT 18,1;"S starts. Q quits."
5090 GO SUB 3000
5100 IF k$="q" OR k$="Q" THEN GO TO 9000
5110 IF k$<>"s" AND k$<>"S" THEN GO TO 5090
5120 RETURN
6000 LET left=0: LET total=0: FOR r=1 TO 8: FOR c=1 TO 8
6010 IF g(r,c)=2 THEN LET left=left+1
6015 IF g(r,c)=2 OR g(r,c)=4 THEN LET total=total+1
6020 NEXT c: NEXT r: RETURN
7000 RESTORE 7200: FOR n=0 TO 159: READ b: POKE USR "a"+n,b: NEXT n
7010 DIM t$(7,4): DIM a(7)
7020 LET t$(1)=" ": LET t$(2)=CHR$ 144 +CHR$ 145 +CHR$ 146 +CHR$ 147
7030 LET t$(3)=CHR$ 148 +CHR$ 149 +CHR$ 150 +CHR$ 151
7040 LET t$(4)=CHR$ 152 +CHR$ 153 +CHR$ 154 +CHR$ 155: LET t$(5)=t$(4)
7050 LET t$(6)=CHR$ 156 +CHR$ 157 +CHR$ 158 +CHR$ 159
7055 LET t$(7)=CHR$ 160 +CHR$ 161 +CHR$ 162 +CHR$ 163
7060 LET a(1)=0: LET a(2)=1: LET a(3)=5: LET a(4)=6: LET a(5)=4: LET a(6)=7: LET a(7)=5: RETURN
7200 DATA 0,254,129,129,129,129,129,0
7210 DATA 0,254,2,2,2,2,2,0
7220 DATA 127,64,64,64,64,64,127,0
7230 DATA 127,129,129,129,129,129,127,0
7240 DATA 0,0,0,3,12,8,16,17
7250 DATA 0,0,0,192,48,16,8,136
7260 DATA 17,16,8,12,3,0,0,0
7270 DATA 136,8,16,48,192,0,0,0
7280 DATA 0,127,64,95,88,84,82,81
7290 DATA 0,254,2,250,26,42,74,138
7300 DATA 81,82,84,88,95,64,127,0
7310 DATA 138,74,42,26,250,2,254,0
7320 DATA 3,7,7,3,1,15,31,27
7330 DATA 192,224,224,192,128,240,248,216
7340 DATA 27,3,3,7,6,6,14,0
7350 DATA 216,192,192,224,96,96,112,0
7360 DATA 3,7,7,3,13,15,31,27
7370 DATA 192,224,224,192,176,240,248,216
7380 DATA 27,19,11,15,7,6,14,0
7390 DATA 216,200,208,240,224,96,112,0
9000 PAPER 0: INK 7
9010 PRINT AT 21,0;"Finished. RUN to try again. ";
9020 STOPLine 10 now builds the graphics, then calls the instructions at 5000. That routine clears the remembered key, explains the controls and uses the same input routine to wait for S or Q. RETURN begins the room only after S.
After an accepted step, line 590 sets won = 1 when no targets remain uncovered. The status routine prints the delivery message. On later input, Q and R are handled before line 140 prevents further movement. Success therefore stops walking but still permits replay or exit.
won is a flag: zero means the room is active; one means it is complete. Restart already resets it at line 80, along with the player and step count. A held direction cannot act as R or Q, so completing a room cannot dismiss its own ending.

Run from the instructions. Try an unrelated key, then S. Solve the room, try another movement key, replay with R, and quit with Q. Also try Q directly from the instructions on another RUN. Each replay should restore the crate, player, zero steps and GOALS 0/1.
If the completion message appears but walking continues, check line 140. If replay leaves GOALS at 1/1, check that the call at 85 follows the room’s reconstruction. You now have a complete one-room game. The next work makes its room easier to describe and extend.
Sources
Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapters 4–5 (loops and control flow), 12 (arrays), and 18 (keyboard polling).
Run it here
This unit's program, built for you.
- Program
- step-02.tap
- Machine
- ZX Spectrum 48K (PAL)