Falling Blocks

This file is part of and Timex Sinclair Public Domain Library Tape 1006. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000
Tags: Game

This is a ZX81/TS1000 falling-blocks arcade game where the player controls a horizontally moving cursor to catch descending items. The screen is set up with inverse-video rows forming a playing field, and the PEEK of system variables 16396/16397 is used to obtain the base address of the display file so that direct POKE operations can manipulate individual character cells. The ball/block (character code 151) falls column by column toward the bottom, and a collision with character 148 triggers a score increment. A countdown timer (variable B starting at 501) drives the game loop, ending with a score display and automatic restart via RUN.


Program Analysis

Program Structure

The program is organised into four logical phases:

  1. Initialisation (lines 1–7): Resets the score N, sets the countdown B=501, draws the playing field with inverse-video characters, and sets the paddle position P=8.
  2. Main game loop (lines 8–100): Decrements the timer, reads the keyboard, moves the falling block down through display memory, and loops back via GOTO 10.
  3. Catch handler (lines 110–140): Awards a point, and every 112 catches redraws the screen (GOTO 3); otherwise returns to the game loop.
  4. End screen (lines 200–220): Prints the score, pauses, clears, and restarts with RUN.

Display File Addressing

The display file base address is obtained at line 8 with:

LET V=PEEK 16396+256*PEEK 16397

System variables at addresses 16396–16397 hold the low and high bytes of the display file start (D_FILE). Adding offsets to V lets the program treat screen memory as a flat array, bypassing BASIC’s own PRINT AT mechanism for speed.

Movement and Collision

The paddle position P is updated each loop iteration at line 30:

LET P=P-1+(INKEY$="")*2-(P=15)+(P=0)

This single expression moves the paddle left when a key is held (subtracts 1 and adds back 2 only when no key is pressed), and clamps P within the range 0–15 using the boolean terms -(P=15) and +(P=0). On ZX81 BASIC, boolean expressions evaluate to 1 (true) or 0 (false), making this an efficient idiom for boundary clamping without IF statements.

The falling block is written at 120+V+P (line 40 — row 7, column P) and then the FOR loop at lines 50–90 steps backward through display memory in strides of 17 (the ZX81 screen width of 32 columns plus one newline byte = 33 bytes per row, but the stride here is 17, suggesting a narrower virtual playfield). At each cell the loop checks for character 148 (the paddle/catcher character) and, on a miss, writes then immediately clears character 151 (the block).

Key Variables

VariablePurpose
NPlayer score (caught blocks)
BCountdown timer, starts at 501
PHorizontal paddle position (0–15)
VDisplay file base address from D_FILE
ZLoop counter / current display memory address

Notable Techniques

  • Boolean arithmetic for clamping: The paddle movement expression exploits ZX81 boolean-as-integer to handle wrapping without branching.
  • Direct display POKE: Writing character codes directly into display memory is significantly faster than PRINT AT and is the standard ZX81 trick for animation.
  • Screen redraw trigger: IF INT(N/112)<>N/112 tests divisibility by 112 to trigger a full screen refresh, preventing inverse-video rows from being corrupted over time.
  • Auto-restart: RUN at line 215 reinitialises all variables and restarts without requiring user input.

Bugs and Anomalies

  • The FOR loop stride of -17 is unusual. The ZX81 display file uses 33 bytes per row (32 character positions plus a NEWLINE token at the end). A stride of 17 means the loop visits every other row in reverse, but also potentially lands on non-character bytes, which could produce unpredictable graphical artefacts.
  • Line 220 (CLEAR) is unreachable: execution flows RUN at line 215, which restarts the program before CLEAR can execute.
  • The falling block at line 40 is placed at byte offset 120+V+P relative to the display file, which corresponds to roughly row 3 column P (120 ÷ 33 ≈ 3.6). The loop then scans back toward V, meaning the “falling” direction is upward in memory terms — this is consistent with the ZX81 display layout where lower addresses appear higher on screen, so visually the block appears to fall downward.

Content

Appears On

Assembled by Tim Ward from many sources. Contains programs 10252 – 10293.

Related Products

Related Articles

Related Content

Image Gallery

Falling Blocks

Source Code

   1 LET N=0
   2 LET B=501
   3 FOR Z=0 TO 6
   4 PRINT AT Z,0;"%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%="
   5 NEXT Z
   6 PRINT "% % % % % % % % % % % % % % % % ","\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~\~~"
   7 LET P=8
   8 LET V=PEEK 16396+256*PEEK 16397
  10 LET B=B-1
  20 IF B=0 THEN GOTO 200
  30 LET P=P-1+(INKEY$="")*2-(P=15)+(P=0)
  40 POKE 120+V+P,151
  50 FOR Z=120+V+P TO V STEP -17
  70 IF PEEK Z=148 THEN GOTO 110
  80 POKE Z,151
  81 POKE Z,128
  90 NEXT Z
 100 GOTO 10
 110 POKE Z,120
 120 LET N=N+1
 130 IF INT (N/112)<>N/112 THEN GOTO 10
 140 GOTO 3
 200 PRINT "YOUR SCORE ";N
 205 PAUSE 50000
 210 CLS 
 215 RUN 
 220 CLEAR 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top