This is a space combat strategy game in the style of Star Trek, played on a 10×10 grid. Two parallel arrays, A() and B(), track game state and display state respectively: A() holds logical values (0=empty, 1=alien, 2=player) while B() drives the map rendering with additional codes for misses (3) and kills (4). The player chooses between scanning, moving, and firing each turn, with an energy budget that depletes by 10, 50, or 100 units depending on the action. Sector names are derived by multiplying the player’s grid coordinates and mapping the product to one of ten star names. The program uses FAST/SLOW mode switching around the map redraw routine at line 8000 to speed up screen output.
Program Analysis
Program Structure
The program is organized into a main loop and a set of subroutines identified by line-number ranges:
| Line Range | Purpose |
|---|---|
| 10–500 | Main loop: initialisation calls, command menu, dispatch |
| 1000–1700 | Scanner (close and long-range) |
| 2000–2300 | Move command |
| 3000–3460 | Fire command |
| 3800–3890 | Game-over / energy exhausted |
| 5000–5900 | Ship collision / stop |
| 6950–6970 | Clear message area (lines 13+) |
| 7000–7490 | Status display |
| 7500–7900 | Random crew-member voice prefix |
| 8000–8490 | Map redraw |
| 8500–8740 | Sector name lookup |
| 9000–9900 | Initialisation (arrays, position, energy, alien name) |
Command Dispatch
Line 160 uses the expression GOSUB 1000*D where D is 1, 2, or 3, dispatching to subroutines at lines 1000, 2000, or 3000 respectively. This is a compact computed-GOSUB idiom that avoids an IF/GOTO ladder. Input validation at line 150 ensures D is always in range before the multiplication.
Dual-Array Map Design
Two 10×10 arrays serve distinct roles:
A(Q,P)— logical state: 0 = empty, 1 = alien ship, 2 = player shipB(Q,P)— display state: 0 = empty, 2 = player, 3 = missed shot marker, 4 = destroyed alien
The map renderer at line 8000 iterates over B() exclusively, printing inverse-video characters for each cell code. This separation means the game logic can query A() cleanly without display artefacts interfering.
Map Rendering and FAST/SLOW
The subroutine at line 8000 wraps its output between FAST (line 8002) and SLOW (line 8225) to minimise flicker and speed up the 10×10 grid draw. A compass rose (N/+/W·E/S) is printed at a fixed position (lines 8220–8223) using AT coordinates to the right of the grid. Each row also prints a cursor-reset sequence (AT Q,13;"\@@" then AT Q,13;" ") before printing cell contents, likely to handle line-wrap artefacts.
Sector Name Calculation
Line 8520 computes Q=B*C (player row × column) and maps the product to one of ten sector names via a chain of IF comparisons spanning lines 8540–8720. This gives a positionally-derived name that changes as the player moves, though the mapping is not bijective — many coordinate pairs yield the same product and thus the same sector name. Note line 8700 contains a typo: STRIUS instead of SIRIUS.
Random Crew Voice
Subroutine 7500 picks R=INT(RND*5) and prints one of five crew-member prefixes (Spock, Scott, Uhura, Chekov, Sulu) before any message. This is called before nearly every player-facing PRINT to simulate crew reporting, adding narrative flavour without additional logic.
Energy Economy
| Action | Energy Cost |
|---|---|
| Close scanner (K=1) | 10 |
| Long-range scanner (K=2) | 20 |
| Move | 50 |
| Fire (hit or miss) | 100 |
| Enemy return fire hit | 100 × RND (additional) |
Starting energy is 1000 + 2000*RND (line 9340), giving a range of 1000–3000. Energy is checked at line 7030; if it drops below 1, execution jumps to the game-over sequence at line 3800.
Initialisation and Variable Reuse
The initialisation subroutine at line 9000 uses the loop variable A for its FOR loop (lines 9060–9140) even though A is also the name of the 2D array A(). In Sinclair BASIC, a simple variable and an array variable share the same name space only if they have the same name but differ in dimension; here the loop variable A and array A() coexist because array access always uses parentheses. However, this is a risky naming choice that could confuse maintenance.
Collision Detection
After a move, line 2260 checks IF A(B,C)=1 (new cell contains an alien) and branches to line 5500, which enters an alternating inverse/normal print loop displaying a collision message — effectively a terminal game-over state that loops indefinitely without a clean exit.
Bugs and Anomalies
- Line
3400is referenced byGOTO 3400at line3340but does not exist; the branch falls through to line3420which prints the miss message. This is intentional ZX81 behaviour: branching to a non-existent line runs the next available line. - Line
1020is the effective entry point for the scanner subroutine, but the dispatch at line160callsGOSUB 1000— line1000does not exist, so execution begins at1020. Same technique as above. - The game-over loop at line
3890jumps back to3805(aSCROLLstatement), creating an infinite scroll that cannot be escaped without a manual break. - Typo at line
8700: STRIUS should be SIRIUS. - The
FOR G=1 TO 30: NEXT Gloops at lines 3315–3317 and 3330–3335 serve as busy-wait delays with no body, a common ZX81 timing technique. - Line
9260setsE=RND(a value between 0 and 1) solely to drive the alien-name selection at lines 9280–9320 before being overwritten by the actual energy value at line9340. This is a valid but potentially confusing reuse of the energy variable.
Content
Source Code
10 FAST
20 GOSUB 9000
25 GOSUB 8000
30 GOSUB 6950
40 GOSUB 7000
50 GOSUB 6950
80 GOSUB 7500
100 PRINT "WHAT IS YOUR ORDER,"
120 PRINT TAB 5;"SIR ?",,TAB 12;"1-SCAN";TAB 12;"2-MOVE";TAB 12;"3-FIRE"
140 INPUT D
150 IF D<1 OR D>3 THEN GOTO 140
155 GOSUB 6950
160 GOSUB 1000*D
170 FOR W=1 TO 30
180 PRINT AT 20,5;" : : : : :";AT 20,5;" "
190 NEXT W
500 GOTO 30
1020 PRINT TAB 4;"% % SCANNER % % "
1030 GOSUB 7500
1040 PRINT "CLOSE (1) OR ","LONG-RANGE (2), SIR ?"
1060 INPUT K
1080 LET E=E-10*K
1090 GOSUB 6950
1100 IF K=2 THEN GOTO 1500
1120 IF A(B+1,C)=1 OR A(B+1,C+1)=1 OR A(B,C+1)=1 OR A(B-1,C)=1 OR A(B-1,C-1)=1 OR A(B,C-1)=1 OR A(B+1,C-1)=1 OR A(B-1,C+1)=1 THEN PRINT Z$;" IN VICINITY,","SIR"
1140 RETURN
1500 GOSUB 7500
1520 PRINT AT 15,0;"DIRECTION: N-1, S-2, E-3, W-4 ?"
1525 PRINT TAB 8;"(ENTER A NUMBER)"
1530 INPUT N
1540 LET Z=0
1560 IF N=1 AND A(B-2,C)=1 THEN LET Z=1
1580 IF N=2 AND A(B+2,C)=1 THEN LET Z=1
1600 IF N=3 AND A(B,C+2)=1 THEN LET Z=1
1620 IF N=4 AND A(B,C-2)=1 THEN LET Z=1
1630 GOSUB 7500
1640 PRINT "LONG-RANGE SCANNER REPORT IS"
1660 IF Z=1 THEN PRINT "POSITIVE"
1680 IF Z=0 THEN PRINT "NEGATIVE"
1700 RETURN
2020 LET E=E-50
2040 LET A(B,C)=0
2050 LET B(B,C)=0
2060 PRINT "DIRECTION (N/S)?"
2080 INPUT A$
2100 LET B=B-1
2120 IF A$="S" THEN LET B=B+2
2130 GOSUB 7500
2140 PRINT "NOW AT ";B;",";C
2160 PRINT TAB 12;"(E/W)?"
2180 INPUT A$
2200 LET C=C-1
2220 IF A$="E" THEN LET C=C+2
2240 PRINT "NOW AT ";B;",";C
2260 IF A(B,C)=1 THEN GOTO 5500
2270 LET A(B,C)=2
2280 LET B(B,C)=2
2290 GOSUB 8000
2300 RETURN
3000 REM FIRE
3010 GOSUB 7500
3020 PRINT "DIRECTION OF FIRE (N/S)?"
3040 INPUT A$
3060 LET G=B-1
3080 IF A$="S" THEN LET G=G+2
3100 PRINT TAB 12;"(E/W)?"
3120 LET F=C-1
3140 INPUT A$
3160 IF A$="E" THEN LET F=F+2
3180 LET E=E-100
3190 IF A(G,F)<>1 THEN GOTO 3300
3195 GOSUB 7500
3200 PRINT "YOU HIT THE ";Z$
3220 LET AL=AL+1
3260 LET B(G,F)=4
3290 RETURN
3300 GOSUB 7500
3305 LET B(G,F)=3
3310 PRINT "YOU MISSED, SIR"
3315 FOR G=1 TO 30
3317 NEXT G
3320 PRINT "THE ";Z$;" ARE","SHOOTING BACK"
3330 FOR G=1 TO 30
3335 NEXT G
3337 GOSUB 6950
3340 IF RND>.6 THEN GOTO 3400
3360 PRINT "THEY HIT US, SIR"
3370 GOSUB 8000
3380 LET E=E-100*RND
3390 RETURN
3420 PRINT "THE ";Z$;" MISSED, SIR"
3460 RETURN
3800 GOSUB 6950
3805 SCROLL
3810 PRINT "ENERGY BANKS EXHAUSTED"
3815 SCROLL
3820 PRINT "YOU KILLED ";AL;" ALIEN";
3830 IF AL<>1 THEN PRINT "S"
3850 SCROLL
3860 PRINT "ON THIS MISSION"
3870 SCROLL
3880 PRINT "YOUR COMMANDER RATING IS ";INT (AL/8*100)
3890 GOTO 3805
5000 REM END
5500 GOSUB 6950
5520 PRINT AT 15,0;"YOUR SHIP HAS LANDED ON A",Z$;" VESSEL"
5540 PRINT AT 15,0;"%Y%O%U%R% %S%H%I%P% %H%A%S% %L%A%N%D%E%D% %O%N% %A"
5560 GOTO 5520
5900 STOP
6950 PRINT AT 13,0;" "
6955 PRINT AT 13,0;
6970 RETURN
7000 REM STATUS
7020 PRINT AT 2,14;"ENERGY BANK: ";INT E;" "
7030 IF E<1 THEN GOTO 3800
7040 IF AL>0 THEN PRINT AT 3,14;"ALIEN KILL";AT 4,17;"TALLY: ";AL
7060 PRINT AT 7,14;"YOU ARE AT ";B;",";C
7070 PRINT AT 8,14;" "
7075 PRINT AT 8,14;"IN ";
7080 GOSUB 8500
7100 PRINT " SECTOR"
7120 PRINT AT 12,0;
7490 RETURN
7500 LET R=INT (RND*5)
7520 IF R=0 THEN PRINT "SPOCK: AS YOU HUMANS SAY,"
7540 IF R=1 THEN PRINT "SCOTT: ";
7560 IF R=2 THEN PRINT "LT. UHURA: ";
7580 IF R=3 THEN PRINT "CHEKOV: ";
7600 IF R=4 THEN PRINT "SULU: ";
7900 RETURN
7999 STOP
8000 REM PRINT OUT
8002 FAST
8005 PRINT AT 0,0;
8010 PRINT " 1234567890"
8020 FOR Q=1 TO 10
8025 PRINT AT Q,13;"@@";AT Q,13;" "
8030 IF Q<10 THEN PRINT Q;" ";
8035 IF Q=10 THEN PRINT Q;
8040 FOR P=1 TO 10
8060 IF B(Q,P)=0 THEN PRINT "% ";
8080 IF B(Q,P)=2 THEN PRINT "%$";
8100 IF B(Q,P)=3 THEN PRINT "%X";
8120 IF B(Q,P)=4 THEN PRINT "%*";
8160 NEXT P
8200 NEXT Q
8210 PRINT
8220 PRINT AT 4,15;"N"
8221 PRINT AT 5,15;"+"
8222 PRINT AT 5,14;"W";AT 5,16;"E"
8223 PRINT AT 6,15;"S"
8225 SLOW
8490 RETURN
8500 REM SECTOR
8520 LET Q=B*C
8540 IF Q<10 THEN PRINT "ANTARES";
8560 IF Q>9 AND Q<20 THEN PRINT "RIGEL";
8580 IF Q>19 AND Q<30 THEN PRINT "PROCYON";
8600 IF Q>29 AND Q<40 THEN PRINT "VEGA";
8620 IF Q>39 AND Q<50 THEN PRINT "CANOPUS";
8640 IF Q>49 AND Q<60 THEN PRINT "ALTAIR";
8660 IF Q>59 AND Q<70 THEN PRINT "SAGITTARIUS";
8680 IF Q>69 AND Q<80 THEN PRINT "POLLUX";
8700 IF Q>79 AND Q<90 THEN PRINT "STRIUS";
8720 IF Q>89 THEN PRINT "BETELGEUSE";
8740 RETURN
8999 STOP
9000 DIM A(10,10)
9020 DIM B(10,10)
9060 FOR A=1 TO 20
9080 LET X=INT (RND*10+1)
9100 LET Y=INT (RND*10+1)
9120 LET A(X,Y)=1
9140 NEXT A
9160 LET B=5
9180 LET C=5
9200 LET A(B,C)=2
9220 LET B(B,C)=2
9240 LET AL=0
9260 LET E=RND
9280 IF E<.33 THEN LET Z$="BRARKONS "
9300 IF E>.33 AND E<.66 THEN LET Z$="WRERKTONIONS "
9320 IF E>.66 THEN LET Z$="POLLUXIANS "
9340 LET E=1000+2000*RND
9900 RETURN
9910 CLEAR
9920 SAVE "1031%6"
9930 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
