Boggle

This file is part of and Miscellaneous Programs. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Game

This program implements a multiplayer word game (Boggle) in three languages—English, German, and Spanish—selectable at runtime via the variable L(R). The game generates a 4×4 grid of letter dice, displays a countdown timer from 9000 units, and accepts words from two players in turn, scoring them by length (4-letter words score 1, up to 10+ letters scoring 39). Custom UDG characters are defined for accented and special letters (Ñ, Ü, Ö, LL, RR, Ch) needed for the Spanish and German modes, with the Spanish Ñ represented internally as CHR$ 157. Multiple rounds are supported, with scores tracked across rounds in arrays X(R) and Y(R).


Program Structure

The program is organised into functional blocks rather than a strict top-down flow. The entry point at line 5 sets round number R=1 and jumps to line 800 (not shown, but expected to handle initialisation and the title/setup sequence). Key functional regions are:

  1. Lines 5–40: Display routines for the word grid and timer (GO SUB 20, GO SUB 25).
  2. Lines 50–85: Dice generation — shuffle and assign letter faces using arrays A(), B(), D$(), and C$().
  3. Lines 90–165: Main game loop — countdown timer T from 9000 to 0, keypress detection, and switching between OVER modes for display.
  4. Lines 200–240: Word entry and validation for the active player.
  5. Lines 250–260: Grid line drawing using PLOT/DRAW.
  6. Lines 300–325: Player 2 setup after Player 1’s turn ends.
  7. Lines 330–435: Score reduction input in each language (English 330–355, German 370–395, Spanish 410–435).
  8. Lines 550–565: Word list swap/restore routine using sentinel value "QKZ".
  9. Lines 600–739: Scoring, display, and round management.
  10. Lines 810–855: UDG definition via POKE USR and READ/DATA.
  11. Lines 920–2500: Variable initialisation, language string setup, and dimension statements.

UDG Definitions

Eight custom UDGs are defined at line 810 by poking 8-byte bitmaps into USR "x" addresses. These provide special characters needed for multilingual play:

UDG CharPurpose
"N"Ñ (Spanish)
"C"Ç or Ch digraph indicator
"O"Ö (German)
"U"Ü (German)
"J"Horizontal rule / separator glyph
"H"Ch digraph symbol
"R"RR digraph symbol
"L"LL digraph symbol

In the A$ letter distribution string for Spanish (line 1950), the digraphs Ch, LL, RR are encoded as \h, \l, \r (UDGs H, L, R), and Ñ as \n (UDG N). Line 32 handles display of these multi-character tiles specially, printing “Ch”, “LL”, or “rr” in place of the single UDG code.

Dice Generation Algorithm

The shuffling routine (lines 50–85) uses a probabilistic chain to assign one of 16 dice positions to each of 16 slots without replacement. Array B() tracks which slots have been assigned, and A() accumulates the order. This is not a standard Fisher-Yates shuffle; it relies on repeated random probing and may theoretically loop for long periods if many collisions occur, though in practice convergence is fast for 16 elements.

Each die face is then selected at line 85: D$(I) holds a 6-character face string for die I, and a random face index N is chosen, setting C$(I) to one letter.

Scoring System

Words are scored by length at lines 618 and 654 using a cumulative AND idiom:

  • 4 letters → 1 point
  • 5 letters → 2 points
  • 6 letters → 3 points
  • 7 letters → 7 points
  • 8 letters → 17 points
  • 9 letters → 36 points
  • 10 letters → 75 points (cumulative sum)

Words found by both players (joint words) are marked with sentinel "QKZ" in F$() and excluded from scoring. The penalty input (lines 330–435) allows referees to deduct from either player’s score for invalid words.

OVER Technique for Two-Player Hiding

During Player 1’s turn, words are printed with PRINT OVER 1 to XOR them onto the screen, making them invisible against a pre-drawn background. OVER 0 writes normally. The variable O toggles between these modes, and GO SUB 550 toggles the visibility of all entered words so Player 2 cannot see Player 1’s words and vice versa.

Multilingual String Construction

All UI strings are assembled at lines 1960–1990 using the Sinclair BASIC idiom of string multiplication by boolean condition, e.g.:

LET W$=("WORDS" AND L(R)=1)+("PALABRAS" AND L(R)=3)+("Wo"+CHR$ 8+"\oRTER" AND L(R)=2)

Only one condition is true at a time (returns the string), the others return "". CHR$ 8 (cursor left) combined with a UDG is used to simulate an umlaut by overprinting.

Timer and Beep

