--- title: "Space Shuttle" id: 57161 type: "computer_media" slug: "space-shuttle" url: "http://localhost/computer_media/space-shuttle/" markdown_url: "http://localhost/computer_media/space-shuttle.md" published_at: "2024-10-04T01:05:07+00:00" modified_at: "2026-03-30T21:19:19+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/110_Shut.png" excerpt: "A keyboard-controlled shuttle weaves through a procedurally generated obstacle course — all driven by direct display-file manipulation instead of PRINT statements." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 56733 title: "Timex Sinclair Public Domain Library Tape 1002" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1002/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/110_Shut.png" media_type_tags: "Game" --- # Space Shuttle This program implements a simple Space Shuttle navigation game on the ZX81/TS1000, using direct POKE operations to manipulate the display file rather than PRINT statements for sprite movement. The opening loop (lines 10–50) draws a bordered playfield with inverse-video space characters forming top and bottom walls and a right-side wall using fractional AT row addressing. Lines 60–80 calculate the display file base address via PEEK 16397/16396 (D_FILE system variable) and place the shuttle character (char 23, an inverse-video block) at a starting position offset 392 bytes in. The movement routine (lines 90–180) reads the keyboard using CODE INKEY$, maps arrow-key codes 33–36 to a signed displacement D using a compact Boolean arithmetic expression, then checks whether the destination cell contains a character above code 127 (a wall or obstacle) and STOPs on collision. Line 160 randomly POKEs an inverse-space (char 128) ahead of the shuttle to create moving hazards, adding a procedural obstacle element to the game. *** ## Program Analysis ### Program Structure The program divides into three clear phases: 1. **Playfield setup (lines 10–50):** A `FOR` loop draws inverse-space borders along the top row, bottom row (row 13), and right column using `PRINT AT`. 2. **Initialisation (lines 60–80):** The display file address is computed, and the shuttle sprite and a wall marker are POKEd into the display file directly. 3. **Game loop (lines 90–180):** Keyboard input is polled, a displacement is calculated, collision is checked, the shuttle is moved, and a random obstacle may be placed. ### Display File Addressing Line 60 reads the ZX81 system variable `D_FILE` at addresses 16396–16397 to find where the display file begins in RAM: `LET P=35+256*PEEK 16397+PEEK 16396` The offset 35 skips past the initial HALT byte and the first line’s newline structure, landing the pointer somewhere inside the visible display area. Line 70 then POKEs offset +392 with value 184 (an inverse character used as a wall marker), and line 80 POKEs offset +1 with 23 (the shuttle sprite character). ### Movement and Input Handling Lines 90–100 poll `INKEY$` via `CODE INKEY$` into variable `C`, looping until a value in the range 33–36 is detected. These correspond to the ZX81 cursor keys (5/6/7/8 shifted). The displacement `D` is computed on a single line using Boolean arithmetic: `LET D=(33 AND C=34)-(1 AND C=33)-(33 AND C=35)+(1 AND C=36)` | Key code (C) | Direction | D value | | --- | --- | --- | | 33 | Left (←) | −1 | | 34 | Right (→) | +33 | | 35 | Up (↑) | −33 | | 36 | Down (↓) | +1 | The values ±33 reflect the ZX81 display file row stride (32 character cells plus one newline byte = 33 bytes per row), making vertical movement jump by exactly one display row. ### Collision Detection Line 140 checks the destination cell before moving the shuttle: `IF PEEK P>127 THEN STOP` Any character with code above 127 is an inverse-video character — used here for walls (the border drawn in setup) and randomly placed obstacles (line 160). A collision immediately halts execution via `STOP`. ### Procedural Obstacle Generation Line 160 uses `RND` with a 50% probability to place an inverse-space (code 128) one step ahead of the shuttle in the direction of travel: `IF RND>0.5 THEN POKE P+D,128` This creates a trail of obstacles in the shuttle’s wake/path, increasing difficulty over time without requiring a separate data structure. ### Key BASIC Idioms - **Boolean arithmetic for multi-way branching:** The single-line displacement calculation at line 110 avoids four separate `IF` statements by exploiting the fact that ZX81 BASIC evaluates boolean expressions as 1 (true) or 0 (false). - **Fractional AT row:** Line 40 uses `AT I/2.5,31`, so as `I` runs 1–31, the row ranges from 0.4 to 12.4. The ZX81 truncates fractional row values, effectively spacing wall segments down the right side. - **Debounce loop:** Line 170 waits for the key to be fully released before accepting the next input, preventing key repeat from causing unintended multi-cell moves. ### Potential Anomalies - The starting offset of 35 into the display file is hardcoded and may not reliably place the shuttle in a consistent on-screen cell across different memory configurations or after editing the program (which shifts `D_FILE`). Line 9 (`RAND`) does not affect this. - `RAND` on line 9 reseeds the random number generator — since it is called without an argument it uses a system-clock-derived seed, introducing slight randomness variation at startup but having no direct effect on the display initialisation. - Lines 190–200 (`SAVE` and `RUN`) are utility lines appended to the program listing and are not part of the game execution path. ## Source Code ``` 1 REM SPACE SHUTTLE 9 RAND 10 FOR I=1 TO 31 20 PRINT AT 0,I;"% " 30 PRINT AT 13,I;"% " 40 PRINT AT I/2.5,31;"% % " 50 NEXT I 60 LET P=35+256*PEEK 16397+PEEK 16396 70 POKE P+392,184 80 POKE P+1,23 90 LET C=CODE INKEY$ 100 IF C<33 OR C>36 THEN GOTO 90 110 LET D=(33 AND C=34)-(1 AND C=33)-(33 AND C=35)+(1 AND C=36) 120 POKE P,0 130 LET P=P+D 140 IF PEEK P>127 THEN STOP 150 POKE P,23 160 IF RND>0.5 THEN POKE P+D,128 170 IF INKEY$<>"" THEN GOTO 170 180 GOTO 90 190 SAVE "1011%0" 200 RUN ```