Skip to content
Game 3

Read the shape of the site

We can now describe a landscape as values, then make its sides participate in contact.

Continue with Give every column a ground height, with the temporary line 35 removed. We can now describe a landscape as values, then make its sides participate in contact.

Read the flat site from DATA

Add line 9000. Replace lines 20, 30.

20 DIM h(32): RESTORE 9000
30 FOR c=1 TO 32: READ h(c): NEXT c
9000 DATA 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20

DATA stores a list of values in the program. READ takes the next value and assigns it to its destination. Here each trip through the loop reads one height into h(c). RESTORE 9000 positions reading at that DATA line before the loop begins.

There are 32 values because there are 32 columns. Their order runs left to right. DATA does not draw anything and is not an assignment executed each time the flight loop reaches it. The values become the array when READ runs.

This first list is deliberately all 20s. It should produce the same flat site as the preceding version. If there are too few values, READ eventually reports that the data has run out; check the count rather than inventing a height to silence the report.

Complete program for this step
10 BORDER 0: PAPER 0: INK 7: BRIGHT 1: CLS
20 DIM h(32): RESTORE 9000
30 FOR c=1 TO 32: READ h(c): NEXT c
50 PRINT AT 3,9;"TOUCHDOWN"
60 PRINT AT 6,2;"O / P: steer left / right"
70 PRINT AT 8,2;"SPACE: thrust (with steering)"
80 PRINT AT 10,2;"Pad: ========  Safe: 0 to 12"
90 PRINT AT 12,2;"Empty tank? You still coast."
100 PRINT AT 15,2;"S launches. Q quits."
110 GO SUB 800: IF k$="q" THEN GO TO 850
120 CLS: GO SUB 600
130 LET x=18: LET y=400: LET v=0: LET fuel=45: LET r=4: LET burn=0
140 PRINT AT r,x;"A"
150 PRINT AT 0,1;"FUEL       SPEED       MAX 12"
160 PRINT AT 1,1;"O/P STEER  SPACE THRUST  Q QUIT"
200 LET k$=INKEY$: IF k$="q" THEN GO TO 850
210 LET keys=IN 57342: LET nx=x
220 IF INT (keys/2)-2*INT (keys/4)=0 THEN LET nx=nx-1
230 IF keys-2*INT (keys/2)=0 THEN LET nx=nx+1
240 IF nx<1 THEN LET nx=1
250 IF nx>30 THEN LET nx=30
260 LET burn=0: LET keys=IN 32766
270 IF keys-2*INT (keys/2)=0 AND fuel>0 THEN LET burn=1: LET fuel=fuel-1
280 LET v=v+2-6*burn
290 IF v>60 THEN LET v=60
300 IF v<-30 THEN LET v=-30
310 LET ny=y+v: LET contact=0: LET limit=100*(h(nx+1)-1)
330 IF ny>=limit THEN LET contact=1
340 IF contact=1 THEN LET ny=limit
350 IF ny<300 THEN LET ny=300: LET v=0
360 LET nr=INT (ny/100)
370 PRINT AT 0,6;fuel;"  ";AT 0,19;v;"   "
375 LET a$="A": IF burn=1 THEN LET a$="*"
380 PRINT AT r,x;" ";AT nr,nx;a$
390 LET x=nx: LET y=ny: LET r=nr
400 IF contact=1 THEN GO TO 700
410 PAUSE 2: GO TO 200
600 FOR c=0 TO 31
610 FOR j=h(c+1) TO 21: PRINT PAPER 4;INK 0;AT j,c;" ";: NEXT j
620 PRINT PAPER 4;INK 0;AT h(c+1),c;"#"
630 NEXT c
640 FOR c=20 TO 27: PRINT PAPER 6;INK 0;AT 20,c;"=": NEXT c
650 RETURN
700 PRINT AT r,x;"A"
710 LET m$="Off the pad."
720 IF x>=20 AND x<=27 THEN LET m$="Too fast for the pad."
730 IF x>=20 AND x<=27 AND v<=12 AND v>=0 THEN LET m$="Safe landing!"
740 PRINT AT 2,1;m$;"    "
770 PRINT AT 1,1;"R retries. Q quits.            "
780 IF INKEY$<>"" THEN GO TO 780
790 LET k$=INKEY$: IF k$<>"r" AND k$<>"q" THEN GO TO 790
795 IF INKEY$<>"" THEN GO TO 795
796 IF k$="q" THEN GO TO 850
797 GO TO 120
800 IF INKEY$<>"" THEN GO TO 800
810 LET k$=INKEY$: IF k$<>"s" AND k$<>"q" THEN GO TO 810
820 IF INKEY$<>"" THEN GO TO 820
830 RETURN
850 IF INKEY$<>"" THEN GO TO 850
860 PAPER 0: INK 7: CLS: PRINT "Finished.": STOP
9000 DATA 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20