The countdown runs as a FOR T=9000 TO 0 STEP -1 loop (line 100). At T=1800 (line 105), a one-second beep at pitch -30 warns players of 20% time remaining. The displayed time is INT(T/60), giving an approximate seconds display since each loop iteration is not exactly 1/60th of a second (BASIC overhead makes this an approximation). At timeout, BEEP 2,0 signals end of turn.

Word List and Sentinel Values

Player 1’s words are stored in S$() with lengths in T(). Words also found by Player 2 are marked by overwriting with "QKZ" (lines 235, 305). Player 2’s confirmed unique words go into J$() with lengths in K(). The sentinel "QXZ" is used at line 305 to blank Player 1’s entries before Player 2’s turn. The display routine at line 557 checks for "QKZ" to skip joint words.

Notable Bugs and Anomalies

  • The word validation loop at lines 214–216 checks both S$() and J$() but uses TO LEN X$ slicing without bounds checking, which could cause an error if LEN X$ exceeds the dimension of the string arrays (11 characters for S$, 10 for J$).

Round and Match Management

The variable R tracks the current round. Scores are stored in X(R) and Y(R). After scoring, line 735 prompts for the next round number; if the entered value matches R, the game loops to line 1100 (language selection for the new round). Otherwise, “END OF MATCH” is printed and execution falls to line 3000 (not shown, likely a final display or halt). Each round can independently select a language, enabling mixed-language matches.

Content

Related Products

Related Articles

Related Content

Image Gallery

Boggle

