This program implements a Breakout-style game called “Demolition” in which a ball is dropped from a horizontally-moving cursor to destroy blocks arranged in coloured rows on screen. The game uses SCREEN$ to detect block collisions and implements a splash-damage mechanic in subroutine at line 700, clearing surrounding cells in a radius of up to five characters from the impact point. A UDG character (“g”) is defined at line 8000 as a solid rectangular block (six full-width scan lines between two blank rows) and used to draw the brick wall. Score digits are rendered into the display file directly by copying font data from the system character set via the ROM font address in system variable 23606/23607, writing pixel rows to a fixed screen address at line 4050. The ball speed is controlled by PAUSE p and a BEEP call each step, and the game tracks both current score and a persistent high score across rounds.
Program Analysis
Program Structure
The program is organised into several functional regions, entered non-linearly via GO TO chains:
- Lines 10–95: Title screen, instructions, and initialisation.
- Lines 100–398: Main game loop — ball movement left/right and drop trigger.
- Lines 500–780: Ball drop, collision detection, and splash-damage scoring.
- Lines 1000–1110: Wall rebuild trigger; manages level count and speed.
- Lines 2100–2190: Wall drawing using UDG “g” in five coloured rows.
- Lines 3000–3030: Game-over screen; prompts replay.
- Lines 4000–4100: Score rendering subroutine (direct display-file font copy).
- Lines 8000–8100: UDG definition and system-variable initialisation.
Initialisation and UDG Definition
Execution begins at line 190 with GO TO 8000. Lines 8000–8060 define UDG “g” as a block character: scan lines 0 and 7 are set to BIN 00000000 (blank) and lines 1–6 to BIN 01111110 (six pixels wide), producing a rectangular brick tile. Line 8080 reads the ROM font base address from system variables 23606/23607 into u, and line 8090 calculates a fixed display-file address v at screen row 0, column 6 (pixel address 16384 + 16*256 + 32*6 = 16576 + 192 = wait — 16384 + 256*16 + 32*6 = 16384 + 4096 + 192 = 20672), used as the score display area.
Ball Movement
The paddle/launcher is simulated by a * character sliding across row 1. Direction is chosen randomly at line 240 via INT(RND*2). In the rightward pass (lines 300–348), the cursor advances using CHR$ 8 (backspace) to erase and redraw the asterisk one column at a time. The leftward pass (lines 350–398) uses two consecutive CHR$ 8 characters to step back two positions (erase then move left). Each step calls BEEP .01,16 and PAUSE p; p starts at 1 and the speed mechanic is managed through k at line 1100.
Pressing key 6 at any step (checked via INKEY$ at lines 312, 332, 362, 382) triggers the drop routine at line 500.
Drop and Collision Detection
Line 510 computes the ball’s column using PEEK 23688, the system variable holding the current print column, subtracting 1: LET x=33-PEEK 23688-1. The ball then falls from row 2 to row 20, checking SCREEN$(i,x) at each step. A non-space character signals a brick hit; the ball stops and scoring begins.
Splash-Damage Mechanic
Lines 700–780 implement an expanding-radius explosion. After a direct hit, the loop at lines 720–780 iterates j from 1 to 5, checking cells diagonally above-left and above-right of impact. Variables sm, tm, sp, tp are Boolean flags (0 or 1 in Spectrum BASIC) indicating whether those cells are blank (already cleared). Their sum w counts remaining bricks in the splash zone; if w=0 the loop exits early. Each cleared brick awards 10 points (s=s+w*10).
This is a notable algorithmic feature — most BASIC Breakout clones do not implement area-effect scoring.
Score Rendering (Subroutine at Line 4000)
Rather than using PRINT AT for the score, the subroutine at line 4000 manually copies font bitmap data into the display file. For each digit character in STR$ s, it reads 8 scan-line bytes from the ROM font (base address u, offset f*8 per character) and POKEs them directly into display file addresses at row 2 (address v + j - 1 + 256*i). This bypasses the BASIC print system entirely and renders the score at pixel level, allowing placement in any screen area without attribute interference.
Wall Drawing
Lines 2100–2180 draw 16 blank rows followed by 5 rows of UDG “g” characters, each in a different INK colour (0–4, derived from i-16). The wall string a$ is 32 copies of \g (UDG “g”), filling the full screen width. After drawing, execution falls through to GO TO 200 to start the game loop.
Level Progression
Variable k counts how many times all bricks in row 1 have been cleared (detected at lines 210–213 by scanning SCREEN$(1,i) for a space). When c=k the wall is redrawn. k starts at 8 and decreases by 1 each cycle at line 1100, floored at 3, implying the game gets harder (fewer redraws before a new wall). Variable a counts redraws and changes the wall colour at a=5; at a=10 it resets.
Key Variables
| Variable | Purpose |
|---|---|
s | Current score |
z | High score (persists across rounds) |
c | Clear counter (triggers wall rebuild at c=k) |
k | Clears required per level; decreases each cycle |
a | Wall colour cycle counter |
p | PAUSE duration (ball speed control) |
u | ROM font base address |
v | Display file address for score rendering |
x | Ball column on drop, from PEEK 23688 |
Bugs and Anomalies
- Variables
a$andb$are defined inside the wall-drawing block (lines 2100–2110) but are also referenced at lines 1010–1022, which execute before line 2100 in subsequent cycles — on the first pass this is safe because line 8100 routes to 2100 first, butb$anda$would be undefined if the code path ever reached line 1000 before 2100. In practice the flow is always 8100→2100→200→…→1000→200→…→2100, so it works. - Line 510 uses
PEEK 23688to find the current print column. System variable 23688 (SCRCT) is the scroll counter, not the print column. The actual print column is at system variable23688— on the Spectrum,23688is indeed not a standard column register. The correct variables are 23688 (SCRCT) vs 23689 (ATTR_P). The intended variable for column is 23689 or the23688family; this may work incidentally due to side effects of the PRINT statements setting internal state, but is architecturally questionable. - Line 552 prints a blank at row 20 after the loop exhausts without a hit, cleaning up the ball — correct behaviour.
- The
POKE 23692,255calls at lines 1010 and 1022 reset the scroll counter to suppress the “scroll?” prompt, a standard Spectrum idiom.
Content
Source Code
10 REM "breakout" game
20 CLS
40 RANDOMIZE
45 LET z=0: LET q$="Hi Score: "
50 BORDER 6
60 PRINT AT 6,6; INK 7; PAPER 1;" D E M O L I T I O N "
70 REM
80 PRINT AT 16,6;"Press ENTER to Start"
85 PRINT AT 21,4;"Use '6' key to Drop Ball"
90 INPUT LINE l$
95 CLS
100 LET c=0: LET k=8: LET a=0: LET s=0: LET p=1
190 GO TO 8000
200 REM
202 GO SUB 4000
210 FOR i=0 TO 31
211 IF SCREEN$ (1,i)="" THEN GO TO 3000
213 NEXT i
220 LET c=c+1: IF c=k THEN GO TO 1000
240 LET vv=INT (RND*2)
245 PRINT AT 0,0;q$;z
250 IF vv=0 THEN GO TO 300
260 GO TO 350
300 REM go right
310 PRINT AT 1,0;"*";
312 IF INKEY$="6" THEN GO TO 500
320 FOR i=1 TO 31
322 BEEP .01,16: PAUSE p
330 PRINT CHR$ 8;" ";" ";CHR$ 8;"*";
332 IF INKEY$="6" THEN GO TO 500
340 NEXT i
342 PRINT CHR$ 8;" ";
348 GO TO 200
350 REM go left
360 PRINT AT 1,31;"*";
362 IF INKEY$="6" THEN GO TO 500
370 FOR i=0 TO 30
372 BEEP .01,16: PAUSE p
380 PRINT CHR$ 8;" ";CHR$ 8;CHR$ 8;"*";
382 IF INKEY$="6" THEN GO TO 500
390 NEXT i
392 PRINT CHR$ 8;" ";
398 GO TO 200
500 REM drop
510 LET x=33-PEEK 23688-1
520 FOR i=2 TO 20
530 PRINT AT i-1,x;" ";
540 IF SCREEN$ (i,x)="" THEN GO TO 700
542 PRINT AT i,x;"*": BEEP .01,8
550 NEXT i
552 PRINT AT 20,x;" ";
560 GO TO 200
700 REM
710 PRINT AT i,x;" ": LET s=s+10: BEEP .02,16
711 IF s>z THEN LET z=s
712 LET i=i+1: IF i>21 THEN GO TO 720
714 IF SCREEN$ (i,x)="" THEN LET s=s+10
716 PRINT AT i,x;" ";
720 FOR j=1 TO 5
722 LET xm=x-j: IF xm<0 THEN LET xm=0
724 LET xp=x+j: IF xp>31 THEN LET xp=31
726 LET sm=(SCREEN$ (i-j,xm)="")
727 LET tm=(SCREEN$ (i-j-1,xm)="")
728 LET sp=(SCREEN$ (i-j,xp)="")
729 LET tp=(SCREEN$ (i-j-1,xp)="")
730 LET w=sm+sp+tm+tp
740 IF w=0 THEN GO TO 200
760 PRINT AT i-j,xm;" ";: PRINT AT i-j,xp;" ";
770 PRINT AT i-j-1,xm;" ";: PRINT AT i-j-1,xp;" ";
772 LET s=s+w*10: BEEP .05,4
775 IF s>z THEN LET z=s
780 NEXT j
1000 LET c=0: LET a=a+1: IF a>5 THEN GO TO 1020
1010 POKE 23692,255: PRINT AT 21,31;b$: PRINT AT 20,0;b$: GO TO 1100
1020 LET q=INT (RND*7)
1022 POKE 23692,255: PRINT AT 21,31;b$: PRINT INK q;AT 20,0;a$: IF a=10 THEN LET a=0
1100 LET k=k-1: IF k=2 THEN LET k=3
1110 GO TO 200
2100 LET a$="\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g\g"
2110 LET b$=" "
2112 LET z$=" Press ENTER to Play Again! "
2120 FOR i=0 TO 15
2130 PRINT b$
2140 NEXT i
2150 FOR i=16 TO 20
2160 PRINT INK (i-16);a$
2170 NEXT i
2180 PRINT b$
2190 GO TO 200
3000 REM stop
3010 PRINT AT 21,0;z$
3024 PRINT AT 0,0;q$;s
3030 GO TO 90
4000 REM score
4020 LET s$=STR$ s: LET l=LEN s$
4030 FOR j=1 TO l
4040 LET f=CODE s$(j)
4050 FOR i=0 TO 7: LET e=PEEK (u+f*8+i): POKE (v+j-1+256*i),e: NEXT i
4060 NEXT j
4100 RETURN
8000 LET g0=BIN 00000000
8010 LET g1=BIN 01111110
8020 POKE USR "g"+0,g0
8030 FOR i=1 TO 6
8040 POKE USR "g"+i,g1
8050 NEXT i
8060 POKE USR "g"+7,g0
8080 LET u=PEEK (23607)*256+PEEK (23606)
8090 LET v=16*256+32*6+16384
8100 GO TO 2100
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