One obstacle and its side

Add lines 320, 345. Replace lines 310, 710, 720, 730, 9000.

310 LET ny=y+v: LET contact=0: LET side=0: LET limit=100*(h(nx+1)-1)
320 IF nx<>x AND y>=limit THEN LET contact=1: LET side=1: LET nx=x
345 IF side=1 THEN LET ny=y
710 LET m$="Terrain collision."
720 IF side=0 AND x>=20 AND x<=27 THEN LET m$="Too fast for the pad."
730 IF side=0 AND x>=20 AND x<=27 AND v<=12 AND v>=0 THEN LET m$="Safe landing!"
9000 DATA 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,18,20,20,20,20,20,20,20,20,20,20,20,20

The twentieth DATA value is now 18. That raises screen column 19, immediately beside the starting column, while keeping the pad level. The craft can strike its side before it reaches ordinary ground.

Line 320 checks a horizontal move using the old vertical position and the destination column’s limit. If that position is already at or below the destination surface, it records side=1 and keeps nx=x. After other contact handling, line 345 also restores ny=y. The craft stays in its previous clear cell rather than being drawn inside the hillside or teleported to its top.

The side flag starts at zero on every update. It prevents a side collision from being reclassified as a safe pad landing. The ordinary downward crossing test remains: a proposed vertical position reaching or passing the surface is clamped before drawing.

For a numerical example, suppose the craft’s position is 1490 and it moves into a column whose contact limit is 1400. Even if thrust makes its proposed position 1482, it is still entering solid terrain. That is a side collision, not an upward escape through the cliff.

Why isn’t checking only whether the new position reaches the ground enough for sideways movement?

Show the explanation

The craft can cross into a taller column while already below its top. Resolving that as an ordinary downward arrival could move it upwards to the top or mislabel the result. The old height and destination column establish that it entered a side; the side flag preserves that reason for failure.

