Skip to content

Look around at corners

Represent a patrol as positions and changing facings.

  • Sinclair ZX Spectrum
  • BASIC

Following immediately behind the guard is about to become a worse plan. At each corner it will look back, face the next corridor, and only then walk on.

Continue from Keep a patrol moving. We will replace the corner calculation with a table of guard positions and facings. Capture still requires contact until we add sight.

A pause can be a record

Each record has three fields: guard column, guard row, facing. The opening record at 8200 is (7,5,1). Subsequent records describe each new phase. Near the first corner, the sequence is:

Phase Position Facing Action
17 (24,5) East Arrive
18 (24,5) West Look back
19 (24,5) South Check the next corridor
20 (24,6) South Walk

Three records share one position. Their facings tell different stories. Because each phase lasts two player updates, the stationary looks are readable parts of the patrol.

Enter the phase table

Replace lines 100, 430, 440.

Add lines 420, 8200–8800 in steps of ten.

There are no lines to delete. Enter the changed lines below; their numbers replace existing lines or insert new ones.

changes.bas
 100 LET x=3: LET y=16: LET phase=0
 420 LET phase=phase+1: IF phase=61 THEN LET phase=1
 430 RESTORE 8200+10*phase: READ gx,gy,gd
 440 GO SUB 2000
8200 DATA 7,5,1
8210 DATA 8,5,1
8220 DATA 9,5,1
8230 DATA 10,5,1
8240 DATA 11,5,1
8250 DATA 12,5,1
8260 DATA 13,5,1
8270 DATA 14,5,1
8280 DATA 15,5,1
8290 DATA 16,5,1
8300 DATA 17,5,1
8310 DATA 18,5,1
8320 DATA 19,5,1
8330 DATA 20,5,1
8340 DATA 21,5,1
8350 DATA 22,5,1
8360 DATA 23,5,1
8370 DATA 24,5,1
8380 DATA 24,5,3
8390 DATA 24,5,2
8400 DATA 24,6,2
8410 DATA 24,7,2
8420 DATA 24,8,2
8430 DATA 24,9,2
8440 DATA 24,10,2
8450 DATA 24,11,2
8460 DATA 24,12,2
8470 DATA 24,13,2
8480 DATA 24,14,2
8490 DATA 24,14,4
8500 DATA 24,14,3
8510 DATA 23,14,3
8520 DATA 22,14,3
8530 DATA 21,14,3
8540 DATA 20,14,3
8550 DATA 19,14,3
8560 DATA 18,14,3
8570 DATA 17,14,3
8580 DATA 16,14,3
8590 DATA 15,14,3
8600 DATA 14,14,3
8610 DATA 13,14,3
8620 DATA 12,14,3
8630 DATA 11,14,3
8640 DATA 10,14,3
8650 DATA 9,14,3
8660 DATA 8,14,3
8670 DATA 7,14,3
8680 DATA 7,14,1
8690 DATA 7,14,4
8700 DATA 7,13,4
8710 DATA 7,12,4
8720 DATA 7,11,4
8730 DATA 7,10,4
8740 DATA 7,9,4
8750 DATA 7,8,4
8760 DATA 7,7,4
8770 DATA 7,6,4
8780 DATA 7,5,4
8790 DATA 7,5,2
8800 DATA 7,5,1
Complete program at this stage
night-patrol.bas
  10 GO SUB 7000: GO SUB 7100
 100 LET x=3: LET y=16: LET phase=0
 120 LET gx=7: LET gy=5: LET gd=1
 130 LET got=0: LET outcome=0: LET beat=0: LET steps=0
 140 GO SUB 1000: GO SUB 3300: GO SUB 2500
 150 LET tick=PEEK 23672
 200 LET k$=INKEY$
 210 IF k$="q" OR k$="Q" THEN GO TO 9000
 220 IF k$="r" OR k$="R" THEN GO SUB 8100: GO TO 100
 230 LET elapsed=PEEK 23672-tick: IF elapsed<0 THEN LET elapsed=elapsed+256
 240 IF elapsed<8 THEN GO TO 200
 250 LET k$=INKEY$
 260 LET dx=0: LET dy=0
 270 IF k$="i" OR k$="I" THEN LET dy=-1
 280 IF k$="k" OR k$="K" THEN LET dy=1
 290 IF k$="j" OR k$="J" THEN LET dx=-1
 300 IF k$="l" OR k$="L" THEN LET dx=1
 310 LET nx=x+dx: LET ny=y+dy
 320 IF m$(ny,nx)=CHR$ 145 THEN GO TO 370
 330 IF nx=x AND ny=y THEN GO TO 370
 340 LET r=y: LET c=x: LET x=nx: LET y=ny: GO SUB 2000
 350 LET steps=steps+1: LET r=y: LET c=x: GO SUB 2000
 370 IF x=gx AND y=gy THEN LET outcome=1: GO TO 4000
 380 IF x=27 AND y=3 AND got=0 THEN LET got=1: GO SUB 2500
 390 IF x=3 AND y=16 AND got=1 THEN LET outcome=2: GO TO 4000
 400 LET beat=beat+1: IF beat<2 THEN GO TO 470
 410 LET beat=0: LET r=gy: LET c=gx
 420 LET phase=phase+1: IF phase=61 THEN LET phase=1
 430 RESTORE 8200+10*phase: READ gx,gy,gd
 440 GO SUB 2000
 455 GO SUB 3300
 460 IF x=gx AND y=gy THEN LET outcome=1: GO TO 4000
 470 LET tick=PEEK 23672: GO TO 200
