--- title: "HIDDENWORD" id: 54517 type: "computer_media" slug: "hiddenword" url: "http://localhost/computer_media/hiddenword/" markdown_url: "http://localhost/computer_media/hiddenword.md" published_at: "2024-06-02T16:14:38+00:00" modified_at: "2026-03-30T21:42:58+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "This BASIC puzzle generator hides your chosen words in a grid across eight directions, fills blank cells with random letters, and sends the result to screen or printer." 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/" indiv: - name: "George Mockridge" slug: "george-mockridge" taxonomy: "indiv" url: "http://localhost/indiv/george-mockridge/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 51212 title: "CATS Library Tape 1" type: "computer_media" url: "http://localhost/computer_media/cats-library-tape-1/" media_type: "Program" programmers: - name: "George Mockridge" slug: "george-mockridge" taxonomy: "indiv" url: "http://localhost/indiv/george-mockridge/" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/06/Hidden-Word-2.png" - url: "http://localhost/wp-content/uploads/2024/06/Hidden-Word-1.png" media_type_tags: "Game" --- # HIDDENWORD This program is a hidden-word puzzle generator that places user-supplied words into a grid in all eight directions (horizontal, vertical, and four diagonals, both forward and backward). It begins by loading and executing a machine code routine from “DRIVER.BIN” at address 60000, then collects grid dimensions (up to 22 rows by 16 columns) and up to 50 words from the user. Words are sorted by length in a custom insertion-sort routine before placement, and unused cells are filled with random uppercase letters using CHR$(INT(RND*26)+65). Output can be directed to the screen, printer, or both, with the word list printed alongside the completed grid. *** ## Program Analysis ### Program Structure The program is organized into several well-defined phases, each occupying a range of line numbers: 1. **Lines 10–20:** Load and execute the machine code binary “DRIVER.BIN” at address 60000. 2. **Lines 50–1000:** Initialization — set system flags, collect grid size, allocate arrays. 3. **Lines 1700–2700:** Word entry loop — collect up to 50 words, track total letter count, exit on blank entry. 4. **Lines 2700–3600:** Pre-processing — read direction vectors, estimate completion time, randomize cell order, sort words by length. 5. **Lines 3600–7098:** Grid-filling engine — attempt to place each word in each of the eight directions at each candidate cell; fill unplaced cells with random letters. 6. **Lines 7100–9990:** Output section — display and/or print the puzzle grid and word list. 7. **Line 9999:** Save the program with an auto-run entry point. ### Machine Code Usage Lines 10 and 20 use `CAT "DRIVER.BIN",60000` and `RANDOMIZE USR 60000` to load and call an external machine code routine. This routine likely handles low-level tasks such as fast screen output or keyboard handling that would be too slow in BASIC. The address 60000 sits in high RAM, well above the normal BASIC program area. ### Array Allocation | Array | Dimensions | Purpose | | --- | --- | --- | | `M$(MR,MC)` | up to 22×16 | The puzzle grid, one character per cell | | `W$(50,16)` | 50×16 | Stored words (max 16 chars each) | | `R(50,2)` | 50×2 | Word index and length, used for sorting | | `D(8,2)` | 8×2 | Direction vectors (row delta, column delta) | | `S(NC)` | up to 352 | Randomized cell visit order | | `U(50)` | 50 | Flag: word successfully placed | | `Q(50)` | 50 | Working queue of unplaced word indices | ### Direction Vectors Eight direction vectors are read from `DATA` at line 2800 into the `D(8,2)` array. Each pair represents a (row delta, column delta): - (0,1) — right - (1,1) — down-right diagonal - (1,0) — down - (1,-1) — down-left diagonal - (0,-1) — left - (-1,-1) — up-left diagonal - (-1,0) — up - (-1,1) — up-right diagonal ### Word Sorting Lines 3400–3564 implement an insertion sort on the `R` array, ordering words from longest to shortest. Placing longer words first improves placement success rate by consuming more of the grid before shorter, more flexible words are attempted. The sorted order is copied into the working queue array `Q`. ### Cell Randomization Lines 3150–3300 build a Fisher-Yates-style shuffle of cell indices into array `S` by repeatedly picking a random unfilled slot. This ensures the placement engine visits grid cells in a pseudo-random order each run, giving varied puzzle layouts. `RANDOMIZE` at line 3100 re-seeds the RNG without a seed argument, using the system clock for true randomness. ### Placement Engine For each unvisited cell (line 3700 loop), the engine tries all eight directions (the `DI`/`DK` loop at lines 4000–6900). For each direction, it computes the full run of cells from one edge of the grid to the other passing through the candidate cell (lines 4050–5250), extracts the string of current cell contents as `X$`, then tries every substring of `X$` at lines 5500–6800 to see whether any queued word fits — matching either a blank marker `P$` (“-“), a free slot marker `K$` (“*”), or the correct letter already in that cell. ### Inline String Search Subroutine Lines 5452–5476 implement a simple substring-search subroutine parameterized by `Q$` (the string to search), `R$` (the pattern), and `QO` (start offset), returning the match position in `QF`. It is used at lines 5454–5460 specifically to locate the first free-slot marker `K$` (“*”) within the candidate run, to confirm that at least one truly empty cell is present before committing a word. ### Fill Characters Cells that remain unoccupied after all placement attempts receive a random uppercase ASCII letter via `CHR$(INT(RND*26)+65)` at line 6950. The count of such fill characters is tracked in `FU` and individual fill events are reported with a scroll-prevention `POKE 23692,255`. ### Time Estimation Line 2905 computes a rough estimated completion time in minutes using the formula `INT(((NC/100)*.6)+(6.7^(NC*(E/NC)/100+.6)))`, where `NC` is total cell count and `E` is total letters in all words. The exponential term (`6.7^x`) models the dramatically increasing time for denser grids, and the warning at line 2910 explicitly flags grids over 50% full. ### Output Section Lines 8200–9990 handle three output modes selected by the user: screen only (`A$="1"`), printer only (`A$="2"`), or both (`A$="3"`). Printer output at lines 8850–8862 builds each row as a spaced string `V$` before issuing `LPRINT`. The word list section at lines 9964–9976 uses a `GOTO`-driven loop (jumping back to `NEXT I` at line 9970 after printing) rather than a structured `FOR`/`NEXT` block, which is an unusual but functional idiom. ### Notable Bugs and Anomalies - Lines 2551 and 2552 are identical (`LET R(NW,1)=NW: LET R(NW,2)=LEN E$`), so the assignment is redundantly executed twice — harmless but wasteful. - The check at line 2600 (`IF W$(NW,1)=" " THEN GO TO 2700`) tests whether the first character of the stored word string is a space, which is the condition for an empty (blank) input, since `W$(NW)` is zero-padded with spaces. This is a correct but indirect blank-entry detection idiom for string arrays. - At line 5702, the loop `FOR K=1 TO 15 / IF W$(W,K)<>" " THEN NEXT K` finds the position of the first trailing space to determine word length, then checks `K-1<>CL`. This relies on the string array padding behavior and breaks if a word is exactly 15 characters (the loop exits without finding a space and `K` will be 16 after the loop, giving length 15 by coincidence). Words up to 15 characters are handled, consistent with the 16-column `W$` array declaration. - The `RESTORE` at line 2700 is called before reading the direction `DATA` at line 2750, which is correct since the `DATA` statement at line 2800 is the only data block; without `RESTORE` a second puzzle run would fail to re-read it. ## Source Code ``` 10 CAT "DRIVER.BIN",60000 20 RANDOMIZE USR 60000 50 POKE 23658,8 55 REM Remove line 50 if you want the hidden words to appear in small letters. This will help in debugging program. 100 CLS 150 PRINT " HIDDEN WORD" 200 PRINT " PUZZLE GENERATOR" 250 PRINT 300 PRINT 350 PRINT 400 INPUT "HOW MANY ROWS HIGH? 22 MAX. ";MR 402 IF MR>22 THEN GO TO 400 450 INPUT "HOW MANY COLUMNS WIDE? 16 MAX.";MC 452 IF MC>16 THEN GO TO 450 500 LET NC=MR*MC 550 LET P$="-" 600 LET K$="*" 650 LET D$="+" 700 LET NW=0 750 DIM M$(MR,MC) 800 DIM W$(50,16) 825 DIM R(50,2) 850 DIM D(8,2) 900 DIM S(NC) 950 DIM U(50) 1000 DIM Q(50) 1700 CLS 2300 LET NW=0 2350 LET E=0 2400 LET NW=NW+1 2450 CLS 2452 PRINT "GRID SIZE IS ";MR;" BY ";MC 2454 PRINT "YOU HAVE HIDDEN ";NW-1;" WORDS." 2456 PRINT "GRID IS ";INT (E/NC*100);" % FULL." 2498 PRINT "PRESS ENTER WHEN FINISHED." 2500 PRINT "ENTER WORD # ";NW 2525 IF NW>50 THEN PRINT : PRINT : PRINT "MAX.50 WORDS USED, PRESS ENTER." 2540 INPUT E$ 2545 IF NW>50 AND E$="" THEN GO TO 2700 2550 IF NW>50 AND E$<>"" THEN CLS : PRINT AT 10,0;"YOU MAY NOT USE MORE THAN 50 WORDS. RUN THE PROGRAM AGAIN.": STOP 2551 LET R(NW,1)=NW: LET R(NW,2)=LEN E$ 2552 LET R(NW,1)=NW: LET R(NW,2)=LEN E$ 2553 LET W$(NW)=E$ 2554 LET E=E+LEN (E$) 2600 IF W$(NW,1)=" " THEN GO TO 2700 2650 GO TO 2400 2700 LET NW=NW-1: RESTORE 2750 FOR I=1 TO 8: READ D(I,1): READ D(I,2): NEXT I 2800 DATA 0,1,1,1,1,0,1,-1,0,-1,-1,-1,-1,0,-1,1 2905 LET EST=INT (((NC/100)*.6)+(6.7^(NC*(E/NC)/100+.6))) 2910 PRINT : PRINT "THE TIME IT TAKES TO COMPLETE THE PUZZLE WILL VARY WITH THE SIZE OF THE GRID AND THE # OF WORDS USED. WARNING - TIME INCREASES GREATLY FOR LARGER GRIDS OVER 50% FULL." 2912 PRINT "EST. TIME OF THIS PUZZLE ";EST;" MIN." 2950 PRINT : PRINT "SETTING UP THE GRID. PLEASE WAIT" 3000 FOR I=1 TO MR: FOR J=1 TO MC: LET M$(I,J)=P$: NEXT J: NEXT I 3050 FOR I=1 TO NC: LET S(I)=0: NEXT I 3100 RANDOMIZE 3150 FOR I=1 TO NC 3200 LET Q=INT (RND*NC)+1: IF S(Q)<>0 THEN GO TO 3200 3250 LET S(Q)=I 3300 NEXT I 3350 FOR I=1 TO NW: LET Q(I)=0: LET U(I)=0: NEXT I 3400 FOR I=1 TO NW-1 3402 LET J=I 3404 LET T1=R(I+1,1): LET T2=R(I+1,2) 3406 IF T2=1 THEN GO TO 3406 3414 LET R(J+1,2)=T2: LET R(J+1,1)=T1 3416 NEXT I 3560 FOR I=1 TO NW 3562 LET Q(I)=R(I,1) 3564 NEXT I 3600 LET MF=0: LET WA=NW: LET FU=0: LET DI=1 3650 PRINT : PRINT "STARTING TO FILL IN THE GRID" 3652 PRINT 3700 FOR N=1 TO NC 3750 LET CP=S(N) 3800 LET CR=INT ((CP-1)/MC)+1: LET CC=CP-(CR-1)*MC 3850 IF M$(CR,CC)<>P$ THEN GO TO 7000 3900 IF WA=0 THEN LET MF=0: GO TO 6950 3950 LET M$(CR,CC)=K$ 4000 LET DK=1 4050 LET IR=D(DI,1): LET IC=D(DI,2) 4100 LET RT=1: IF IR<0 THEN LET RT=MR 4150 IF IR=0 THEN LET RT=CR 4200 LET CT=1: IF IC<0 THEN LET CT=MC 4250 IF IC=0 THEN LET CT=CC 4300 LET BR=CR: LET BC=CC 4350 IF (BR=RT AND IR<>0) OR (BC=CT AND IC<>0) THEN GO TO 4600 4400 REM GOTO 1500 4450 LET BR=BR-IR 4500 LET BC=BC-IC 4550 GO TO 4350 4600 LET RT=1: IF IR>0 THEN LET RT=MR 4650 IF IR=0 THEN LET RT=CR 4700 LET CT=1: IF IC>0 THEN LET CT=MC 4750 IF IC=0 THEN LET CT=CC 4800 LET ER=CR: LET EC=CC 4850 IF (ER=RT AND IR<>0) OR (EC=CT AND IC<>0) THEN GO TO 5050 4900 LET ER=ER+IR 4950 LET EC=EC+IC 5000 GO TO 4850 5050 LET UR=ER: IF BR>ER THEN LET UR=BR 5100 LET LR=BR: IF ER
EC THEN LET UC=BC 5200 LET LC=BC: IF EC=LR AND PR<=UR AND PC>=LC AND PC<=UC THEN GO TO 5300 5400 LET PL=LEN (X$) 5452 LET QO=1 5454 LET Q$=X$ 5456 LET R$=K$ 5458 GO SUB 5462 5460 LET P=QF 5461 GO TO 5500 5462 LET QF=0 5464 IF LEN (R$)=0 THEN RETURN 5466 IF QO+LEN (R$)-1>LEN (Q$) THEN RETURN 5468 IF Q$(QO TO QO+LEN (R$)-1)=R$ THEN GO TO 5474 5470 LET QO=QO+1 5472 GO TO 5466 5474 LET QF=QO 5476 RETURN 5500 FOR L=1 TO P: FOR R=PL TO P STEP -1 5550 LET C$=X$(L TO L+(R-L+1)-1): LET CL=LEN (C$) 5600 LET Q=1 5650 LET W=Q(Q) 5700 FOR K=1 TO 15 5701 IF W$(W,K)<>" " THEN NEXT K 5702 IF K-1<>CL THEN LET MF=0: GO TO 6750 5750 LET MF=1 5800 FOR C=1 TO CL 5850 IF C$(C)=P$ OR C$(C)=K$ THEN GO TO 5950 5900 IF C$(C)<>W$(W,C) THEN LET C=CL: LET MF=0 5950 NEXT C 6000 IF MF=0 THEN GO TO 6750 6050 LET F$=W$(W,1 TO C-1) 6100 IF L>1 THEN LET F$=D$+F$: LET L=L-1: GO TO 6100 6150 IF R0) OR (C=EC AND IC<>0) THEN GO TO 6450 6400 LET C=C+IC: LET R=R+IR: LET PR=PR+1: GO TO 6250 6450 IF Q=WA THEN GO TO 6550 6500 FOR I=Q TO WA-1: LET Q(I)=Q(I+1): NEXT I 6550 LET WA=WA-1 6600 LET U(W)=1 6650 LET R=P: LET L=P: LET DK=8 6700 POKE 23692,255: PRINT "USED WORD ";NW-WA;"/";NW;" ";W$(W): GO TO 6800 6750 LET Q=Q+1: IF Q<=WA THEN GO TO 5650 6800 NEXT R: NEXT L 6850 LET DI=DI+1: LET DK=DK+1: IF DI>8 THEN LET DI=1 6900 IF DK<=8 THEN GO TO 4050 6950 IF MF=0 THEN LET M$(CR,CC)=CHR$ (INT (RND*26)+65): LET FU=FU+1: POKE 23692,255: PRINT "USED A FILL CHAR. ";NC-N: GO TO 7050 7000 PRINT "CELLS NOT YET EXAM. ";NC-N 7050 NEXT N 7098 BEEP 3,30 7100 CLS 7150 PRINT " PUZZLE COMPLETED" 7200 PRINT 7250 PRINT 7300 PRINT "PRINTER AND DISPLAY SECTION" 7450 PRINT 7500 PRINT "WHERE DO YOU WISH THE " 7550 PRINT " PUZZLE SENT ?" 7600 PRINT 7650 PRINT 7700 PRINT "(1) SCREEN DISPLAY ONLY" 7750 PRINT 7800 PRINT "(2) SEND TO PRINTER ONLY" 7850 PRINT 7900 PRINT "(3) DISPLAY ON SCREEN *AND*" 7950 PRINT " SEND TO PRINTER" 8000 PRINT 8050 PRINT "(ENTER 1,2 or 3)" 8100 PRINT 8150 INPUT A$ 8200 IF A$="1" THEN GO TO 8400 8250 IF A$="2" THEN GO TO 8850 8300 IF A$="3" THEN GO TO 8400 8350 GO TO 8050 8400 CLS 8450 FOR T=1 TO MR 8550 PRINT M$(T,1 TO MC) 8750 NEXT T 8754 PRINT 8755 IF A$="1" THEN GO TO 9950 8850 FOR T=1 TO MR 8851 LET V$="" 8852 FOR C=1 TO MC 8854 LET V$=V$+M$(T,C) 8855 LET V$=V$+" " 8856 NEXT C 8860 LPRINT V$ 8862 NEXT T 8864 IF A$="2" THEN GO TO 9951 9950 PRINT "The Answers Are Hidden In EIGHT Directions." 9951 IF A$<>"1" THEN LPRINT : LPRINT "The Answers Are Hidden In EIGHT Directions." 9952 IF A$<>"2" THEN PRINT "VERT. HORIZ. DIA. BACK. FOR." 9953 IF A$<>"1" THEN LPRINT : LPRINT "VERT. HORIZ. DIA. BACK. FOR." 9960 IF A$<>"2" THEN PRINT : PRINT "THE HIDDEN WORDS ARE:" 9961 IF A$<>"1" THEN LPRINT : LPRINT "THE HIDDEN WORDS ARE:" 9962 IF A$<>"2" THEN PRINT 9963 IF A$<>"1" THEN LPRINT 9964 FOR I=1 TO NW 9966 IF U(I)<>0 THEN GO TO 9974 9970 NEXT I 9972 GO TO 9980 9974 IF A$<>"2" THEN PRINT W$(I);; 9975 IF A$<>"1" THEN LPRINT W$(I); 9976 GO TO 9970 9980 PRINT 9981 IF A$<>"1" THEN LPRINT 9982 PRINT : PRINT "RETURN TO MENU? (Y OR N)" 9984 INPUT A$ 9986 IF A$="Y" THEN GO TO 7100 9988 IF A$<>"N" THEN GO TO 9982 9990 STOP 9999 CLEAR : SAVE "WORD" LINE 50 ```