Complete program for this step
10 BORDER 0: PAPER 0: INK 7: BRIGHT 1: CLS
20 DIM h(32): RESTORE 9000
30 FOR c=1 TO 32: READ h(c): NEXT c
50 PRINT AT 3,9;"TOUCHDOWN"
60 PRINT AT 6,2;"O / P: steer left / right"
70 PRINT AT 8,2;"SPACE: thrust (with steering)"
80 PRINT AT 10,2;"Pad: ========  Safe: 0 to 12"
90 PRINT AT 12,2;"Empty tank? You still coast."
100 PRINT AT 15,2;"S launches. Q quits."
110 GO SUB 800: IF k$="q" THEN GO TO 850
120 CLS: GO SUB 600
130 LET x=18: LET y=400: LET v=0: LET fuel=45: LET r=4: LET burn=0
140 PRINT AT r,x;"A"
150 PRINT AT 0,1;"FUEL       SPEED       MAX 12"
160 PRINT AT 1,1;"O/P STEER  SPACE THRUST  Q QUIT"
200 LET k$=INKEY$: IF k$="q" THEN GO TO 850
210 LET keys=IN 57342: LET nx=x
220 IF INT (keys/2)-2*INT (keys/4)=0 THEN LET nx=nx-1
230 IF keys-2*INT (keys/2)=0 THEN LET nx=nx+1
240 IF nx<1 THEN LET nx=1
250 IF nx>30 THEN LET nx=30
260 LET burn=0: LET keys=IN 32766
270 IF keys-2*INT (keys/2)=0 AND fuel>0 THEN LET burn=1: LET fuel=fuel-1
280 LET v=v+2-6*burn
290 IF v>60 THEN LET v=60
300 IF v<-30 THEN LET v=-30
310 LET ny=y+v: LET contact=0: LET side=0: LET limit=100*(h(nx+1)-1)
320 IF nx<>x AND y>=limit THEN LET contact=1: LET side=1: LET nx=x
330 IF ny>=limit THEN LET contact=1
340 IF contact=1 THEN LET ny=limit
345 IF side=1 THEN LET ny=y
350 IF ny<300 THEN LET ny=300: LET v=0
360 LET nr=INT (ny/100)
370 PRINT AT 0,6;fuel;"  ";AT 0,19;v;"   "
375 LET a$="A": IF burn=1 THEN LET a$="*"
380 PRINT AT r,x;" ";AT nr,nx;a$
390 LET x=nx: LET y=ny: LET r=nr
400 IF contact=1 THEN GO TO 700
410 PAUSE 2: GO TO 200
600 FOR c=0 TO 31
610 FOR j=h(c+1) TO 21: PRINT PAPER 4;INK 0;AT j,c;" ";: NEXT j
620 PRINT PAPER 4;INK 0;AT h(c+1),c;"#"
630 NEXT c
640 FOR c=20 TO 27: PRINT PAPER 6;INK 0;AT 20,c;"=": NEXT c
650 RETURN
700 PRINT AT r,x;"A"
710 LET m$="Terrain collision."
720 IF side=0 AND x>=20 AND x<=27 THEN LET m$="Too fast for the pad."
730 IF side=0 AND x>=20 AND x<=27 AND v<=12 AND v>=0 THEN LET m$="Safe landing!"
740 PRINT AT 2,1;m$;"    "
770 PRINT AT 1,1;"R retries. Q quits.            "
780 IF INKEY$<>"" THEN GO TO 780
790 LET k$=INKEY$: IF k$<>"r" AND k$<>"q" THEN GO TO 790
795 IF INKEY$<>"" THEN GO TO 795
796 IF k$="q" THEN GO TO 850
797 GO TO 120
800 IF INKEY$<>"" THEN GO TO 800
810 LET k$=INKEY$: IF k$<>"s" AND k$<>"q" THEN GO TO 810
820 IF INKEY$<>"" THEN GO TO 820
830 RETURN
850 IF INKEY$<>"" THEN GO TO 850
860 PAPER 0: INK 7: CLS: PRINT "Finished.": STOP
9000 DATA 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,18,20,20,20,20,20,20,20,20,20,20,20,20

Extend the approach on flat ground

Replace lines 130, 9000.

130 LET x=6: LET y=400: LET v=0: LET fuel=45: LET r=4: LET burn=0
9000 DATA 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20

This checkpoint restores flat heights and moves the start to column 6. The pad stays wide. It separates the longer steering task from the ridge: practise covering the distance while preserving enough height to brake.

A complete reset still starts at the chosen position. It does not reread DATA on every retry, because the stored landscape has not changed. RUN starts the program afresh and uses RESTORE before filling the array again.

