--- title: "Rabbit Raid" id: 70828 type: "computer_media" slug: "rabbit-raid" url: "http://localhost/computer_media/rabbit-raid/" markdown_url: "http://localhost/computer_media/rabbit-raid.md" published_at: "2026-08-23T15:08:06+00:00" modified_at: "2026-08-23T20:33:24+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/rabbit-raid.png" alt: "Rabbit Raid screen" excerpt: "Guide your rabbit through a randomizing maze while a relentlessly accelerating weasel closes in — collect carrots for big bonus points if you dare." 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 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Arcade" slug: "arcade" taxonomy: "genre" url: "http://localhost/type/arcade/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Rabbit%20Raid%20%28198x%29%28-%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2026/08/rabbit-raid.png" alt: "Rabbit Raid screen" media_type_tags: "Arcade" --- # Rabbit Raid Rabbit Raid is a maze-chase game in which the player steers a rabbit (UDG “B”) around a grid while a weasel (UDG “A”) pursues them and randomly placed hazards populate the playfield. The maze is stored as a 21×31 string array `m$`, allowing collision detection and cell content checks to be performed with simple string-subscript comparisons rather than separate coordinate arrays. Seven UDGs are defined via DATA statements read in a loop: the weasel, rabbit, a carrot (UDG “D”), a projectile/obstacle (UDG “E”), a dot collectible (UDG “F”), a solid obstacle (UDG “G”), and a wall marker (UDG “H”). The weasel’s pursuit speed is controlled by a variable `k` that starts at a player-chosen value and decreases by 0.001 each iteration, so the weasel continuously accelerates throughout play. Bonus points are awarded for collecting carrots (+100) and dot tiles (+10), and a hi-score is retained across games within the same session. *** ### Program Structure The program is organized into clearly separated functional blocks: 1. **Lines 1–20:** REM label for UDG names, UDG initialization subroutine call. 2. **Lines 20–80:** Game setup — border/paper, title, hi-score carry-forward, speed input, initial positions. 3. **Lines 100–190:** Main game loop (FOR `j` 29 to 1), driving the weasel’s horizontal sweep animation, player movement, scoring, and collision checks. 4. **Lines 200–299:** Player movement subroutine — reads INKEY$ and checks `m$` for wall collisions. 5. **Lines 300–399:** Maze mutation subroutine — randomly places wall (`\h`), hazard (`\g`), or carrot (`\d`) tiles. 6. **Lines 400–470:** Weasel AI subroutine — moves weasel one step toward the rabbit each call, with a probability gate controlling actual movement. 7. **Lines 7000–7020:** Death/game-over handler — descending beep fanfare, score display, hi-score update, restart. 8. **Lines 8500–8550:** Maze initialization — DIM, border rows, random wall scatter, screen draw. 9. **Lines 9000–9499:** UDG loading — reads seven UDGs from DATA in a nested FOR loop. ### UDG Definitions Seven User Defined Graphics are loaded at lines 9000–9070 using a compact nested loop: `FOR g=1 TO 7: READ a$: FOR n=0 TO 7: READ a: POKE USR a$+n,a: NEXT n: NEXT g`. The REM at line 1 documents the mapping: | UDG | Role | | --- | --- | | `\a` (A) | Weasel sprite | | `\b` (B) | Rabbit sprite | | `\d` (D) | Carrot (worth +100 points) | | `\e` (E) | Weasel projectile / moving hazard | | `\f` (F) | Dot collectible (worth +10 points, fills row 5) | | `\g` (G) | Hazard obstacle (kills rabbit on contact) | | `\h` (H) | Wall tile (blocks movement) | ### Maze Representation The playfield is stored in a string array `m$(21,31)` declared at line 8500. Each cell holds a single character representing its content (wall, collectible, hazard, or space). This allows collision detection and content checks to be performed with simple string-subscript comparisons such as `IF m$(x,y-1)<>"\h"`, avoiding any need for a parallel numeric array. The border walls are initialized as full rows and column entries; 100 additional wall cells are scattered randomly at line 8530, and row 5 is pre-filled with dot collectibles (`\f`) at line 8525. ### Weasel AI and Speed Acceleration The weasel’s pursuit logic in lines 400–470 uses a simple axis-aligned step toward the rabbit: it increments or decrements `v` (weasel row) and `w` (weasel column) one step each call. Movement is gated by `IF RND<(k/10) THEN RETURN`, so a high `k` value causes more frequent early returns (slower weasel). The player sets `k` at the start (1 = fast, 9 = slow), and line 145 applies `LET k=k-.001` every iteration of the main loop, continuously lowering the threshold and accelerating the weasel as the game progresses. At `k`=1, the weasel moves almost every frame from the outset. ### Main Loop Mechanics The outer main loop iterates `j` from 29 down to 1, simultaneously driving a weasel sprite across row 5 and calling movement, maze mutation, and weasel-AI subroutines on each step. This means a full “round” consists of 29 game ticks. Line 150 checks whether the rabbit occupies column `j` on row 5 (the weasel’s sweep row), triggering death if so. After the loop completes, line 190 reprints the leftmost dot tile and restarts the sweep from column 29. ### Maze Mutation Subroutine 300 is called every tick. It returns immediately 90% of the time (`IF RND<.9 THEN RETURN`). On the remaining 10%, it selects a random cell at rows 6–19, columns 2–28. With 50% probability it places a wall (`\h`); otherwise it places a hazard (`\g`). An additional 30% chance (of the hazard branch) upgrades the cell to a carrot (`\d`), drawn with a random INK color (`INK RND*3`). This means the maze layout changes constantly during play, adding chaos and difficulty. ### Scoring - +1 point per main loop iteration (line 125, score incremented and printed). - +10 points for stepping onto a dot tile (`\f`), line 235. - +100 points for collecting a carrot (`\d`), which also clears the cell and plays a two-note beep (line 250). - Stepping onto a hazard (`\g`) or being caught by the weasel triggers the game-over handler at line 7000. ### Notable Techniques and Idioms - **String array as map:** Using `m$(row,col)` character comparisons for both collision detection and game-object identity is an efficient use of the string-array feature. - **PAPER 8 transparency:**`PAPER 8` is used extensively for printing sprites and restoring cells without affecting the background color. - **Speed input validation:** Line 40 uses `IF NOT k OR k>9 THEN INPUT "...": GO TO 40` — the INPUT with a blank string clears the editor line, and the loop rejects out-of-range values. - **Hi-score persistence:** Variable `h` is initialized once at line 20 and updated at line 7000, surviving game restarts via `GO TO 30` which skips the initialization. ### Bugs and Anomalies - **Line 70 PAPER syntax:**`PRINT AT n,0; PAPER 5,,:` — the double comma after `PAPER 5` is irregular syntax; on some interpreters this may cause an error or be silently ignored. It appears intended to set the paper color for a blank fill across the status rows. - **m$ boundary risk:** Player movement at lines 200–230 checks the destination cell in `m$` before moving, but if the player is at the edge of the array (e.g., row 1 or column 1), subtracting 1 from the subscript could cause an index error, as `m$` rows 1–4 and column 0 are not all fully defined as walls. - **Line 8505 string length:**`m$(21)` is assigned a 32-character string of `\h` characters, but `m$` is dimensioned as `DIM m$(21,31)` — 31 characters wide. The assignment of 32 characters to a 31-character row will be truncated or cause an error depending on interpreter behavior. - **Weasel collision at line 460:** The weasel AI checks for catch at line 460 after moving, but also at line 135 in the main loop, so the catch check is effectively duplicated. ## Source Code ``` 1 REM \a=a \b=b \d=d \e=e \f=f \g=g \h=h 10 GO SUB 9000: REM GRAPHICS 20 LET h=0: BORDER 0: PAPER 4: CLS 30 CLS : PRINT AT 0,8;"\dRABBIT RAID\d": GO SUB 8500: REM initiaze 40 LET s=0: PRINT #0;"weasel speed (1=fast-9=slow)": PAUSE 0: LET k=CODE INKEY$-48: IF NOT k OR k>9 THEN INPUT " ": GO TO 40 50 INPUT " " 60 LET v=5: LET w=5 70 FOR n=1 TO 5: PRINT AT n,0; PAPER 5,,: NEXT n 75 PRINT AT 2,15; PAPER 8;"HI ";h 80 LET x=20: LET y=29 100 FOR j=29 TO 1 STEP -1: PRINT AT 5,j; PAPER 5; INK 4;" \f";AT 5,j; INK 0;"\e" 110 GO SUB 200: REM move rabbit 120 PRINT AT x,y; PAPER 8; INK 7;"\b" 125 LET s=s+1: PRINT PAPER 5;AT 2,0;"1UP ";s 130 BEEP .0005,60 135 IF x=v AND y=w THEN GO TO 7000 140 GO SUB 300: REM alter maze 145 LET k=k-.001 150 IF x=5 AND y=j THEN GO TO 7000 160 GO SUB 400: PRINT AT v,w; PAPER 8; INK 6;"\a" 170 PRINT AT x,y; PAPER 8;" " 180 NEXT j 190 PRINT AT 5,1; PAPER 5; INK 4;"\f": GO TO 100 200 IF INKEY$="5" AND m$(x,y-1)<>"\h" THEN LET y=y-1 210 IF INKEY$="8" AND m$(x,y+1)<>"\h" THEN LET y=y+1 220 IF INKEY$="7" AND m$(x-1,y)<>"\h" THEN LET x=x-1 230 IF INKEY$="6" AND m$(x+1,y)<>"\h" THEN LET x=x+1 235 IF m$(x,y)="\f" THEN LET s=s+10 240 IF m$(x,y)="\g" THEN GO TO 7000 250 IF m$(x,y)="\d" THEN LET s=s+100: LET m$(x,y)=" ": BEEP 0.5,0: BEEP 0.0125,30 299 RETURN 300 IF RND<.9 THEN RETURN 305 LET a=INT (RND*14)+6: LET b=INT (RND*27)+2 307 IF RND<.5 THEN GO TO 320 310 LET m$(a,b)="\h": PRINT AT a,b;"\h" 315 RETURN 320 LET m$(a,b)="\g": PRINT AT a,b;"\g" 325 IF RND<.7 THEN RETURN 330 LET m$(a,b)="\d": PRINT AT a,b; INK RND*3;"\d" 399 RETURN 400 PRINT PAPER 8;AT v,w;m$(v,w) 410 IF RND<(k/10) THEN RETURN 420 IF xv THEN LET v=v+1 440 IF y>w THEN LET w=w+1 450 IF yh THEN PRINT "A NEW HI'SCORE": LET h=s 7010 PRINT "PRESS ANY KEY FOR ANOTHER GAME": PAUSE 0 7015 CLS 7020 GO TO 30 8500 DIM m$(21,31) 8505 LET m$(21)="\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h" 8510 FOR n=5 TO 21: LET m$(n,1)="\h": LET m$(n,31)="\h": NEXT n 8520 LET m$(4)="\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h" 8525 LET m$(5)="\h\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\f\h" 8530 FOR n=1 TO 100: LET m$(INT (RND*14)+6,INT (RND*30)+1)="\h": NEXT n 8540 FOR n=6 TO 21: PRINT AT n,0;" ";m$(n): NEXT n 8550 RETURN 9000 FOR g=1 TO 7: READ a$: FOR n=0 TO 7: READ a: POKE USR a$+n,a: NEXT n: NEXT g 9010 DATA "A",0,BIN 01000010,BIN 01100110,BIN 01111110,BIN 01011010,BIN 01111110,BIN 01000010,BIN 01111110 9020 DATA "B",0,BIN 00100100,BIN 00100100,BIN 00111100,BIN 11011011,BIN 01111110,BIN 11000011,BIN 00111100 9030 DATA "D",BIN 00100100,BIN 00100100,BIN 00111100,BIN 01011010,BIN 00111100,BIN 01111110,BIN 01111110,BIN 00111100 9040 DATA "E",BIN 00001000,BIN 00000100,BIN 00001010,BIN 00010001,BIN 01110000,BIN 11110000,BIN 11110000,BIN 01100000 9050 DATA "F",0,0,0,0,BIN 00011000,BIN 00111100,BIN 00111100,BIN 00011000 9060 DATA "G",BIN 00111100,BIN 01111110,255,255,255,255,BIN 01111110,BIN 00111100 9070 DATA "H",0,0,BIN 00011000,BIN 00111100,BIN 00111100,BIN 00011000,0,0 9499 RETURN ```