WORDSQUARE

This file is part of and CATS Library Tape 6. Download the collection to get this file.
Developer(s): Tim Hartnell, James DuPuy
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Game

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:

  1. Title/intro sequence (lines 2–7): Animated BEEP loop printing “WORDSQUARE”, then screen setup with BRIGHT and BORDER.
  2. User input phase (lines 10–190): Collects the word count and each word, storing them in the 2D string array C$.
  3. 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$.
  4. Grid fill and display (lines 560–656): Fills empty cells with random letters, draws a border, and optionally triggers a COPY.
  5. Answer reveal (lines 660–795): Optionally prints the word list via LPRINT, then reveals placed words in inverse video.
  6. Subroutine (line 800): COPY + LPRINT line feeds, then RETURN.
  7. 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 K array 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 into H$ 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 Z and W as 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 in C$. The DIM at line 120 was sized based on LEN 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 corresponding K(L,1) and K(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 in C$. The correct restart target is likely line 10 or 80.
  • Z$ reuse: The decorative string Z$="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

LinesPurpose
2–7Animated intro, screen configuration
10–80Prompt for answer visibility preference and word count
100–190Word entry loop, populate C$
200–270Initialize display grid and H$ array
280–550Word placement loop with collision detection
560–656Fill empty cells, draw border, offer COPY
660–665Optional LPRINT of word list
670–795Answer reveal and replay prompt
800COPY subroutine
865, 9998SAVE statements

Content

Appears On

Capital Area Timex Sinclair User Group’s Library Tape.

Related Products

Related Articles

Related Content

Image Gallery

WORDSQUARE

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.

Scroll to Top