Complete program for this step
10 BORDER 0: PAPER 0: INK 7: BRIGHT 1: CLS
20 DIM h(32): RESTORE 9000
30 FOR c=1 TO 32: READ h(c): NEXT c
50 PRINT AT 3,9;"TOUCHDOWN"
60 PRINT AT 6,2;"O / P: steer left / right"
70 PRINT AT 8,2;"SPACE: thrust (with steering)"
80 PRINT AT 10,2;"Pad: ========  Safe: 0 to 12"
90 PRINT AT 12,2;"Empty tank? You still coast."
100 PRINT AT 15,2;"S launches. Q quits."
110 GO SUB 800: IF k$="q" THEN GO TO 850
120 CLS: GO SUB 600
130 LET x=6: LET y=400: LET v=0: LET fuel=45: LET r=4: LET burn=0
140 PRINT AT r,x;"A"
150 PRINT AT 0,1;"FUEL       SPEED       MAX 12"
160 PRINT AT 1,1;"O/P STEER  SPACE THRUST  Q QUIT"
200 LET k$=INKEY$: IF k$="q" THEN GO TO 850
210 LET keys=IN 57342: LET nx=x
220 IF INT (keys/2)-2*INT (keys/4)=0 THEN LET nx=nx-1
230 IF keys-2*INT (keys/2)=0 THEN LET nx=nx+1
240 IF nx<1 THEN LET nx=1
250 IF nx>30 THEN LET nx=30
260 LET burn=0: LET keys=IN 32766
270 IF keys-2*INT (keys/2)=0 AND fuel>0 THEN LET burn=1: LET fuel=fuel-1
280 LET v=v+2-6*burn
290 IF v>60 THEN LET v=60
300 IF v<-30 THEN LET v=-30
310 LET ny=y+v: LET contact=0: LET side=0: LET limit=100*(h(nx+1)-1)
320 IF nx<>x AND y>=limit THEN LET contact=1: LET side=1: LET nx=x
330 IF ny>=limit THEN LET contact=1
340 IF contact=1 THEN LET ny=limit
345 IF side=1 THEN LET ny=y
350 IF ny<300 THEN LET ny=300: LET v=0
360 LET nr=INT (ny/100)
370 PRINT AT 0,6;fuel;"  ";AT 0,19;v;"   "
375 LET a$="A": IF burn=1 THEN LET a$="*"
380 PRINT AT r,x;" ";AT nr,nx;a$
390 LET x=nx: LET y=ny: LET r=nr
400 IF contact=1 THEN GO TO 700
410 PAUSE 2: GO TO 200
600 FOR c=0 TO 31
610 FOR j=h(c+1) TO 21: PRINT PAPER 4;INK 0;AT j,c;" ";: NEXT j
620 PRINT PAPER 4;INK 0;AT h(c+1),c;"#"
630 NEXT c
640 FOR c=20 TO 27: PRINT PAPER 6;INK 0;AT 20,c;"=": NEXT c
650 RETURN
700 PRINT AT r,x;"A"
710 LET m$="Terrain collision."
720 IF side=0 AND x>=20 AND x<=27 THEN LET m$="Too fast for the pad."
730 IF side=0 AND x>=20 AND x<=27 AND v<=12 AND v>=0 THEN LET m$="Safe landing!"
740 PRINT AT 2,1;m$;"    "
770 PRINT AT 1,1;"R retries. Q quits.            "
780 IF INKEY$<>"" THEN GO TO 780
790 LET k$=INKEY$: IF k$<>"r" AND k$<>"q" THEN GO TO 790
795 IF INKEY$<>"" THEN GO TO 795
796 IF k$="q" THEN GO TO 850
797 GO TO 120
800 IF INKEY$<>"" THEN GO TO 800
810 LET k$=INKEY$: IF k$<>"s" AND k$<>"q" THEN GO TO 810
820 IF INKEY$<>"" THEN GO TO 820
830 RETURN
850 IF INKEY$<>"" THEN GO TO 850
860 PAPER 0: INK 7: CLS: PRINT "Finished.": STOP
9000 DATA 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20

Give the site its skyline

Replace line 9000.

9000 DATA 18,18,18,19,19,19,19,19,18,17,16,15,14,14,14,15,16,17,18,19,20,20,20,20,20,20,20,20,19,18,18,18

The new DATA list builds a ridge between the start and the pad. Keep each value aligned with its column when editing it. The pad’s columns remain at ground row 20; drawing a flat yellow pad over mismatched height data would be a misleading target.

Run a few approaches without changing the flight constants. You now need to clear the ridge as well as arrive slowly. A smaller height value makes a column taller; try changing one off-pad value, predict the skyline and then test both a downward arrival and a sideways approach to it.

Keep the wide-pad version. It will help us compare the final narrower target without changing terrain and target width at once.

