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:
- Lines 10–20: Load and execute the machine code binary “DRIVER.BIN” at address 60000.
- Lines 50–1000: Initialization — set system flags, collect grid size, allocate arrays.
- Lines 1700–2700: Word entry loop — collect up to 50 words, track total letter count, exit on blank entry.
- Lines 2700–3600: Pre-processing — read direction vectors, estimate completion time, randomize cell order, sort words by length.
- 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.
- Lines 7100–9990: Output section — display and/or print the puzzle grid and word list.
- 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, sinceW$(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 Kfinds the position of the first trailing space to determine word length, then checksK-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 andKwill be 16 after the loop, giving length 15 by coincidence). Words up to 15 characters are handled, consistent with the 16-columnW$array declaration. - The
RESTOREat line 2700 is called before reading the directionDATAat line 2750, which is correct since theDATAstatement at line 2800 is the only data block; withoutRESTOREa second puzzle run would fail to re-read it.
Content
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<R(J,2) THEN GO TO 3414
3408 LET R(J+1,2)=R(J,2): LET R(J+1,1)=R(J,1)
3410 LET J=J-1
3412 IF J>=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<BR THEN LET LR=ER
5150 LET UC=EC: IF BC>EC THEN LET UC=BC
5200 LET LC=BC: IF EC<BC THEN LET LC=EC
5250 LET PR=BR: LET PC=BC: LET X$=""
5300 LET X$=X$+M$(PR,PC)
5350 LET PR=PR+IR: LET PC=PC+IC: IF PR>=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 R<PL THEN LET F$=F$+D$: LET R=R+1: GO TO 6150
6200 LET PR=1: LET R=BR: LET C=BC
6250 LET Y$=F$(PR TO PR+1-1): IF Y$=D$ THEN GO TO 6350
6300 LET M$(R,C)=Y$
6350 IF (R=ER AND IR<>0) 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
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

