This program implements a carnival-style weight-guessing game where the player enters their weight and a “guesser” character attempts to predict it. Custom UDGs (User Defined Graphics) are defined via DATA statements and POKEd into memory at USR “\a” through USR “\e”, creating the character sprites and display elements. The game draws a scale using block graphics and PLOT/DRAW commands, animates a weight indicator moving up or down, and compares the player’s input against a randomly generated target range. Lines 9900–9952 contain an elaborate self-listing routine that reads the program’s own tokenized BASIC from memory, decodes keyword tokens, and renders each statement graphically using DRAW commands to approximate letter shapes, with arc-based curves for rounded characters like O, C, and S.
Program Analysis
Program Structure
The program divides cleanly into two independent sections. Lines 10–370 implement the weight-guessing game itself. Lines 9900–9952 form a standalone self-listing and pseudo-pretty-printer routine that is never called by the game — it must be invoked separately (e.g., by RUNning from line 9900 or via the SAVE line’s LINE 0 autostart).
UDG Initialization
Lines 20–70 define five custom UDGs (\a through \e, characters 144–148) using 40 bytes of DATA. Each UDG is 8 bytes tall. The DATA at line 30 uses the variable a as a placeholder (value 0 after being consumed by READ) — this is a subtle trick where a appears in the DATA list itself, producing whatever value a currently holds at read time, which is 0 after the first READ iteration resets it. The POKE loop at line 70 writes sequentially to USR "\a" through USR "\a"+39, filling five UDGs.
Game Logic
The game flow is as follows:
- Draw a decorative border using block graphics (lines 80–110).
- Initialize player position (
x=21,y=8) and draw a scale with PLOT/DRAW (line 120). - Place the player sprite (
\a) at the starting position (line 130). - Pick a random target row
hin the range 8–18 and display a marker (\b) (lines 140–150). - Prompt for and validate weight input
w, 1–14 (lines 160–170). - Animate a weight dropping (line 180) and redraw the scale line (line 190).
- Move the sprite upward by
wrows (lines 200–230) then shift left two columns (line 240). - Compare final position against target
h: exact match triggers a win (lines 280–310); landing above the target causes a fall animation (lines 320–350); landing below shows a failure sprite (\e) with a low BEEP (line 270).
Graphics Techniques
The playing field border is drawn entirely with block graphic characters printed via PRINT AT, using INK 6 (yellow) for the frame and INK 4 (green) for interior details. The weighing scale is rendered with PLOT 64,0: DRAW 37,16 and later erased and redrawn with DRAW OVER 1 to show the scale tipping. Sprite animation uses character-cell movement: the old position is blanked with a space and the new position is printed with the UDG character.
Self-Listing Routine (Lines 9900–9952)
This is the most technically ambitious section of the program. It walks the tokenized BASIC program area in memory, decoding each line and rendering keyword tokens as pixel-drawn letterforms using DRAW commands.
PEEK 23635 + 256*PEEK 23636(line 9901) reads system variable PROG to find the start of the BASIC area.- Line 9903 reads the two-byte line number and advances the pointer past the line-length word (4 bytes total header).
- Lines 9906–9911 dispatch on the token byte
bto select a drawing subroutine for that keyword’s shape. Token values in the 226–254 range correspond to BASIC keywords. - Line 9911 draws a generic rectangular letter outline using a sequence of DRAW commands (baseline rectangle with a gap), representing the keyword.
- Line 9923 draws rounded-end forms (for tokens like
ON ERR,PRINT, etc.) using arc DRAW calls with-PIangle parameter for semicircles. - Line 9924 draws plain rectangular outlines for another token class.
- Lines 9925–9932 handle tokens for
SOUND(b=250) andSTICK(b=243) with a distinctive stepped shape. - Lines 9933–9938 handle
CIRCLEand related tokens, drawing an actual circle withCIRCLE x,y-4,4. - Lines 9916–9920 scan forward through the token stream byte by byte; byte 34 (
") triggers a subroutine to skip string literals (lines 9951–9952), byte 14 skips the 5-byte floating-point number format (LET a=a+4), byte 13 is a newline (end of statement), and byte 58 (:) marks a statement separator handled at line 9939. - Line 9942 displays a prompt using INVERSE 1, and lines 9943–9945 poll INKEY$ for “v” (view) or “p” (print via COPY).
Notable Idioms and Techniques
VAL "number"is not used here; GO TO targets are plain literals.- The
DRAW OVER 1at line 190 erases the previous scale line by XOR-drawing over it, a standard technique for flicker-free animation. - The self-lister limits output to 20 items (
c=20checks at lines 9921 and 9939) to avoid scrolling off-screen. - The SAVE line at 9953 uses
LINE 0, targeting non-existent line 0, which is a recognized technique to influence program startup behavior. - The DATA values in line 30 use the variable
aliterally inside a DATA statement — this is unusual and works because the variableaholds 0 after the first READ, making those entries effectively 0.
Potential Bugs and Anomalies
- Line 30’s use of
ain DATA is unconventional. In standard Spectrum BASIC, DATA elements are stored as literals at program entry time, not evaluated dynamically, soahere is the numeric variable’s current value when READ is executed — this works only becauseais reliably 0 at that point, but it is fragile. - The self-lister at line 9946 resets
c=0,x=130,y=175for a fresh render pass, butacontinues from wherever the previous pass left off, meaning the “view” mode may not restart from the beginning of the program. - Line 9950 issues
COPYfor printer output but does not reset the display mode, so the printed output depends on what is currently on screen.
Token Dispatch Table
| Token byte(s) | Description | Drawing routine |
|---|---|---|
| 226, 234, 242, 254 | Rounded-end keyword group | Line 9923 (arc DRAW) |
| 228–230, 232, 235, 241, 247, 249, 253 | Rectangular keyword group | Line 9924 (box DRAW) |
| 243, 250 | STICK / SOUND | Line 9925 (stepped shape) |
| 236, 237 | CIRCLE-related | Line 9933 (CIRCLE + line) |
| all others | Generic keywords | Line 9911 (default outline) |
Content
Source Code
10 PAPER 0: INK 7: BORDER 0: CLS
20 DATA 56,56,146,254,16,124,68,198
30 DATA 0,255,171,a,a,a,255,a
40 DATA 0,a,28,20,62,a,127,a
50 DATA 0,a,a,a,24,126,255,a
60 DATA 192,224,a,240,a,224,a,192
70 FOR f=0 TO 39: READ a: POKE USR "\a"+f,a: NEXT f
80 PRINT AT 4,0; INK 6;"\:: \:: \:: \::"'"\::\::\::\::\::\::\::"'"\::\::\::\::\::\::\::"
90 FOR n=7 TO 21: PRINT AT n,1; INK 6;"\::\::\::\::\::": NEXT n
100 PRINT AT 11,13; INK 4;"\':\::\::";AT 12,15;"\':";AT 13,15;"\ :";AT 14,15;"\ '";AT 18,15;"\ :";AT 19,15;"\ :";AT 20,15;"\ :";AT 21,15;"\.:"
110 FOR n=11 TO 21: PRINT AT n,16; INK 4;"\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::\::": NEXT n
120 LET x=21: LET y=8: PRINT AT 21,10;"O": PLOT 64,0: DRAW 37,16
130 PRINT AT x,y; INK 5;"\a"
140 LET h=INT (RND*11)+8
150 PRINT AT h+1,6;"\b"
160 PRINT AT 4,11;"ENTER WEIGHT";AT 5,13;"(max.14)"
170 INPUT w: IF w<=0 OR w>=15 THEN GO TO 170
180 FOR n=10 TO 20: PRINT AT n-1,12;" ";AT n,12;"\c": BEEP .1,n: NEXT n
190 PLOT 64,0: DRAW OVER 1;37,16: PLOT 64,16: DRAW 37,-16
200 FOR n=1 TO w
210 LET x=x-1
220 PRINT AT x,y;"\a";AT x+1,y;" "
230 NEXT n
240 FOR n=1 TO 2: LET y=y-1: PRINT AT x,y;"\a ": NEXT n
250 IF x=h THEN GO TO 280
260 IF x>h THEN GO TO 320
270 IF x<=h THEN PRINT AT x,y; INK 5;"\e": BEEP 1,-10: PAUSE 30: CLS : GO TO 80
280 PRINT AT x,y+1;"WELL DONE!"
290 FOR n=0 TO 40 STEP 10: BEEP .1,n: NEXT n
300 CLS
310 PAUSE 30: RUN
320 FOR n=x TO 21
330 PRINT AT n,y; INK 5;"\e";AT n-1,y;" "
340 BEEP .05,n: NEXT n
350 PRINT AT 21,y; INK 5;"\d"
360 BEEP 1,-10
370 PAUSE 30: CLS : GO TO 80
9900 OVER 0: INVERSE 0: BRIGHT 0: FLASH 0: BORDER 7: PAPER 7: INK 0: CLS
9901 LET a=PEEK 23635+256*PEEK 23636
9902 LET c=0: LET y=175: LET x=130
9903 LET l=PEEK (a+1)+256*PEEK a: LET a=a+4
9904 IF l>9900 THEN GO TO 9942
9905 PRINT l;TAB 5;CHR$ PEEK a: LET c=c+2: PRINT
9906 PLOT x,y: LET b=PEEK a
9907 IF b=226 OR b=234 OR b=242 OR b=254 THEN GO TO 9923
9908 IF b>227 AND b<231 OR b=232 OR b=235 OR b=241 OR b=247 OR b=249 OR b=253 THEN GO TO 9924
9909 IF b=243 OR b=250 THEN GO TO 9925
9910 IF b=236 OR b=237 THEN GO TO 9933
9911 DRAW 16,0: DRAW -4,-8: DRAW -28,0: DRAW 4,8: DRAW 12,0
9912 LET y=y-8
9913 IF b=226 OR b=236 OR b=237 OR b=254 THEN GO TO 9915
9914 PLOT x,y: DRAW 0,-7: DRAW 4,4: DRAW -4,-4: DRAW -4,4
9915 LET y=y-8
9916 LET b=PEEK a: IF b=34 THEN GO SUB 9951
9917 IF b=14 THEN LET a=a+4
9918 IF b=13 THEN GO TO 9921
9919 IF b=58 THEN GO TO 9939
9920 LET a=a+1: GO TO 9916
9921 IF c=20 THEN GO TO 9942
9922 LET a=a+1: GO TO 9903
9923 DRAW 12,0: DRAW 4,-8,-PI: DRAW -24,0: DRAW -4,8,-PI: DRAW 12,0: GO TO 9912
9924 DRAW 16,0: DRAW 0,-8: DRAW -32,0: DRAW 0,8: DRAW 16,0: GO TO 9912
9925 DRAW 8,-4: DRAW 8,0: DRAW -4,4: DRAW 4,-4: DRAW -4,-4: DRAW 4,4: DRAW -8,0: DRAW -8,-4: DRAW -8,4: DRAW 8,4
9926 IF b=243 THEN GO TO 9932
9927 LET a=a+1: LET f=PEEK a
9928 IF f=14 THEN LET a=a+4
9929 IF NOT f=203 THEN GO TO 9927
9930 LET a=a+1: LET f=PEEK a: PRINT AT c-2,19;CHR$ f: PRINT
9931 IF f=236 OR f=237 THEN GO TO 9934
9932 GO TO 9912
9933 CIRCLE x,y-4,4: PLOT x+4,y-4: DRAW 64,0: DRAW -4,4: DRAW 4,-4: DRAW -4,-4: PLOT x,y
9934 LET a=a+1: LET f=PEEK a
9935 IF NOT f=14 THEN GO TO 9934
9936 LET a=a+3: LET g=PEEK a+256*PEEK (a+1)
9937 PRINT AT c-2,26;g: PRINT
9938 GO TO 9912
9939 IF c=20 THEN GO TO 9942
9940 LET a=a+1: PRINT " :";TAB 5;CHR$ PEEK a: PRINT : LET c=c+2
9941 GO TO 9906
9942 INVERSE 1: PRINT AT 21,0;" PRESS ""V"" TO VIEW:""P"" TO PRINT ": INVERSE 0
9943 IF INKEY$="v" THEN GO TO 9946
9944 IF INKEY$="p" THEN GO TO 9950
9945 GO TO 9943
9946 CLS : LET d=0: LET e=22: LET c=0: LET x=130: LET y=175
9947 IF PEEK a=58 THEN GO TO 9940
9948 IF l>9900 THEN PRINT AT 20,6;"End of Basic Program": STOP
9949 LET a=a+1: GO TO 9903
9950 PRINT AT 21,0,,: COPY : GO TO 9946
9951 LET a=a+1: LET b=PEEK a: IF b=34 THEN RETURN
9952 GO TO 9951
9953 SAVE "ROMEO T" LINE 0
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