Source Code

    5 LET R=1: GO TO 800
   15 PRINT OVER O;AT 20,16-(4 AND L(R)=2)-(3 AND L(R)=3);INT (T/60)
   20 PRINT OVER 1-O;AT 1,0+(3 AND L(R)=1);K$: PRINT '''
   25 LET J=1
   27 IF L(R)=3 THEN GO TO 32
   30 PRINT OVER 1;"         ";: FOR I=J TO J+3: PRINT OVER 1-O;C$(I);"u" AND C$(I)="Q"; OVER 1;(" " AND C$(I)<>"Q"); OVER 1;" ";: NEXT I: PRINT '''
   31 GO TO 35
   32 PRINT OVER 1;"         ";: FOR I=J TO J+3: PRINT OVER 1-O;(C$(I) AND C$(I)<>"\h" AND C$(I)<>"\r" AND C$(I)<>"\l");"u" AND C$(I)="Q";"Ch" AND C$(I)="\h";"LL" AND C$(I)="\l";"rr" AND C$(I)="\r"; OVER 1;(" " AND C$(I)<>"Q" AND C$(I)<>"\h" AND C$(I)<>"\r" AND C$(I)<>"\l"); OVER 1;" ";: NEXT I: PRINT '''
   35 LET J=J+4: IF J=17 THEN RETURN 
   40 GO TO 27
   50 LET N=INT (RND*16)+1: LET A(16)=N
   55 LET B(N)=INT (RND*16)+1
   60 LET N=B(N): IF B(N)<>0 THEN GO TO 55
   65 LET A(C)=N: LET C=C+1: IF C=16 THEN GO TO 80
   70 GO TO 55
   80 FOR I=1 TO 16: LET D$(I)=A$(6*A(I)-5 TO 6*A(I))
   85 LET N=INT (RND*6)+1: LET C$(I)=D$(I,N): NEXT I
   90 PRINT OVER 1;AT 1,2+(2 AND L(R)=1);P$+I$(1)
   95 PRINT OVER 1;AT 20,3;W$: PRINT AT 20,16;T$
   96 GO SUB 20
  100 FOR T=9000 TO 0 STEP -1
  105 IF T=1800 THEN BEEP 1,-30
  110 IF INKEY$<>"" THEN GO TO 160
  115 NEXT T
  120 BEEP 2,0: IF SW=0 THEN GO TO 300
  125 GO TO 600
  150 LET O=1: GO SUB 550
  154 GO SUB 15
  155 GO TO 115
  160 LET O=0: GO SUB 15
  165 GO SUB 550
  200 IF L(R)=1 THEN INPUT "ENTER WORD  (""0"" TO SEE LETTERS)";X$
  201 IF L(R)=3 THEN INPUT "ENTER SU PALABRA, O ""0"" PARA VERLAS LETRAS  ";X$ 
  202 IF L(R)=2 THEN INPUT "ENTER WORT (""0""  UM DAS BRETT ZUSEHEN  ";X$
  204 IF X$="0" THEN GO TO 150
  205 IF LEN X$<4 OR LEN X$>10 THEN GO TO 200
  210 FOR I=1 TO LEN X$:
  211 IF X$(I)=" " THEN GO TO 200
  212 IF L(R)=3 AND X$(I)="W" THEN LET X$(I)="\n"
  213 NEXT I
  214 FOR I=1 TO (S AND S>B)+(B AND B>=S): IF X$=S$(I, TO LEN X$) AND S$(I,LEN X$+1)=" " THEN GO TO 200:
  215: IF X$=J$(I, TO LEN X$) AND J$(I,LEN X$+1)=" " THEN GO TO 200:
  216 NEXT I
  218 LET T(S)=LEN X$: PRINT AT 20,0;S: LET S$(S)=X$
  220 PRINT AT S-1-(20 AND S>20)-(20 AND S>40),0+(22 AND S>20)-(11 AND S>40);S$(S, TO T(S))
  222 LET S=S+1: IF SW=0 THEN GO TO 200
  224 FOR I=1 TO F: IF S$(S-1, TO 10)=F$(I) THEN GO TO 235
  225 NEXT I
  230 GO TO 200
  235 LET K(B)=LEN X$: LET J$(B)=X$: LET S$(S-1)="QKZ": LET F$(I)="QKZ": LET B=B+1
  240 GO TO 200
  250 FOR I=64 TO 176 STEP 24: PLOT I,143: DRAW 0,-96: NEXT I
  255 FOR I=47 TO 143 STEP 24: PLOT 64,I: DRAW 94,0: NEXT I
  260 RETURN 
  300 LET O=0: GO SUB 20
  305 FOR I=1 TO S-1: LET F$(I)=S$(I): LET S$(I)="QXZ": LET G(I)=T(I): NEXT I
  310 LET F=S-1: LET S=1: LET SW=1
  312 PRINT AT 20,0;"  "
  315 IF L(R)=1 THEN INPUT "PLAYER 2: ENTER INITIALS ";I$(2)
  316 IF L(R)=3 THEN INPUT "JUGADOR 2: ENTER INICIALES";I$(2)
  317 IF L(R)=2 THEN INPUT "SPIELER 2 ANFANGBUCHSTABEN";I$(2)
  319 IF R=1 THEN LET H$=I$(2)
  325 GO TO 96
  330 IF SW=1 THEN GO TO 345
  335 INPUT "REDUCE PLAYER"; BRIGHT 1;" 1 "; BRIGHT 0;"SCORE BY ?  (99 TO SEE BOARD AND/OR UNSCROLL ";A1
  340 IF A1=99 THEN GO TO 740
  345 LET SW=1: INPUT "REDUCE PLAYER"; BRIGHT 1;" 2 "; BRIGHT 0;"SCORE BY ?  (99 TO SEE BOARD AND/OR UNSCROLL ";A2
  350 IF A2=99 THEN GO TO 740
  355 RETURN 
  370 IF SW=1 THEN GO TO 385
  375 INPUT OVER 1;"ZIEHEN ? AUS SPIELER"; BRIGHT 1;" 1 "; BRIGHT 0;"AB (99   ZUM BRETT U/O ZURu";CHR$ 8;"\oCKROLLEN) ";A1
  380 IF A1=99 THEN GO TO 740
  385 LET SW=1: INPUT OVER 1;"ZIEHEN ? AUS SPIELER"; BRIGHT 1;" 2 "; BRIGHT 0;"AB (99   ZUM BRETT U/O ZURu";CHR$ 8;"\oCKROLLEN) ";A2
  390 IF A2=99 THEN GO TO 740
  395 RETURN 
  410 IF SW=1 THEN GO TO 425
  415 INPUT OVER 1;"QUITAR \c \a\l JUGADOR"; BRIGHT 1;" 1 "; BRIGHT 0;"? (99 PARAEL TABLERO Y/O ARROLLAR ATRA";CHR$ 8;"\u\s) " ;A1
  420 IF A1=99 THEN GO TO 740
  425 LET SW=1: INPUT OVER 1;"QUITAR \c \a\l JUGADOR"; BRIGHT 1;" 2 "; BRIGHT 0;"? (99 PARAEL TABLERO Y/O ARROLLAR ATRA";CHR$ 8;"\u\s) " ;A2
  430 IF A2=99 THEN GO TO 740
  435 RETURN 
  550 LET BB=1:: FOR I=1 TO S-1
  552 IF S$(I, TO 3)="QKZ" THEN LET S$(I)=J$(BB)
  557 PRINT OVER O;AT I-1-(20 AND I>20)-(20 AND I>40),0+(22 AND I>20)-(11 AND I>40);S$(I, TO T(I))
  558 IF S$(I, TO 10)=J$(BB) THEN LET S$(I)="QKZ"
  559 IF S$(I, TO 3)="QKZ" THEN LET BB=BB+1
  560 NEXT I
  562 GO SUB 250
  565 RETURN 
  600 LET SW=0
  601 CLS : LET J=1
  602 FOR I=J TO J+3: PRINT AT (J-1)/4,28+I-J;C$(I);: NEXT I: PRINT AT (J-1)/4,27;"▌": LET J=J+4: IF J=17 THEN GO TO 604
  603 GO TO 602
  604: PRINT OVER 1;AT 0,0;(B$+W$ AND L(R)<>3)+(W$+B$ AND L(R)=3)+": ";
  605 LET SCR1=0: FOR I=1 TO B-1: PRINT J$(I, TO K(I));" ";: IF PEEK 23688<K(I+1)+7 AND PEEK 23689>19 THEN PRINT 
  606 NEXT I
  607 PRINT : PRINT : PRINT TAB 12;I$(1): IF B<4 THEN PRINT 
  609 FOR I=1 TO F
  615 IF F$(I, TO 3)="QKZ" THEN GO TO 632
  618 LET X=1+(1 AND G(I)=5)+(2 AND G(I)=6)+(4 AND G(I)=7)+(10 AND G(I)=8)+(19 AND G(I)=9)+(39 AND G(I)=10)        
  628 LET SCR1=SCR1+X
  630 PRINT F$(I);X,
  632 NEXT I
  636 PRINT TAB 26;"\j": PRINT TAB 26;SCR1
  637 PRINT : PRINT : PRINT TAB 12;I$(2): IF B<4 THEN PRINT 
  638 LET SCR2=0
  639 FOR I=1 TO S-1
  640 IF S$(I, TO 3)="QKZ" THEN GO TO 665
  654 LET Y=1+(1 AND T(I)=5)+(2 AND T(I)=6)+(4 AND T(I)=7)+(10 AND T(I)=8)+(19 AND T(I)=9)+(39 AND T(I)=10)          
  657 LET SCR2=SCR2+Y
  660 PRINT S$(I, TO 10);Y,
  665 NEXT I
  670 PRINT TAB 26;"\j": PRINT TAB 26;SCR2
  672 IF PEEK 23689<4 THEN PRINT '
  675 GO SUB 290+40*L(R)
  720 LET SCR1=SCR1-A1: LET SCR2=SCR2-A2
  725 CLS : PRINT TAB 13;G$;TAB 23;H$
  726 IF I$(1)=G$ THEN GO TO 729
  727 LET Z=SCR1: LET SCR1=SCR2: LET SCR2=Z
  729 LET X(R)=SCR1: LET Y(R)=SCR2: LET Z$="EGSEDSIAE"
  730 FOR I=1 TO R: PRINT AT I+1,0;R$(LEN R$-5 TO LEN R$-1);" ";I;"(";Z$(3*L(R)+L(I)-3);")    ";X(I);: PRINT AT I+1,23;Y(I): NEXT I
  735 PRINT OVER 1;AT 21,0;R$: INPUT RR
  736 PRINT OVER 1;AT 21,0;R$
  737 LET R=R+1: IF RR=R THEN GO TO 1100
  739 PRINT "END OF MATCH": GO TO 3000
  740 CLS : PRINT '''': GO SUB 25
  745 IF INKEY$<>"" THEN GO TO 601
  746 GO TO 745
  810 FOR I=1 TO 8: READ V$: FOR J=0 TO 7: READ Y: POKE USR V$+J,Y: NEXT J: NEXT I
  815 DATA "N",60,66,98,82,74,70,66,0
  820 DATA "C",16,0,16,48,64,68,68,56
  825 DATA "O",36,36,0,0,0,0,0,0
  830 DATA "U",2,4,8,0,0,0,0,0
  835 DATA "J",0,255,0,0,0,0,0,0
  840 DATA "H",4,20,100,134,133,69,53,0
  842 DATA "R",0,119,204,136,136,136,136,0
  845 DATA "L",0,132,132,132,132,132,231,0
  850 DATA 16,-1,0,15,1,1,12,-1,1,7,1,1,4,0,-1,8,-1,1,3,-1,-1
  855 DATA 6,0,1,2,-1,0,1,0,-1,5,0,-1,9,1,-1,14,-1,0,13,0,0
  920 DIM R(20): DIM L(20): DIM X(20): DIM Y(20)
  925 DIM I$(2,3)
 1000 LET O=0: LET C$="NURLDOGEOGOGENOB": GO SUB 250
 1005 PRINT ''''': GO SUB 25
 1010 PAUSE 120: LET A=148: LET B=60: PRINT BRIGHT 1;AT 14,18;"B": FOR I=1 TO 14: READ X: READ Y: READ Z
 1015 REM  NEXT I: GO TO 1050 
 1020 FOR J=1 TO 24: LET A=A+Y: LET B=B+Z: PLOT A,B: NEXT J: PLOT BRIGHT 1;A,B: PLOT PAPER 0;148,60
 1025 FOR J=0 TO 4: PLOT 140-16*J,39-8*J: DRAW 10,0: NEXT J
 1030 FOR J=0 TO 5: PRINT AT 16+J,18-2*J;C$(X)
 1035 PAUSE 10: PRINT OVER 1;AT 16+J,18-2*J;C$(X): NEXT J
 1040 PRINT AT 21,I+1+(8 AND I>6)+(1 AND I>11);C$(X)
 1045 PLOT PAPER 0;A,B: NEXT I
 1100 PAUSE 120: CLS : PRINT ''': PRINT TAB 10;"1  ENGLISH"''TAB 10;"2  DEUTSCH"''TAB 10;"3  ESPA\nOL"
 1110 INPUT L(R): IF L(R)<>1 AND L(R)<>2 AND L(R)<>3 THEN GO TO 1110
 1150 DIM A(16): DIM B(16): DIM F(60): DIM G(60): DIM S(60): DIM T(60): DIM J(50): DIM K(50)
 1160 DIM S$(60,11): DIM F$(60,10): DIM J$(50,10): DIM D$(16,6): DIM C$(16,1)
 1940 IF L(R)=1 THEN LET A$="BTLAYISHrOmACASLErCDPAmEvGTINEGUYKELOQABmJTLSEPUGLrUwIEHYEFIUTODKNOrIXFBDANvEZACIATOINEHPSNwDOSE"
 1945 IF L(R)=2 THEN LET A$="BTLANIEHrOMACASLErCOPAmEvGTINEGUrKELOQABmJTLSEPUGLrUwIEHYEFIUTODKNOrIXFBDANVEZACIATOINEHPSNwDOSE"
 1950 IF L(R)=3 THEN LET A$="BTLAYISHrOmACASLOrCDPAmOvGTINEGUA\hELOQABmJTLSEPUGLrU\nIEH\rEFIUTOD\hNOrIXFBDANvEZACIATOINEHPSN\lDOSE"
 1960 LET W$=("WORDS" AND L(R)=1)+("PALABRAS" AND L(R)=3)+("Wo"+CHR$ 8+"\oRTER" AND L(R)=2)
 1965 LET T$=("    SECONDS LEFT" AND L(R)=1)+(" SEGUNDOS QUEDAN" AND L(R)=3)+("SEKUNDEN BLEIBEN" AND L(R)=2)
 1970 LET K$=(" TOUCH ANY KEY TO WRITE" AND L(R)=1)+(" CUALQUIER TECLA PARA ESCRIBIR" AND L(R)=3)+("IRGENDEINE TASTE UM ZU SCHREIBEN" AND L(R)=2)
 1975 LET P$=("ONE MOMENT PLEASE, " AND L(R)=1)+("EIN AUGENBLICK BITTE, " AND L(R)=2)+("UN MOMENTO POR FAVOR, " AND L(R)=3)
 1980 LET B$=("JOINT " AND L(R)=1)+("GEMEINSAME " AND L(R)=2)+(" EN COMu"+CHR$ 8+"\uN" AND L(R)=3)
 1990 LET R$=("NUMBER OF NEXT ROUND?" AND L(R)=1)+("NUMMER DER NA"+CHR$ 8+"\oCHSTE RUNDE?" AND L(R)=2)+("\cNu"+CHR$ 8+"\uMERO DE LA PRo"+CHR$ 8+"\uXIMA TANDA?" AND L(R)=3)
 2400 LET F=1: LET S=1: LET B=1: LET SW=0: LET C=1: LET O=0:
 2425 IF L(R)=1 THEN INPUT "PLAYER 1: ENTER INITIALS ";I$(1)
 2430 IF L(R)=3 THEN INPUT "JUGADOR 1 ENTER INICIALES ";I$(1)
 2435 IF L(R)=2 THEN INPUT "SPIELER 1 ANFANGBUCHSTABEN";I$(1)
 2450 CLS : GO SUB 250
 2455 IF R=1 THEN LET G$=I$(1)
 2460 PRINT AT 1,2+(2 AND L(R)=1);P$;I$(1)
 2475 GO TO 50
 2500 REM "BOGGLE 3"

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

People

No people associated with this content.

Scroll to Top