xref: /original-bsd/old/boggle/boggle.c (revision 6d223877)
19983bb86Sbostic /*-
2*6d223877Sbostic  * Copyright (c) 1982, 1993
3*6d223877Sbostic  *	The Regents of the University of California.  All rights reserved.
49983bb86Sbostic  *
59983bb86Sbostic  * %sccs.include.proprietary.c%
65cb81c0bSmckusick  */
75cb81c0bSmckusick 
8e78f3172Ssam #ifndef lint
9*6d223877Sbostic static char copyright[] =
10*6d223877Sbostic "@(#) Copyright (c) 1982, 1993\n\
11*6d223877Sbostic 	The Regents of the University of California.  All rights reserved.\n";
129983bb86Sbostic #endif /* not lint */
135cb81c0bSmckusick 
145cb81c0bSmckusick #ifndef lint
15*6d223877Sbostic static char sccsid[] = "@(#)boggle.c	8.1 (Berkeley) 05/31/93";
169983bb86Sbostic #endif /* not lint */
17e78f3172Ssam 
1838cae6d3Storek #include <sys/types.h>
1938cae6d3Storek #include <sys/wait.h>
20e78f3172Ssam #include <ctype.h>
21e78f3172Ssam #include <errno.h>
2238cae6d3Storek #include <fcntl.h>
23e78f3172Ssam #include <setjmp.h>
24e78f3172Ssam #include <sgtty.h>
25e78f3172Ssam #include <signal.h>
26e78f3172Ssam #include <stdio.h>
2738cae6d3Storek #include <stdlib.h>
2838cae6d3Storek #include <string.h>
2938cae6d3Storek #include <time.h>
3038cae6d3Storek #include <unistd.h>
3106a2a5b6Sbostic #include "pathnames.h"
32e78f3172Ssam 
33e78f3172Ssam /* basic parameters */
34e78f3172Ssam #define N 4
35e78f3172Ssam #define SSIZE 200
36e78f3172Ssam #define MAXWORDS 1000
37e78f3172Ssam #define CWIDTH 10
38e78f3172Ssam #define LWIDTH 80
39e78f3172Ssam 
40e78f3172Ssam /* parameters defined in terms of above */
41e78f3172Ssam #define BSIZE (N*N)
42e78f3172Ssam #define row(x) (x/N)
43e78f3172Ssam #define col(x) (x%N)
44e78f3172Ssam 
45e78f3172Ssam /* word being searched for */
46e78f3172Ssam int wlength;
47e78f3172Ssam int numsame;
48e78f3172Ssam char wbuff [BSIZE+1];
49e78f3172Ssam 
50e78f3172Ssam /* tty and process control */
51e78f3172Ssam extern int errno;
52e78f3172Ssam int status;
53e78f3172Ssam int pipefd[2];
54e78f3172Ssam int super = 0;
55e78f3172Ssam int delct = 1;
56e78f3172Ssam int zero = 0;
57e78f3172Ssam int master = 1;
58e78f3172Ssam int column;
59e78f3172Ssam int *timept;
60e78f3172Ssam int timeint[] = {60,60,50,7,1,1,1,0};
6138cae6d3Storek time_t timein;
62e78f3172Ssam struct sgttyb origttyb, tempttyb;
63e78f3172Ssam int ctlecho = 0;
64e78f3172Ssam int lctlech = LCTLECH;
65e78f3172Ssam jmp_buf env;
66e78f3172Ssam 
67e78f3172Ssam /* monitoring variables */
68e78f3172Ssam int games;
69e78f3172Ssam int logfile = -1;
7038cae6d3Storek off_t logloc;
71e78f3172Ssam char logbuff[100] = {"inst\t"};
72e78f3172Ssam 
73e78f3172Ssam /* dictionary interface */
74e78f3172Ssam FILE *dict;
75e78f3172Ssam 
76e78f3172Ssam /* structures for doing matching */
77e78f3172Ssam struct frame {
78e78f3172Ssam 	struct frame *parent;
79e78f3172Ssam 	int place;
80e78f3172Ssam };
81e78f3172Ssam struct frame stack[SSIZE];
82e78f3172Ssam struct frame *level[BSIZE+1];
83e78f3172Ssam 
84e78f3172Ssam /* the board and subsidiary structures */
85e78f3172Ssam char present[BSIZE+1];
86e78f3172Ssam char board[BSIZE];
87e78f3172Ssam char olink[BSIZE];
88e78f3172Ssam char adj[BSIZE+1][BSIZE];
89e78f3172Ssam char occurs[26];
90e78f3172Ssam 
91e78f3172Ssam /* the boggle cubes */
92e78f3172Ssam char *cube[BSIZE] = {
93e78f3172Ssam 	"forixb", "moqabj", "gurilw", "setupl",
94e78f3172Ssam 	"cmpdae", "acitao", "slcrae", "romash",
95e78f3172Ssam 	"nodesw", "hefiye", "onudtk", "tevign",
96e78f3172Ssam 	"anedvz", "pinesh", "abilyt", "gkyleu"
97e78f3172Ssam };
98e78f3172Ssam 
99e78f3172Ssam 
100e78f3172Ssam /* storage for words found */
101e78f3172Ssam int ubotch, ustart, wcount;
102e78f3172Ssam char *word[MAXWORDS];
103e78f3172Ssam char *freesp;
104e78f3172Ssam char space[10000];
105e78f3172Ssam 
10638cae6d3Storek void		aputuword __P((int));
10738cae6d3Storek void		aputword __P((int));
10838cae6d3Storek void		clearscreen __P((void));
10938cae6d3Storek int		compare __P((const void *, const void *));
11038cae6d3Storek void		endline __P((void));
11138cae6d3Storek int		evalboard __P((int (*)(void), void (*)(int)));
11238cae6d3Storek void		genboard __P((void));
11338cae6d3Storek int		getdword __P((void));
11438cae6d3Storek int		getuword __P((void));
11538cae6d3Storek __dead void	goodbye __P((int));
11638cae6d3Storek void		interrupt __P((int));
11738cae6d3Storek void		makelists __P((void));
11838cae6d3Storek int		numways __P((struct frame *, struct frame *));
11938cae6d3Storek void		outword __P((char *));
12038cae6d3Storek void		printboard __P((void));
12138cae6d3Storek void		printdiff __P((void));
12238cae6d3Storek void		printinst __P((void));
12338cae6d3Storek void		setup __P((void));
12438cae6d3Storek void		timeout __P((int));
12538cae6d3Storek void		tputword __P((int));
12638cae6d3Storek int		wordcomp __P((char *, char *));
12738cae6d3Storek 
12838cae6d3Storek 
12938cae6d3Storek void
endline()130e78f3172Ssam endline()
131e78f3172Ssam {
132e78f3172Ssam 	if (column != 0) {
133e78f3172Ssam 		putchar('\n');
134e78f3172Ssam 		column = 0;
135e78f3172Ssam 	}
136e78f3172Ssam }
137e78f3172Ssam 
138a5dcd4d0Sbostic void
timeout(sig)13938cae6d3Storek timeout(sig)
14038cae6d3Storek 	int sig;
141e78f3172Ssam {
142e78f3172Ssam 	if (*timept > 0) {
143e78f3172Ssam 		signal(SIGALRM, timeout);
144e78f3172Ssam 		alarm(*timept++);
145e78f3172Ssam 	}
146e78f3172Ssam 	putchar('\007');
147e78f3172Ssam }
148e78f3172Ssam 
149a5dcd4d0Sbostic void
interrupt(sig)15038cae6d3Storek interrupt(sig)
15138cae6d3Storek 	int sig;
152e78f3172Ssam {
15338cae6d3Storek 
154e78f3172Ssam 	signal(SIGINT, interrupt);
155e78f3172Ssam 	if (delct++ >= 1)
156e78f3172Ssam 		longjmp(env, 1);
157e78f3172Ssam 	timept = &zero;
158e78f3172Ssam }
159e78f3172Ssam 
16038cae6d3Storek __dead void
goodbye(stat)161e78f3172Ssam goodbye(stat)
162e78f3172Ssam 	int stat;
163e78f3172Ssam {
164e78f3172Ssam 	if (master != 0) {
165e78f3172Ssam 		wait(&status);
16638cae6d3Storek 		if (ctlecho & LCTLECH)
167e78f3172Ssam 			ioctl(fileno(stdin), TIOCLBIS, &lctlech);
168e78f3172Ssam 		stty(fileno(stdin), &origttyb);
169e78f3172Ssam 	}
170e78f3172Ssam 	exit(stat);
171e78f3172Ssam }
172e78f3172Ssam 
17338cae6d3Storek void
clearscreen()174e78f3172Ssam clearscreen()
175e78f3172Ssam {
176e78f3172Ssam 	stty(fileno(stdin), &tempttyb);
177e78f3172Ssam 	printf("\n\033\f\r");
178e78f3172Ssam }
179e78f3172Ssam 
18038cae6d3Storek int
compare(a,b)181e78f3172Ssam compare(a, b)
18238cae6d3Storek 	const void *a, *b;
183e78f3172Ssam {
18438cae6d3Storek 
18538cae6d3Storek 	return(wordcomp(*(char **)a, *(char **)b));
186e78f3172Ssam }
187e78f3172Ssam 
18838cae6d3Storek int
wordcomp(p,q)189e78f3172Ssam wordcomp(p, q)
190e78f3172Ssam 	register char *p, *q;
191e78f3172Ssam {
192e78f3172Ssam 	if (*p=='0' && *q!='0')
193e78f3172Ssam 		return(-1);
194e78f3172Ssam 	if (*p!='0' && *q=='0')
195e78f3172Ssam 		return(1);
196e78f3172Ssam 	while (*++p == *++q && isalpha(*p)) ;
197e78f3172Ssam 	if (!isalpha(*p))
198e78f3172Ssam 		return(-isalpha(*q));
199e78f3172Ssam 	if (!isalpha(*q))
200e78f3172Ssam 		return(1);
201e78f3172Ssam 	return(*p-*q);
202e78f3172Ssam }
203e78f3172Ssam 
20438cae6d3Storek void
printinst()205e78f3172Ssam printinst()
206e78f3172Ssam {
207e78f3172Ssam 	stty(fileno(stdin), &tempttyb);
208e78f3172Ssam 	printf("instructions?");
209e78f3172Ssam 	if (getchar() == 'y') {
210e78f3172Ssam 		clearscreen();
211e78f3172Ssam 		printf("     The object of Boggle (TM  Parker  Bros.)  is  to  find,  within  3\n");
212e78f3172Ssam 		printf("minutes,  as many words as possible in a 4 by 4 grid of letters.  Words\n");
213e78f3172Ssam 		printf("may be formed from any sequence of 3 or more adjacent  letters  in  the\n");
214e78f3172Ssam 		printf("grid.   The  letters  may join horizontally, vertically, or diagonally.\n");
215e78f3172Ssam 		printf("However, no position in the grid may be used more than once within  any\n");
216e78f3172Ssam 		printf("one  word.   In  competitive  play amongst humans, each player is given\n");
217e78f3172Ssam 		printf("credit for those of his words which no other player has found.\n");
218e78f3172Ssam 		printf("     This program is intended  for  people  wishing  to  sharpen  their\n");
219e78f3172Ssam 		printf("skills  at  Boggle.   If  you  invoke the program with 4 arguments of 4\n");
220e78f3172Ssam 		printf("letters each, (e.g. \"boggle appl epie moth erhd\") the program forms the\n");
221e78f3172Ssam 		printf("obvious  Boggle grid and lists all the words from /usr/dict/words found\n");
222e78f3172Ssam 		printf("therein.  If you invoke the program without arguments, it will generate\n");
223e78f3172Ssam 		printf("a  board  for you, let you enter words for 3 minutes, and then tell you\n");
224e78f3172Ssam 		printf("how well you did relative to /usr/dict/words.\n");
225e78f3172Ssam 		printf("     In interactive play, enter your words separated by  spaces,  tabs,\n");
226e78f3172Ssam 		printf("or  newlines.   A  bell will ring when there is 2:00, 1:00, 0:10, 0:02,\n");
227e78f3172Ssam 		printf("0:01, and 0:00 time left.  You may complete any word started before the\n");
228e78f3172Ssam 		printf("expiration  of  time.   You  can surrender before time is up by hitting\n");
229e78f3172Ssam 		printf("'break'.  While entering words, your erase character is only  effective\n");
230e78f3172Ssam 		printf("within the current word and your line kill character is ignored.\n");
231e78f3172Ssam 		printf("     Advanced players may wish to invoke the program with 1 or 2 +'s as\n");
23280690fd9Smckusick 		printf("the  first argument.  The first + removes the restriction that positions\n");
233e78f3172Ssam 		printf("can only be used once in each word.  The second + causes a position  to\n");
234e78f3172Ssam 		printf("be  considered  adjacent  to itself as well as its (up to) 8 neighbors.\n");
235e78f3172Ssam 		printf("Hit any key to begin.\n");
236e78f3172Ssam 		stty(fileno(stdin), &tempttyb);
237e78f3172Ssam 		getchar();
238e78f3172Ssam 	}
239e78f3172Ssam 	stty(fileno(stdin), &tempttyb);
240e78f3172Ssam }
241e78f3172Ssam 
24238cae6d3Storek void
setup()243e78f3172Ssam setup()
244e78f3172Ssam {
245e78f3172Ssam 	register int i, j;
246e78f3172Ssam 	int rd, cd, k;
247e78f3172Ssam 	for (i=0; i<BSIZE; i++) {
248e78f3172Ssam 		adj[i][i] = super>=2 ? 1 : 0;
249e78f3172Ssam 		adj[BSIZE][i] = 1;
250e78f3172Ssam 		for (j=0; j<i; j++) {
251e78f3172Ssam 			rd = row(i)-row(j);
252e78f3172Ssam 			cd = col(i)-col(j);
253e78f3172Ssam 			k = 0;
254e78f3172Ssam 			switch (rd) {
255e78f3172Ssam 			case -1:
256e78f3172Ssam 			case 1:
257e78f3172Ssam 				if (-1<=cd && cd<=1)
258e78f3172Ssam 					k = 1;
259e78f3172Ssam 				break;
260e78f3172Ssam 			case 0:
261e78f3172Ssam 				if (cd==-1 || cd==1)
262e78f3172Ssam 					k = 1;
263e78f3172Ssam 				break;
264e78f3172Ssam 			}
265e78f3172Ssam 			adj[i][j] = adj[j][i] = k;
266e78f3172Ssam 		}
267e78f3172Ssam 	}
268e78f3172Ssam 	stack[0].parent = &stack[0];
269e78f3172Ssam 	stack[0].place = BSIZE;
270e78f3172Ssam 	level[0] = &stack[0];
271e78f3172Ssam 	level[1] = &stack[1];
272e78f3172Ssam }
273e78f3172Ssam 
27438cae6d3Storek void
makelists()275e78f3172Ssam makelists()
276e78f3172Ssam {
277e78f3172Ssam 	register int i, c;
278e78f3172Ssam 	for (i=0; i<26; i++)
279e78f3172Ssam 		occurs[i] = BSIZE;
280e78f3172Ssam 	for (i=0; i<BSIZE; i++) {
281e78f3172Ssam 		c = board[i];
282e78f3172Ssam 		olink[i] = occurs[c-'a'];
283e78f3172Ssam 		occurs[c-'a'] = i;
284e78f3172Ssam 	}
285e78f3172Ssam }
286e78f3172Ssam 
28738cae6d3Storek void
genboard()288e78f3172Ssam genboard()
289e78f3172Ssam {
290e78f3172Ssam 	register int i, j;
291e78f3172Ssam 	for (i=0; i<BSIZE; i++)
292e78f3172Ssam 		board[i] = 0;
293e78f3172Ssam 	for (i=0; i<BSIZE; i++) {
294e78f3172Ssam 		j = rand()%BSIZE;
295e78f3172Ssam 		while (board[j] != 0)
296e78f3172Ssam 			j = (j+1)%BSIZE;
297e78f3172Ssam 		board[j] = cube[i][rand()%6];
298e78f3172Ssam 	}
299e78f3172Ssam }
300e78f3172Ssam 
30138cae6d3Storek void
printboard()302e78f3172Ssam printboard()
303e78f3172Ssam {
304e78f3172Ssam 	register int i, j;
305e78f3172Ssam 	for (i=0; i<N; i++) {
306e78f3172Ssam 		printf("\t\t\t\t\b\b");
307e78f3172Ssam 		for (j=0; j<N; j++) {
308e78f3172Ssam 			putchar ((putchar(board[i*N+j]) == 'q') ? 'u' : ' ');
309e78f3172Ssam 			putchar(' ');
310e78f3172Ssam 		}
311e78f3172Ssam 		putchar('\n');
312e78f3172Ssam 	}
313e78f3172Ssam 	putchar('\n');
314e78f3172Ssam }
315e78f3172Ssam 
31638cae6d3Storek int
getdword()317e78f3172Ssam getdword()
318e78f3172Ssam {
319e78f3172Ssam 	/* input:  numsame = # chars same as last word   */
320e78f3172Ssam 	/* output: numsame = # same chars for next word  */
321e78f3172Ssam 	/*        word in wbuff[0]...wbuff[wlength-1]    */
322e78f3172Ssam 	register int c;
323e78f3172Ssam 	register char *p;
324e78f3172Ssam 	if (numsame == EOF)
325e78f3172Ssam 		return (0);
326e78f3172Ssam 	p = &wbuff[numsame]+1;
327e78f3172Ssam 	while ((*p++ = c = getc(dict)) != EOF && isalpha(c)) ;
328e78f3172Ssam 	numsame = c;
329e78f3172Ssam 	wlength = p - &wbuff[2];
330e78f3172Ssam 	return (1);
331e78f3172Ssam }
332e78f3172Ssam 
33338cae6d3Storek int
getuword()334e78f3172Ssam getuword()
335e78f3172Ssam {
336e78f3172Ssam 	int c;
337e78f3172Ssam 	register char *p, *q, *r;
338e78f3172Ssam 	numsame = 0;
339e78f3172Ssam 	while (*timept>0 && (isspace(c=getchar()) || c==EOF));
340e78f3172Ssam 	if (*timept == 0)
341e78f3172Ssam 		return(0);
342e78f3172Ssam 	word[wcount++] = freesp;
343e78f3172Ssam 	*freesp++ = '0';
344e78f3172Ssam 	r = &wbuff[1];
345e78f3172Ssam 	q = p = freesp;
346e78f3172Ssam 	*p++ = c;
347e78f3172Ssam 	while (!isspace(c = getchar())) {
348e78f3172Ssam 		if (c == EOF)
349e78f3172Ssam 			continue;
350e78f3172Ssam 		if (c == origttyb.sg_erase) {
351e78f3172Ssam 			if (p > q)
352e78f3172Ssam 				p--;
353e78f3172Ssam 			continue;
354e78f3172Ssam 		}
355e78f3172Ssam 		*p++ = c;
356e78f3172Ssam 	}
357e78f3172Ssam 	freesp = p;
358e78f3172Ssam 	for (p=q; p<freesp && r<&wbuff[BSIZE]; )
359e78f3172Ssam 		if (islower(c = *p++) && (*r++ = *q++ = c) == 'q' && *p == 'u')
360e78f3172Ssam 			p++;
361e78f3172Ssam 	*(freesp = q) = '0';
362e78f3172Ssam 	wlength = r-&wbuff[1];
363e78f3172Ssam 	return(1);
364e78f3172Ssam }
365e78f3172Ssam 
36638cae6d3Storek void
aputuword(ways)367e78f3172Ssam aputuword(ways)
368e78f3172Ssam 	int ways;
369e78f3172Ssam {
370e78f3172Ssam 	*word[wcount-1] = ways>=10 ? '*' : '0'+ways;
371e78f3172Ssam }
372e78f3172Ssam 
37338cae6d3Storek void
aputword(ways)374e78f3172Ssam aputword(ways)
375e78f3172Ssam 	int ways;
376e78f3172Ssam {
377e78f3172Ssam 	/* store (wbuff, ways) in next slot in space */
378e78f3172Ssam 	register int i;
379e78f3172Ssam 	*freesp++ = ways>=10 ? '*' : '0'+ways;
380e78f3172Ssam 	for (i=1; i<= wlength; i++)
381e78f3172Ssam 		*freesp++ = wbuff[i];
382e78f3172Ssam 	word[++wcount] = freesp;
383e78f3172Ssam }
384e78f3172Ssam 
38538cae6d3Storek void
tputword(ways)386e78f3172Ssam tputword(ways)
387e78f3172Ssam 	int ways;
388e78f3172Ssam {
389e78f3172Ssam 	/* print (wbuff, ways) on terminal */
390e78f3172Ssam 	wbuff[wlength+1] = '0';
391e78f3172Ssam 	wbuff[0] = ways>=10 ? '*' : '0'+ways;
392e78f3172Ssam 	outword(&wbuff[0]);
393e78f3172Ssam }
394e78f3172Ssam 
39538cae6d3Storek void
outword(p)396e78f3172Ssam outword(p)
397e78f3172Ssam 	register char *p;
398e78f3172Ssam {
399e78f3172Ssam 	register int newcol;
400e78f3172Ssam 	register char *q;
401e78f3172Ssam 	for (q=p+1; isalpha(*q); ) {
402e78f3172Ssam 		putchar(*q);
403e78f3172Ssam 		if (*q++ == 'q') {
404e78f3172Ssam 			putchar('u');
405e78f3172Ssam 			column++;
406e78f3172Ssam 		}
407e78f3172Ssam 	}
408e78f3172Ssam 	column += q-p-1;
409e78f3172Ssam 	if (column > LWIDTH-CWIDTH) {
410e78f3172Ssam 		putchar('\n');
411e78f3172Ssam 		column = 0;
412e78f3172Ssam 		return;
413e78f3172Ssam 	}
414e78f3172Ssam 	newcol = ((column+CWIDTH)/CWIDTH)*CWIDTH;
415e78f3172Ssam 	while (((column+8)/8)*8 <= newcol) {
416e78f3172Ssam 		putchar('\t');
417e78f3172Ssam 		column = ((column+8)/8)*8;
418e78f3172Ssam 	}
419e78f3172Ssam 	while (column < newcol) {
420e78f3172Ssam 		putchar(' ');
421e78f3172Ssam 		column++;
422e78f3172Ssam 	}
423e78f3172Ssam }
424e78f3172Ssam 
42538cae6d3Storek void
printdiff()426e78f3172Ssam printdiff()
427e78f3172Ssam {
428e78f3172Ssam 	register int c, d, u;
429e78f3172Ssam 	char both, donly, uonly;
430e78f3172Ssam 	word[wcount] = freesp;
431e78f3172Ssam 	*freesp = '0';
432e78f3172Ssam 	both = donly = uonly = column = d = 0;
433e78f3172Ssam 	u = ustart;
434e78f3172Ssam 	while (d < ubotch) {
435e78f3172Ssam 		c = u<wcount ? wordcomp (word[d], word[u]) : -1;
436e78f3172Ssam 		if (c == 0) {
437e78f3172Ssam 			/* dict and user found same word */
438e78f3172Ssam 			if (both == 0) {
439e78f3172Ssam 				both = 1;
440e78f3172Ssam 				printf("\t\t\t   we both found:\n");
441e78f3172Ssam 			}
442e78f3172Ssam 			outword(word[d]);
443e78f3172Ssam 			word[d++] = NULL;
444e78f3172Ssam 			word[u++] = NULL;
445e78f3172Ssam 		} else if (c < 0) {
446e78f3172Ssam 			/* dict found it, user didn't */
447e78f3172Ssam 			donly = 1;
448e78f3172Ssam 			d++;
449e78f3172Ssam 		} else {
450e78f3172Ssam 			/* user found it, dict didn't */
451e78f3172Ssam 			uonly = 1;
452e78f3172Ssam 			u++;
453e78f3172Ssam 		}
454e78f3172Ssam 	}
455e78f3172Ssam 	endline();
456e78f3172Ssam 	if (donly) {
457e78f3172Ssam 		printf("\n\t\t\tI alone found these:\n");
458e78f3172Ssam 		for (d=0; d<ubotch; d++)
459e78f3172Ssam 			if (word[d] != NULL)
460e78f3172Ssam 				outword(word[d]);
461e78f3172Ssam 		endline();
462e78f3172Ssam 	}
463e78f3172Ssam 	if (uonly) {
464e78f3172Ssam 		printf("\n\t\t\tyou alone found these:\n");
465e78f3172Ssam 		for (u=ustart; u<wcount; u++)
466e78f3172Ssam 			if (word[u] != NULL)
467e78f3172Ssam 				outword(word[u]);
468e78f3172Ssam 		endline();
469e78f3172Ssam 	}
470e78f3172Ssam 	if (ubotch < ustart) {
471e78f3172Ssam 		printf("\n\t\t\t  you botched these:\n");
472e78f3172Ssam 		for (u=ubotch; u<ustart; u++)
473e78f3172Ssam 			outword(word[u]);
474e78f3172Ssam 		endline();
475e78f3172Ssam 	}
476e78f3172Ssam }
477e78f3172Ssam 
47838cae6d3Storek int
numways(leaf,last)479e78f3172Ssam numways(leaf, last)
480e78f3172Ssam 	register struct frame *leaf;
481e78f3172Ssam 	struct frame *last;
482e78f3172Ssam {
483e78f3172Ssam 	int count;
484e78f3172Ssam 	register char *p;
485e78f3172Ssam 	register struct frame *node;
486e78f3172Ssam 	if (super > 0)
487e78f3172Ssam 		return(last-leaf);
488e78f3172Ssam 	count = 0;
489e78f3172Ssam 	present[BSIZE] = 1;
490e78f3172Ssam 	while (leaf < last) {
491e78f3172Ssam 		for (p = &present[0]; p < &present[BSIZE]; *p++ = 0);
492e78f3172Ssam 		for (node = leaf; present[node->place]++ == 0; node = node->parent);
493e78f3172Ssam 		if (node == &stack[0])
494e78f3172Ssam 			count++;
495e78f3172Ssam 		leaf++;
496e78f3172Ssam 	}
497e78f3172Ssam 	return(count);
498e78f3172Ssam }
499e78f3172Ssam 
50038cae6d3Storek int
501e78f3172Ssam evalboard (getword, putword)
50238cae6d3Storek 	int (*getword) __P((void));
50338cae6d3Storek 	void (*putword) __P((int));
504e78f3172Ssam {
505e78f3172Ssam 	register struct frame *top;
506e78f3172Ssam 	register int l, q;
507e78f3172Ssam 	int fo, found;
508e78f3172Ssam 	struct frame *parent, *lastparent;
509e78f3172Ssam 	char *padj;
510e78f3172Ssam 
511e78f3172Ssam 	numsame = found = 0;
512e78f3172Ssam 	makelists ();
513e78f3172Ssam 
514e78f3172Ssam 	while (1) {
515e78f3172Ssam 		l = numsame;
516e78f3172Ssam 		if (!(*getword) ())
517e78f3172Ssam 			break;
518e78f3172Ssam 		top = level[l+1];
519e78f3172Ssam 
520e78f3172Ssam 		while (1) {
521e78f3172Ssam 			level[l+1] = lastparent = top;
522e78f3172Ssam 			/* wbuff[1]...wbuff[l] have been matched */
523e78f3172Ssam 			/* level[0],...,level[l] of tree built */
524e78f3172Ssam 			if (l == wlength) {
525e78f3172Ssam 				if (wlength >= 3 && (q = numways(level[l], top)) != 0) {
526e78f3172Ssam 					(*putword) (q);
527e78f3172Ssam 					found++;
528e78f3172Ssam 				}
529e78f3172Ssam 				l = BSIZE+1;
530e78f3172Ssam 				break;
531e78f3172Ssam 			}
532e78f3172Ssam 			if ((fo = occurs[wbuff[++l]-'a']) == BSIZE)
533e78f3172Ssam 				break;
534e78f3172Ssam 			/* wbuff[1]...wbuff[l-1] have been matched */
535e78f3172Ssam 			/* level[0],...,level[l-1] of tree built */
536e78f3172Ssam 			for (parent=level[l-1]; parent<lastparent; parent++) {
537e78f3172Ssam 				padj = &adj[parent->place][0];
538e78f3172Ssam 				for (q=fo; q!=BSIZE; q=olink[q])
539e78f3172Ssam 					if (padj[q]) {
540e78f3172Ssam 						top->parent = parent;
541e78f3172Ssam 						top->place = q;
542e78f3172Ssam 						if (++top >= &stack[SSIZE]) {
543e78f3172Ssam 							printf("stack overflow\n");
544e78f3172Ssam 							goodbye(1);
545e78f3172Ssam 						}
546e78f3172Ssam 					}
547e78f3172Ssam 			}
548e78f3172Ssam 			/* were any nodes added? */
549e78f3172Ssam 			if (top == lastparent)
550e78f3172Ssam 				break;
551e78f3172Ssam 		}
552e78f3172Ssam 
553e78f3172Ssam 		/* advance until first l characters of next word are different */
554e78f3172Ssam 		while (numsame >= l && (*getword)()) ;
555e78f3172Ssam 	}
556e78f3172Ssam 	return(found);
557e78f3172Ssam }
558e78f3172Ssam 
55938cae6d3Storek int
main(argc,argv)560e78f3172Ssam main(argc, argv)
561e78f3172Ssam 	int argc;
562e78f3172Ssam 	char **argv;
563e78f3172Ssam {
564e78f3172Ssam 	char *q;
565e78f3172Ssam 	register char *p;
566e78f3172Ssam 	register int i, c;
567e78f3172Ssam 
568e78f3172Ssam 	gtty(fileno(stdin), &origttyb);
569e78f3172Ssam 	setbuf(stdin, NULL);
570e78f3172Ssam 	tempttyb = origttyb;
571e78f3172Ssam 	if (setjmp(env) != 0)
572e78f3172Ssam 		goodbye(0);
573e78f3172Ssam 	signal(SIGINT, interrupt);
574a5dcd4d0Sbostic 	timein = time((time_t *)NULL);
57538cae6d3Storek 	if (argv[0][0] != 'a' &&
57638cae6d3Storek 	    (logfile = open(_PATH_BOGLOG, O_WRONLY, 0)) >= 0) {
577e78f3172Ssam 		p = &logbuff[5];
578e78f3172Ssam 		q = getlogin();
57938cae6d3Storek 		while ((*p++ = *q++) != 0);
580e78f3172Ssam 		p[-1] = '\t';
581e78f3172Ssam 		q = ctime(&timein);
58238cae6d3Storek 		while ((*p++ = *q++) != 0);
583e78f3172Ssam 		logloc = lseek(logfile, 0L, 2);
584e78f3172Ssam 		write(logfile, &logbuff[0], p-&logbuff[1]);
585e78f3172Ssam 	}
58606a2a5b6Sbostic 	if ((dict = fopen(_PATH_DICTIONARY, "r")) == NULL) {
58706a2a5b6Sbostic 		printf("can't open %s\n", _PATH_DICTIONARY);
588e78f3172Ssam 		goodbye (2);
589e78f3172Ssam 	}
590e78f3172Ssam 	while ( argc > 1 && ( argv[1][0] == '+' || argv[1][0] == '-' ) ) {
591e78f3172Ssam 		if (argv[1][0]=='+') {
592e78f3172Ssam 			while(*(argv[1]++) == '+')
593e78f3172Ssam 				super++;
594e78f3172Ssam 			argc--;
595e78f3172Ssam 			argv++;
596e78f3172Ssam 		}
597e78f3172Ssam 		if ( argv[1][0] == '-' ) {
598e78f3172Ssam 			timeint[0] = 60 * ( atol( &argv[1][1] ) - 2 );
599e78f3172Ssam 			if ( timeint[0] <= 0 ) {
600e78f3172Ssam 				timeint[0] = 60;
601e78f3172Ssam 			}
602e78f3172Ssam 			argc--;
603e78f3172Ssam 			argv++;
604e78f3172Ssam 		}
605e78f3172Ssam 	}
606e78f3172Ssam 	setup ();
607e78f3172Ssam 	switch (argc) {
608e78f3172Ssam 	default:  punt:
609e78f3172Ssam 		printf("usage: boggle [+[+]] [row1 row2 row3 row4]\n");
610e78f3172Ssam 		goodbye (3);
611e78f3172Ssam 	case 5:
612e78f3172Ssam 		for (i=0; i<BSIZE; i++) {
613e78f3172Ssam 			board[i] = c = argv[row(i)+1][col(i)];
614e78f3172Ssam 			if (!islower(c)) {
615e78f3172Ssam 				printf("bad board\n");
616e78f3172Ssam 				goto punt;
617e78f3172Ssam 			}
618e78f3172Ssam 		}
619e78f3172Ssam 		printboard();
620e78f3172Ssam 		column = 0;
621e78f3172Ssam 		evalboard(getdword, tputword);
622e78f3172Ssam 		endline();
623e78f3172Ssam 		if (logfile >= 0) {
624e78f3172Ssam 			strncpy(&logbuff[0], "eval", 4);
625e78f3172Ssam 			lseek(logfile, logloc, 0);
626e78f3172Ssam 			write(logfile, &logbuff[0], 4);
627e78f3172Ssam 		}
628e78f3172Ssam 		goodbye(0);
629e78f3172Ssam 	case 1:
630e78f3172Ssam 		tempttyb.sg_flags |= CBREAK;
631e78f3172Ssam 		if ( ioctl( fileno(stdin), TIOCLGET, &ctlecho ) == 0 ) {
632e78f3172Ssam 			if ( ctlecho & LCTLECH ) {
633e78f3172Ssam 				ioctl( fileno(stdin), TIOCLBIC, &lctlech );
634e78f3172Ssam 			}
635e78f3172Ssam 		}
636e78f3172Ssam 		printinst();
637e78f3172Ssam 		srand((int) timein);
638e78f3172Ssam 		while (setjmp(env) == 0) {
639e78f3172Ssam 			errno = 0;
640e78f3172Ssam 			if (pipe(&pipefd[0]) != 0) {
641e78f3172Ssam 				printf("can't create pipe\n");
642e78f3172Ssam 				goodbye(4);
643e78f3172Ssam 			}
644e78f3172Ssam 			genboard();
645e78f3172Ssam 			delct = wcount = 0;
646e78f3172Ssam 			word[0] = freesp = &space[0];
647e78f3172Ssam 			if ((master = fork()) == 0) {
648e78f3172Ssam 				close(pipefd[0]);
649e78f3172Ssam 				clearscreen();
650e78f3172Ssam 				printboard();
651e78f3172Ssam 				signal(SIGALRM, timeout);
652e78f3172Ssam 				timept = &timeint[0];
653e78f3172Ssam 				alarm(*timept++);
654e78f3172Ssam 				evalboard(getuword, aputuword);
655e78f3172Ssam 				clearscreen();
656e78f3172Ssam 				qsort(&word[0], wcount, sizeof(int), compare);
657e78f3172Ssam 				for (i=0; i<wcount; i++)
658e78f3172Ssam 					if (i==0 || wordcomp(word[i], word[i-1])!=0) {
659e78f3172Ssam 						p = word[i];
660e78f3172Ssam 						while (isalpha(*++p)) ;
661e78f3172Ssam 						write (pipefd[1], word[i], p-word[i]);
662e78f3172Ssam 					}
663e78f3172Ssam 				close(pipefd[1]);
664e78f3172Ssam 				goodbye(0);
665e78f3172Ssam 			}
666e78f3172Ssam 			close(pipefd[1]);
667e78f3172Ssam 			rewind(dict);
668e78f3172Ssam 			getc(dict);
669e78f3172Ssam 			evalboard(getdword, aputword);
670e78f3172Ssam 			p = freesp;
671e78f3172Ssam 			while ((i = read(pipefd[0], freesp, 512)) != 0) {
672e78f3172Ssam 				if (i < 0)
673e78f3172Ssam 					if (errno != EINTR)
674e78f3172Ssam 						break;
675e78f3172Ssam 					else
676e78f3172Ssam 						i = 0;
677e78f3172Ssam 				freesp += i;
678e78f3172Ssam 			}
679e78f3172Ssam 			close(pipefd[0]);
680e78f3172Ssam 			ustart = ubotch = wcount;
681e78f3172Ssam 			while (p < freesp) {
682e78f3172Ssam 				word[wcount++] = p;
683e78f3172Ssam 				if (*p == '0')
684e78f3172Ssam 					ustart = wcount;
685e78f3172Ssam 				while (isalpha(*++p));
686e78f3172Ssam 			}
687e78f3172Ssam 			wait(&status);
688e78f3172Ssam 			if (status != 0)
689e78f3172Ssam 				goodbye (5);
690e78f3172Ssam 			delct = 1;
691e78f3172Ssam 			printdiff();
692e78f3172Ssam 			printboard();
693e78f3172Ssam 			games++;
694e78f3172Ssam 			if (logfile >= 0) {
6953b557790Sbostic 				(void)sprintf(&logbuff[0], "%4d", games);
696e78f3172Ssam 				lseek(logfile, logloc, 0);
697e78f3172Ssam 				write(logfile, &logbuff[0], 4);
698e78f3172Ssam 			}
699e78f3172Ssam 			stty (fileno(stdin), &tempttyb);
700e78f3172Ssam 			printf("\nanother game?");
701e78f3172Ssam 			if (getchar() != 'y') {
702e78f3172Ssam 				putchar('\n');
703e78f3172Ssam 				break;
704e78f3172Ssam 			}
705e78f3172Ssam 			stty (fileno(stdin), &tempttyb);
706e78f3172Ssam 		}
707e78f3172Ssam 		goodbye(0);
708e78f3172Ssam 	}
709e78f3172Ssam }
710