This program generates word search puzzles by placing a user-specified list of 2 to 20 words randomly onto a 20×20 grid, with each word placed in one of eight directional orientations (horizontal, vertical, and diagonal, both forward and backward). After placement, empty grid cells are filled with random uppercase letters using CHR$(INT(RND*26)+65). The program supports an optional display-suppression mode (pressing N at the start hides words as they are placed), and offers printer output via LPRINT for both the word list and the completed grid. POKEs to addresses 23609 and 23658 adjust the keyboard repeat rate and the CAPS LOCK flag respectively. The title screen uses a BEEP-driven animation loop that prints “WORDSQUARE” repeatedly while playing a rising tone sequence.
Translated from TS1000 to TS2068 by James Dupuy.
Program Analysis
Program Structure
The program is organized into several distinct phases:
- Title/intro sequence (lines 2–7): Animated BEEP loop printing “WORDSQUARE”, then screen setup with BRIGHT and BORDER.
- User input phase (lines 10–190): Collects the word count and each word, storing them in the 2D string array
C$. - Word placement loop (lines 200–550): Iterates over each word, randomly choosing a start position and direction, checking for conflicts, then writing placed letters into the grid array
H$. - Grid fill and display (lines 560–656): Fills empty cells with random letters, draws a border, and optionally triggers a COPY.
- Answer reveal (lines 660–795): Optionally prints the word list via LPRINT, then reveals placed words in inverse video.
- Subroutine (line 800): COPY + LPRINT line feeds, then RETURN.
- Save lines (lines 865, 9998): Two SAVE statements for persistence.
Grid and Data Structures
The grid size D is fixed at 20 (line 210). Two main arrays are used:
C$(A+5, (LEN B$)+5)— a 2D string array holding all entered words, dimensioned with a small buffer beyond the user-specified count and longest word length.H$(D,D)— a 20×20 character array representing the puzzle grid. A space character indicates an empty cell.K(LEN J$, 5)— a temporary numeric array storing the X,Y coordinates of each letter of the current word being placed, used to commit positions only after a full valid placement is confirmed.
Direction Encoding
Word direction is encoded as two independent step values Z and W (not to be confused with the loop variable Z in the intro), each chosen from {−1, 0, 1}. Lines 330–370 generate them by picking a random integer 0–2 and mapping 2 to −1, giving eight possible directions plus the degenerate (0,0) case which is rejected at line 350. This covers all eight compass directions for diagonal, horizontal, and vertical word placement.
Collision Detection and Retry Logic
Lines 430–440 implement placement validation. If a letter would fall outside the 1–20 grid bounds, or if the target cell is already occupied by a different letter, the entire word placement restarts from line 290 with a new random position and direction. Crucially, the two-phase approach — first computing all coordinates into K, then committing them to H$ only at lines 490–540 — prevents partial writes from corrupting the grid on a failed attempt.
Notable Techniques
- POKE 23609,20 and POKE 23658,8 (line 4): Sets the key repeat delay and enables CAPS LOCK, a common configuration poke for input-heavy programs.
- Random letter fill:
CHR$(INT(RND*26)+65)generates a random ASCII uppercase letter (A–Z), using ASCII rather than the native character set CODE offset. - Two-phase word commit: The
Karray decouples coordinate calculation from grid writing, enabling clean rollback on collision without needing to undo partial writes. - Answer suppression: The variable
R$captured at line 40 is checked throughout the placement loop (line 520); if “N”, letters are placed silently intoH$without being printed. - Decorative border (line 656): A single FOR loop draws asterisks on all four edges simultaneously using multiple AT clauses in one PRINT statement.
- LPRINT output (lines 662–665, 800): Supports a ZX Spectrum printer interface for producing a physical copy of both the grid and the word list.
Bugs and Anomalies
- Variable name collision: The intro loop at line 2 uses
ZandWas loop counters. The same names are later used for direction step values in the placement phase (lines 330–370). Since the intro loop completes before placement begins, this does not cause a runtime error, but it is a potential source of confusion. - Line 165 skip logic: When a word entered at line 160 is longer than the first word
B$, the program jumps to line 180 (skipping the PRINT at line 170), but still stores the over-length word inC$. The DIM at line 120 was sized based onLEN B$, so storing a longer word will be silently truncated by the string array, potentially corrupting the word. - Space handling: Lines 400 and 500 skip spaces in words, allowing multi-word phrases. However, a space in a word will leave a gap in placement coordinates in
K, and the correspondingK(L,1)andK(L,2)will be zero from DIM initialization, which could cause an out-of-range error at line 510 if not skipped correctly — though line 500 does guard against this. - GO TO 7 (line 790): The program loops back to line 7 on “play again,” but line 7 is
CLS— this bypasses the word input and immediately re-enters the placement phase with stale data inC$. The correct restart target is likely line 10 or 80. Z$reuse: The decorative stringZ$="WORDSQUARE"set at line 201 is overwritten by INPUT statements later (lines 660, 661, 670, etc.), but by that point the decorative use is complete, so this causes no functional error.
Line Reference Summary
| Lines | Purpose |
|---|---|
| 2–7 | Animated intro, screen configuration |
| 10–80 | Prompt for answer visibility preference and word count |
| 100–190 | Word entry loop, populate C$ |
| 200–270 | Initialize display grid and H$ array |
| 280–550 | Word placement loop with collision detection |
| 560–656 | Fill empty cells, draw border, offer COPY |
| 660–665 | Optional LPRINT of word list |
| 670–795 | Answer reveal and replay prompt |
| 800 | COPY subroutine |
| 865, 9998 | SAVE statements |
Content
Source Code
1 REM WORDSQUARE TRANSLATED BY ME FROM HARTNELL BOOK, 51 PROGRAMS FOR T1000, THEN POLISHED BY JAMES DUPUY OF GREATER CLEVELAND TSUG
2 FOR Z=1 TO 15: FOR W=1 TO 15
3 BEEP .01,Z: PRINT "WORDSQUARE WORDSQUARE";: NEXT Z: NEXT W
4 POKE 23609,20: POKE 23658,8
5 PAUSE 100: CLS
6 BRIGHT 1: BORDER 5
7 CLS
10 PRINT "IF YOU DO NOT WANT TO SEE THE ANSWERS, THEN PRESS <N> NOW. OTHERWISE, PRESS ANY KEY."
40 LET R$=INKEY$
50 IF R$ ="" THEN GO TO 40
60 CLS
70 PRINT AT 10,4; FLASH 1;"WORD SQUARE WORD SQUARE"
80 INPUT "HOW MANY WORDS? (5-20):";A: IF A<5 OR A>20 THEN GO TO 80
100 PRINT AT 19,0;"ENTER LONGEST WORD."
110 INPUT B$
120 DIM C$(A+5,(LEN B$)+5)
130 LET C$(1)=B$
135 CLS : PRINT "1: ";B$
140 FOR C=2 TO A
150 PRINT AT 21,0;"ENTER WORD NUMBER ";C
160 INPUT D$
165 IF LEN D$>LEN B$ THEN GO TO 180
170 PRINT AT C-1,0;C;": ";D$
180 LET C$(C)=D$
190 NEXT C
200 CLS
201 LET Z$="WORDSQUARE"
205 FOR C=2 TO 20 STEP 2: PRINT AT C,30; INVERSE 1;Z$(C/2): NEXT C
210 LET D=20
220 FOR E=1 TO D
230 FOR F=1 TO D
240 PRINT AT E,F;"*"
250 NEXT F
260 NEXT E
270 DIM H$(D,D)
280 FOR Q=1 TO A
290 LET J$=C$(Q)
300 PRINT AT 0,0;J$
310 LET X=INT (RND*D)+1
320 LET Y=INT (RND*D)+1
330 LET Z=INT (RND*3)
340 LET W=INT (RND*3)
350 IF Z=0 AND W=0 THEN GO TO 330
360 IF Z=2 THEN LET Z=-1
370 IF W=2 THEN LET W=-1
380 DIM K(LEN J$,5)
390 FOR L=1 TO LEN J$
400 IF J$(L)=" " THEN GO TO 480
410 LET X=X+Z
420 LET Y=Y+W
430 IF X<1 OR X>D OR Y<1 OR Y>D THEN GO TO 290
440 IF (NOT H$(X,Y)=" ") AND (NOT (H$(X,Y)=J$(L))) THEN GO TO 290
450 LET K(L,1)=X
460 LET K(L,2)=Y
470 INVERSE 1: PRINT AT 0,L-1;CHR$ (CODE J$(L))
480 NEXT L
485 INVERSE 0
490 FOR M=1 TO LEN J$
500 IF J$(M)=" " THEN GO TO 540
510 LET H$(K(M,1),K(M,2))=J$(M)
520 IF R$="N" THEN GO TO 540
530 PRINT AT K(M,1),K(M,2);J$(M)
535 BEEP .05,30
540 NEXT M
550 NEXT Q
560 PRINT AT 0,0;" "
570 FOR N=1 TO D
580 FOR P=1 TO D
590 IF NOT H$(N,P)=" " THEN PRINT AT N,P;CHR$ (CODE H$(N,P)): GO TO 620
600 LET P$=CHR$ (INT (RND*26)+65)
610 PRINT AT N,P;P$
620 BEEP .003,50
640 NEXT P
650 NEXT N
655 BEEP .5,20
656 FOR T=0 TO 21: PRINT AT 0,T;"*";AT 21,T;"*";AT T,0;"*";AT T,21;"*": NEXT T
660 INPUT FLASH 1;"PRESS ENT FOR COPY";Z$: IF Z$="" THEN GO SUB 800
661 INPUT "PRINT WORDS?((ENT OR N)";Z$: IF Z$="N" THEN PAUSE 30: GO TO 670
662 LPRINT '"THE WORDS TO LOOK FOR ARE:"'
663 FOR U=1 TO A: LPRINT U;": ";C$(U): NEXT U
665 LPRINT '''
670 INPUT FLASH 1;"PRESS ENT FOR ANSWERS. "; LINE Z$
700 FOR N=1 TO D
710 FOR P=1 TO D
720 IF H$(N,P)=" " THEN GO TO 740
725 BEEP .1,25
730 INVERSE 1: PRINT AT N,P;CHR$ (CODE H$(N,P))
740 NEXT P
750 NEXT N
760 INVERSE 0
770 INPUT FLASH 1;"PRESS ENT FOR COPY OF ANSWERS."; LINE Z$: IF Z$="" THEN GO SUB 800
790 INPUT "PLAY AGAIN? (Y/N) ";Z$: IF Z$<>"N" THEN CLEAR : GO TO 7
795 STOP
800 COPY : LPRINT ''': RETURN
850 STOP
865 SAVE "WORDSQUARE": GO TO 2
9998 SAVE "WORDSQUARE" LINE 2
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