Complete program for this step
10 BORDER 0: PAPER 0: INK 7: BRIGHT 1: CLS
20 DIM h(32): RESTORE 9000
30 FOR c=1 TO 32: READ h(c): NEXT c
50 PRINT AT 3,9;"TOUCHDOWN"
60 PRINT AT 6,2;"O / P: steer left / right"
70 PRINT AT 8,2;"SPACE: thrust (with steering)"
80 PRINT AT 10,2;"Pad: ========  Safe: 0 to 12"
90 PRINT AT 12,2;"Empty tank? You still coast."
100 PRINT AT 15,2;"S launches. Q quits."
110 GO SUB 800: IF k$="q" THEN GO TO 850
120 CLS: GO SUB 600
130 LET x=6: LET y=400: LET v=0: LET fuel=45: LET r=4: LET burn=0
140 PRINT AT r,x;"A"
150 PRINT AT 0,1;"FUEL       SPEED       MAX 12"
160 PRINT AT 1,1;"O/P STEER  SPACE THRUST  Q QUIT"
200 LET k$=INKEY$: IF k$="q" THEN GO TO 850
210 LET keys=IN 57342: LET nx=x
220 IF INT (keys/2)-2*INT (keys/4)=0 THEN LET nx=nx-1
230 IF keys-2*INT (keys/2)=0 THEN LET nx=nx+1
240 IF nx<1 THEN LET nx=1
250 IF nx>30 THEN LET nx=30
260 LET burn=0: LET keys=IN 32766
270 IF keys-2*INT (keys/2)=0 AND fuel>0 THEN LET burn=1: LET fuel=fuel-1
280 LET v=v+2-6*burn
290 IF v>60 THEN LET v=60
300 IF v<-30 THEN LET v=-30
310 LET ny=y+v: LET contact=0: LET side=0: LET limit=100*(h(nx+1)-1)
320 IF nx<>x AND y>=limit THEN LET contact=1: LET side=1: LET nx=x
330 IF ny>=limit THEN LET contact=1
340 IF contact=1 THEN LET ny=limit
345 IF side=1 THEN LET ny=y
350 IF ny<300 THEN LET ny=300: LET v=0
360 LET nr=INT (ny/100)
370 PRINT AT 0,6;fuel;"  ";AT 0,19;v;"   "
375 LET a$="A": IF burn=1 THEN LET a$="*"
380 PRINT AT r,x;" ";AT nr,nx;a$
390 LET x=nx: LET y=ny: LET r=nr
400 IF contact=1 THEN GO TO 700
410 PAUSE 2: GO TO 200
600 FOR c=0 TO 31
610 FOR j=h(c+1) TO 21: PRINT PAPER 4;INK 0;AT j,c;" ";: NEXT j
620 PRINT PAPER 4;INK 0;AT h(c+1),c;"#"
630 NEXT c
640 FOR c=20 TO 27: PRINT PAPER 6;INK 0;AT 20,c;"=": NEXT c
650 RETURN
700 PRINT AT r,x;"A"
710 LET m$="Terrain collision."
720 IF side=0 AND x>=20 AND x<=27 THEN LET m$="Too fast for the pad."
730 IF side=0 AND x>=20 AND x<=27 AND v<=12 AND v>=0 THEN LET m$="Safe landing!"
740 PRINT AT 2,1;m$;"    "
770 PRINT AT 1,1;"R retries. Q quits.            "
780 IF INKEY$<>"" THEN GO TO 780
790 LET k$=INKEY$: IF k$<>"r" AND k$<>"q" THEN GO TO 790
795 IF INKEY$<>"" THEN GO TO 795
796 IF k$="q" THEN GO TO 850
797 GO TO 120
800 IF INKEY$<>"" THEN GO TO 800
810 LET k$=INKEY$: IF k$<>"s" AND k$<>"q" THEN GO TO 810
820 IF INKEY$<>"" THEN GO TO 820
830 RETURN
850 IF INKEY$<>"" THEN GO TO 850
860 PAPER 0: INK 7: CLS: PRINT "Finished.": STOP
9000 DATA 18,18,18,19,19,19,19,19,18,17,16,15,14,14,14,15,16,17,18,19,20,20,20,20,20,20,20,20,19,18,18,18

Sources

Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapter 6 (READ, DATA and RESTORE), chapter 12 (arrays), and chapter 15 (PRINT AT).