1000 BORDER 0: PAPER 0: INK 7: BRIGHT 0: CLS
1010 PRINT AT 0,1; INK 5; BRIGHT 1;"NIGHT PATROL";AT 0,20;"THE ARCHIVE"
1020 FOR r=1 TO 18: PRINT AT r+1,1; INK 1; BRIGHT 1;m$(r): NEXT r
1022 LET r=3: LET c=27: GO SUB 2000
1024 LET r=y: LET c=x: GO SUB 2000
1030 PRINT AT 20,1;"I up  J left  K down  L right"
1040 PRINT AT 21,1;"R retry              Q quit";
1050 RETURN
2000 LET z$=" ": LET colour=7: LET shade=0
2010 IF m$(r,c)=CHR$ 145 THEN LET z$=CHR$ 145: LET colour=1
2030 IF r=3 AND c=27 AND got=0 THEN LET z$=CHR$ 146: LET colour=5
2040 IF r=16 AND c=3 THEN LET z$=CHR$ 147: LET colour=4
2050 IF r=gy AND c=gx THEN LET z$=g$(gd): LET colour=6
2060 IF r=y AND c=x THEN LET z$=CHR$ 144: LET colour=7
2080 PRINT AT r+1,c; PAPER shade; INK colour; BRIGHT 1;z$: RETURN
2500 PRINT AT 1,1; INK 5;"TAKE THE FILE. RETURN TO EXIT. "
2510 IF got=1 THEN PRINT AT 1,1; INK 4;"FILE TAKEN. GET BACK TO EXIT.  "
2520 RETURN
3300 LET r=gy: LET c=gx: GO SUB 2000: RETURN
4000 LET r=y: LET c=x: GO SUB 2000
4010 IF outcome=1 THEN PRINT AT 1,1; INK 2; BRIGHT 1;"CAUGHT! Keep clear of the guard."
4020 IF outcome=2 THEN PRINT AT 1,1; INK 4; BRIGHT 1;"FILE RECOVERED. CLEAN GETAWAY! "
4030 PRINT AT 20,1;"R tries again. Q quits.      "
4040 GO SUB 8000
4050 IF k$="r" OR k$="R" THEN GO SUB 8100: GO TO 100
4060 IF k$="q" OR k$="Q" THEN GO TO 9000
4070 GO TO 4040
7000 RESTORE 7500: FOR j=0 TO 31: READ a: POKE USR "a"+j,a: NEXT j
7010 DIM a(4): DIM b(4): LET a(1)=1: LET b(2)=1: LET a(3)=-1: LET b(4)=-1
7020 LET g$=">v<"+CHR$ 94: RETURN
7100 DIM m$(18,30): RESTORE 7200
7110 FOR r=1 TO 18: READ m$(r): FOR c=1 TO 30
7120 IF m$(r,c)="#" THEN LET m$(r,c)=CHR$ 145
7130 NEXT c: NEXT r: RETURN
7200 DATA "##############################"
7210 DATA "##############################"
7220 DATA "###########  ############# ###"
7230 DATA "#####        #######     # ###"
7240 DATA "#####                      ###"
7250 DATA "#####     ######   #     #####"
7260 DATA "###### #########  ##### ######"
7270 DATA "######   ############   ######"
7280 DATA "######   ############   ######"
7290 DATA "######  ##############  ######"
7300 DATA "####   ################   ####"
7310 DATA "####   ####  ##########   ####"
7320 DATA "#####        #######     #####"
7330 DATA "#####                    #####"
7340 DATA "#####     ######   #     #####"
7350 DATA "##     #########  ############"
7360 DATA "##############################"
7370 DATA "##############################"
7500 DATA 24,24,0,60,90,24,36,66
7510 DATA 255,128,128,255,8,8,8,255
7520 DATA 126,66,90,66,90,66,126,0
7530 DATA 126,66,66,74,66,66,126,0
8000 GO SUB 8100
8010 LET k$=INKEY$: IF k$="" THEN GO TO 8010
8020 RETURN
8100 IF INKEY$<>"" THEN GO TO 8100
8110 RETURN
8200 DATA 7,5,1
8210 DATA 8,5,1
8220 DATA 9,5,1
8230 DATA 10,5,1
8240 DATA 11,5,1
8250 DATA 12,5,1
8260 DATA 13,5,1
8270 DATA 14,5,1
8280 DATA 15,5,1
8290 DATA 16,5,1
8300 DATA 17,5,1
8310 DATA 18,5,1
8320 DATA 19,5,1
8330 DATA 20,5,1
8340 DATA 21,5,1
8350 DATA 22,5,1
8360 DATA 23,5,1
8370 DATA 24,5,1
8380 DATA 24,5,3
8390 DATA 24,5,2
8400 DATA 24,6,2
8410 DATA 24,7,2
8420 DATA 24,8,2
8430 DATA 24,9,2
8440 DATA 24,10,2
8450 DATA 24,11,2
8460 DATA 24,12,2
8470 DATA 24,13,2
8480 DATA 24,14,2
8490 DATA 24,14,4
8500 DATA 24,14,3
8510 DATA 23,14,3
8520 DATA 22,14,3
8530 DATA 21,14,3
8540 DATA 20,14,3
8550 DATA 19,14,3
8560 DATA 18,14,3
8570 DATA 17,14,3
8580 DATA 16,14,3
8590 DATA 15,14,3
8600 DATA 14,14,3
8610 DATA 13,14,3
8620 DATA 12,14,3
8630 DATA 11,14,3
8640 DATA 10,14,3
8650 DATA 9,14,3
8660 DATA 8,14,3
8670 DATA 7,14,3
8680 DATA 7,14,1
8690 DATA 7,14,4
8700 DATA 7,13,4
8710 DATA 7,12,4
8720 DATA 7,11,4
8730 DATA 7,10,4
8740 DATA 7,9,4
8750 DATA 7,8,4
8760 DATA 7,7,4
8770 DATA 7,6,4
8780 DATA 7,5,4
8790 DATA 7,5,2
8800 DATA 7,5,1
9000 PAPER 0: INK 7: BRIGHT 0: PRINT AT 21,0;"Finished. RUN to try again.     ";: STOP

