This program implements a carnival shooting-gallery style game called “CHAIN-SAW” for the ZX81/TS1000. Three rows of a scrolling marquee — built from inverse-video characters — move across the screen in opposite directions, simulating a moving target belt; the top and bottom rows scroll left-to-right and right-to-left respectively. The player presses any key to fire a “bullet” (an asterisk) that travels upward from row 21, and the program checks whether it strikes a target on row 12 (the lower belt, string C$) or row 10 (the upper belt, string A$), awarding points equal to the character code of the hit symbol minus 156. The game ends after 10 shots, displaying total shots and score before restarting via RUN.
Program Analysis
Program Structure
The program is organized into a main animation loop and two subroutines:
- Initialization (lines 5–6): Score
Sand shotsJare set to zero. - String setup (lines 10–30): Three 32-character display strings
A$,B$, andC$are defined. - Main loop (lines 40–80): Prints the three-row display, scrolls
A$andC$in opposite directions, then calls the input/bullet subroutine before repeating. - Input and bullet subroutine (lines 100–220): Checks for a keypress; if pressed, animates a bullet travelling upward from row 21 to row 0, calling hit-detection subroutines at rows 12 and 10.
- Hit detection — lower belt (lines 300–340): Increments shot count, scores if target at position 11 of
C$is not already blank, then blanks it. - Hit detection — upper belt (lines 400–430): Scores and blanks if target at position 11 of
A$is not already blank, then advances the scroll. - Game over (lines 500–550): Displays result, waits for ENTER, and restarts via
RUN.
Display Strings and Scrolling
A$ (line 10) and C$ (line 30) are 32-character strings. Each character pair consists of a block graphic followed by an inverse-video digit or letter (0–9, A–F), making 16 pairs that fill the 32-column display exactly. B$ (line 20) is a static 32-character string spelling “CHAIN-SAW” in inverse video, centred with inverse spaces.
Scrolling is achieved by simple string slicing each frame:
A$scrolls left:A$(2 TO 32)+A$(1)— drops the first character and appends it to the end.C$scrolls right:C$(32)+C$( TO 31)— moves the last character to the front.
Because the marquee characters are two-character pairs (graphic + label), scrolling by one character per frame causes the pairs to break up midway through a cycle, giving an asymmetric visual shimmer rather than a clean per-symbol scroll.
Bullet Animation
When a key is detected (line 110–120), the bullet loop (lines 140–190) runs from row 20 down to row 0 in STEP -1, printing an asterisk * at the current row and erasing the previous position one row below. The horizontal position I starts at 1 and increments each step, so the bullet travels diagonally upward-right rather than straight up. Hit-detection subroutines are called when N=12 and N=10, corresponding to the rows occupied by C$ and A$ respectively.
Scoring Mechanism
Scoring exploits the character codes of the block graphics used in the target strings. The formula CODE C$(11)-156 (line 320) and CODE A$(11)-156 (line 410) extract a numeric value from whichever symbol the bullet strikes at column position 11. The block graphic ▀ (ZX81 char 156) used in C$ and the block graphic ▖ (ZX81 char 154) used in A$ both yield small non-negative differences from 156, effectively giving a score of 0 or −2 respectively for a blank hit — though the blank-check guard (lines 310, 400) prevents scoring a previously-hit cell. Targets that have already been hit are replaced with the respective “blank” graphic.
Notable Techniques and Idioms
- Inverse video in strings: The
%Xescape encodes inverse-video characters directly in string literals, used extensively for the title bar and score display. - Block graphics as target markers:
\..(▖) marks an active upper-belt target;\'\'(▀) marks an active lower-belt target; hitting changes the cell to the same graphic, effectively making it look identical but registering as spent — a subtle visual bug. - FAST/SLOW around restart: Lines 520–540 bracket
CLSwithFAST/SLOWto clear the screen quickly without display flicker.
Bugs and Anomalies
| Location | Issue |
|---|---|
| Lines 310 / 400 | The “already hit” check compares C$(11) to \'\' (▀) and A$(11) to \..
(▖), but these are the same graphics used to represent active targets, so an un-hit cell and a previously-hit cell are visually and logically identical. Scoring is blocked by the guard but the player receives no visual feedback that a target was already spent. |
| Line 150 | The erase step prints a space at AT N+1,I-1 using the previous row and column. When N=20 (first iteration), this prints at row 21, column 0 — overwriting the inverse-asterisk prompt printed at line 100. |
| Line 430 | The upper belt A$ is scrolled an extra step inside the hit-detection subroutine (line 430), meaning a hit causes the belt to advance one extra character that frame, creating a slight lurch in the animation. |
| Lines 310–320 vs 400–410 | Shot counter J is only incremented in the lower-belt subroutine (line 300/310), not in the upper-belt subroutine (line 400). Hitting the upper belt does not consume a shot, potentially allowing more than 10 scoring events. |
Content
Source Code
5 LET S=0
6 LET J=0
10 LET A$="\..%0\..%1\..%2\..%3\..%4\..%5\..%6\..%7\..%8\..%9\..%A\..%B\..%C\..%D\..%E\..%F"
20 LET B$="% % % % % % % % % % % %C%H%A%I%N%-%S%A%W% % % % % % % % % % % % "
30 LET C$="\''%0\''%1\''%2\''%3\''%4\''%5\''%6\''%7\''%8\''%9\''%A\''%B\''%C\''%D\''%E\''%F"
40 PRINT AT 10,0;A$;AT 11,0;B$;AT 12,0;C$
50 LET A$=A$(2 TO 32)+A$(1)
60 LET C$=C$(32)+C$( TO 31)
70 GOSUB 100
80 GOTO 40
100 PRINT AT 21,0;"%*"
110 LET D$=INKEY$
120 IF D$="" THEN RETURN
130 LET I=1
140 FOR N=20 TO 0 STEP -1
150 PRINT AT N,I;"*";AT N+1,I-1;" "
160 IF N=12 THEN GOSUB 300
170 IF N=10 THEN GOSUB 400
180 LET I=I+1
190 NEXT N
200 PRINT AT 0,0;"%S%H%O%T%S% %= ";J;AT 0,12;" %S%C%O%R%E% %= ";S
210 IF J=10 THEN GOTO 500
220 GOTO 40
300 LET J=J+1
310 IF C$(11)="\''" THEN GOTO 480
320 LET S=S+CODE C$(11)-156
330 LET C$(11)="\''"
340 RETURN
400 IF A$(11)="\.." THEN RETURN
410 LET S=S+CODE A$(11)-156
420 LET A$(11)="\.."
430 LET A$=A$(2 TO 32)+A$(1)
480 RETURN
500 PRINT AT 6,0;"GAME OVER - PRESS ENTER","TO RESTART :::"
510 INPUT A$
520 FAST
530 CLS
540 SLOW
550 RUN
\n9998 SAVE "CHAINSA%W"
\n9999 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