RUN and watch each corner. The guard should arrive, turn to look behind, turn towards the next passage and then move. There are eight stationary facing changes per circuit: two at each of four corners.

Find the next record

phase starts at zero. Line 420 advances it; after 60 it returns to one. Line 430 uses RESTORE 8200+10*phase, then READ consumes the three fields. Thus phase 18 selects line 8380. RESTORE is explicit because READ otherwise carries on from wherever the last read ended.

The complete circuit has 52 walking phases and eight stationary phases. Phase 60 returns to (7,5), facing east, the same pose as the opening. Its successor is phase one, moving to (8,5). Inserting phase zero at every wrap would add an unwanted extra pause.

The program still prepares a() and b(), but the table now supplies the positions directly. Those arrays no longer drive this guard. Keeping track of which representation owns a decision matters more than the variable names left in the listing.

Why can this guard look back without walking backwards?

Show the explanation

Its facing is an independent field. A record can change gd while keeping gx and gy unchanged. Direction no longer automatically implies displacement.

Check the last corner as carefully as the first. The look-back there faces south; the next-corridor look faces east. Watch the following step to (8,5), then retry and confirm that the opening pose is restored. A repeated phase or a missing turn usually means a mistyped DATA record or wrap condition.

Sources

Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapter 5, chapter 6.

Run it here

This unit's program, built for you.

Program
night-patrol.tap
Machine
ZX Spectrum 48K (PAL)

Download night-patrol.tap