xref: /csrg-svn/old/boggle/boggle.c (revision 47854)
1*47854Sbostic /*-
2*47854Sbostic  * Copyright (c) 1982 The Regents of the University of California.
3*47854Sbostic  * All rights reserved.
4*47854Sbostic  *
5*47854Sbostic  * %sccs.include.proprietary.c%
621499Smckusick  */
721499Smckusick 
89895Ssam #ifndef lint
921499Smckusick char copyright[] =
10*47854Sbostic "@(#) Copyright (c) 1982 The Regents of the University of California.\n\
1121499Smckusick  All rights reserved.\n";
12*47854Sbostic #endif /* not lint */
139895Ssam 
1421499Smckusick #ifndef lint
15*47854Sbostic static char sccsid[] = "@(#)boggle.c	5.6 (Berkeley) 04/08/91";
16*47854Sbostic #endif /* not lint */
1721499Smckusick 
189895Ssam #include <ctype.h>
199895Ssam #include <errno.h>
209895Ssam #include <setjmp.h>
219895Ssam #include <sgtty.h>
229895Ssam #include <signal.h>
239895Ssam #include <stdio.h>
2441169Sbostic #include "pathnames.h"
259895Ssam 
269895Ssam /* basic parameters */
279895Ssam #define N 4
289895Ssam #define SSIZE 200
299895Ssam #define MAXWORDS 1000
309895Ssam #define CWIDTH 10
319895Ssam #define LWIDTH 80
329895Ssam 
339895Ssam /* parameters defined in terms of above */
349895Ssam #define BSIZE (N*N)
359895Ssam #define row(x) (x/N)
369895Ssam #define col(x) (x%N)
379895Ssam 
389895Ssam /* word being searched for */
399895Ssam int wlength;
409895Ssam int numsame;
419895Ssam char wbuff [BSIZE+1];
429895Ssam 
439895Ssam /* tty and process control */
449895Ssam extern int errno;
459895Ssam int status;
469895Ssam int pipefd[2];
479895Ssam int super = 0;
489895Ssam int delct = 1;
499895Ssam int zero = 0;
509895Ssam int master = 1;
519895Ssam int column;
529895Ssam int *timept;
539895Ssam int timeint[] = {60,60,50,7,1,1,1,0};
549895Ssam long timein;
559895Ssam extern long int time();
569895Ssam struct sgttyb origttyb, tempttyb;
579895Ssam int ctlecho = 0;
589895Ssam int lctlech = LCTLECH;
599895Ssam jmp_buf env;
609895Ssam 
619895Ssam /* monitoring variables */
629895Ssam int games;
639895Ssam int logfile = -1;
649895Ssam long logloc;
659895Ssam char logbuff[100] = {"inst\t"};
669895Ssam extern char *ctime(), *getlogin();
679895Ssam extern long lseek();
689895Ssam 
699895Ssam /* dictionary interface */
709895Ssam FILE *dict;
719895Ssam 
729895Ssam /* structures for doing matching */
739895Ssam struct frame {
749895Ssam 	struct frame *parent;
759895Ssam 	int place;
769895Ssam };
779895Ssam struct frame stack [SSIZE];
789895Ssam struct frame *level [BSIZE+1];
799895Ssam 
809895Ssam /* the board and subsidiary structures */
819895Ssam char present [BSIZE+1];
829895Ssam char board [BSIZE];
839895Ssam char olink [BSIZE];
849895Ssam char adj [BSIZE+1][BSIZE];
859895Ssam char occurs [26];
869895Ssam 
879895Ssam /* the boggle cubes */
889895Ssam char *cube [BSIZE] = {
899895Ssam 	"forixb", "moqabj", "gurilw", "setupl",
909895Ssam 	"cmpdae", "acitao", "slcrae", "romash",
919895Ssam 	"nodesw", "hefiye", "onudtk", "tevign",
929895Ssam 	"anedvz", "pinesh", "abilyt", "gkyleu"
939895Ssam };
949895Ssam 
959895Ssam 
969895Ssam /* storage for words found */
979895Ssam int ubotch, ustart, wcount;
989895Ssam char *word [MAXWORDS];
999895Ssam char *freesp;
1009895Ssam char space[10000];
1019895Ssam 
1029895Ssam endline ()
1039895Ssam {
1049895Ssam 	if (column != 0) {
1059895Ssam 		putchar('\n');
1069895Ssam 		column = 0;
1079895Ssam 	}
1089895Ssam }
1099895Ssam 
11046734Sbostic void
1119895Ssam timeout ()
1129895Ssam {
1139895Ssam 	if (*timept > 0) {
1149895Ssam 		signal (SIGALRM, timeout);
1159895Ssam 		alarm(*timept++);
1169895Ssam 	}
1179895Ssam 	putchar('\007');
1189895Ssam }
1199895Ssam 
12046734Sbostic void
1219895Ssam interrupt ()
1229895Ssam {
1239895Ssam 	signal(SIGINT, interrupt);
1249895Ssam 	if (delct++ >= 1)
1259895Ssam 		longjmp(env, 1);
1269895Ssam 	timept = &zero;
1279895Ssam }
1289895Ssam 
1299895Ssam goodbye (stat)
1309895Ssam int stat;
1319895Ssam {
1329895Ssam 	if (master != 0) {
1339895Ssam 		wait(&status);
1349895Ssam 		if ( ctlecho & LCTLECH ) {
1359895Ssam 			ioctl( fileno(stdin), TIOCLBIS, &lctlech );
1369895Ssam 		}
1379895Ssam 		stty(fileno(stdin), &origttyb);
1389895Ssam 	}
1399895Ssam 	exit(stat);
1409895Ssam }
1419895Ssam 
1429895Ssam clearscreen ()
1439895Ssam {
1449895Ssam 	stty (fileno(stdin), &tempttyb);
1459895Ssam 	printf("\n\033\f\r");
1469895Ssam }
1479895Ssam 
1489895Ssam compare (a, b)
1499895Ssam char **a, **b;
1509895Ssam {
1519895Ssam 	return(wordcomp(*a, *b));
1529895Ssam }
1539895Ssam 
1549895Ssam wordcomp (p, q)
1559895Ssam register char *p, *q;
1569895Ssam {
1579895Ssam 	if (*p=='0' && *q!='0')
1589895Ssam 		return(-1);
1599895Ssam 	if (*p!='0' && *q=='0')
1609895Ssam 		return(1);
1619895Ssam 	while (*++p == *++q && isalpha(*p)) ;
1629895Ssam 	if (!isalpha(*p))
1639895Ssam 		return(-isalpha(*q));
1649895Ssam 	if (!isalpha(*q))
1659895Ssam 		return(1);
1669895Ssam 	return(*p-*q);
1679895Ssam }
1689895Ssam 
1699895Ssam printinst ()
1709895Ssam {
1719895Ssam 	stty (fileno(stdin), &tempttyb);
1729895Ssam 	printf("instructions?");
1739895Ssam 	if (getchar() == 'y') {
1749895Ssam 		clearscreen();
1759895Ssam 		printf("     The object of Boggle (TM  Parker  Bros.)  is  to  find,  within  3\n");
1769895Ssam 		printf("minutes,  as many words as possible in a 4 by 4 grid of letters.  Words\n");
1779895Ssam 		printf("may be formed from any sequence of 3 or more adjacent  letters  in  the\n");
1789895Ssam 		printf("grid.   The  letters  may join horizontally, vertically, or diagonally.\n");
1799895Ssam 		printf("However, no position in the grid may be used more than once within  any\n");
1809895Ssam 		printf("one  word.   In  competitive  play amongst humans, each player is given\n");
1819895Ssam 		printf("credit for those of his words which no other player has found.\n");
1829895Ssam 		printf("     This program is intended  for  people  wishing  to  sharpen  their\n");
1839895Ssam 		printf("skills  at  Boggle.   If  you  invoke the program with 4 arguments of 4\n");
1849895Ssam 		printf("letters each, (e.g. \"boggle appl epie moth erhd\") the program forms the\n");
1859895Ssam 		printf("obvious  Boggle grid and lists all the words from /usr/dict/words found\n");
1869895Ssam 		printf("therein.  If you invoke the program without arguments, it will generate\n");
1879895Ssam 		printf("a  board  for you, let you enter words for 3 minutes, and then tell you\n");
1889895Ssam 		printf("how well you did relative to /usr/dict/words.\n");
1899895Ssam 		printf("     In interactive play, enter your words separated by  spaces,  tabs,\n");
1909895Ssam 		printf("or  newlines.   A  bell will ring when there is 2:00, 1:00, 0:10, 0:02,\n");
1919895Ssam 		printf("0:01, and 0:00 time left.  You may complete any word started before the\n");
1929895Ssam 		printf("expiration  of  time.   You  can surrender before time is up by hitting\n");
1939895Ssam 		printf("'break'.  While entering words, your erase character is only  effective\n");
1949895Ssam 		printf("within the current word and your line kill character is ignored.\n");
1959895Ssam 		printf("     Advanced players may wish to invoke the program with 1 or 2 +'s as\n");
19620195Smckusick 		printf("the  first argument.  The first + removes the restriction that positions\n");
1979895Ssam 		printf("can only be used once in each word.  The second + causes a position  to\n");
1989895Ssam 		printf("be  considered  adjacent  to itself as well as its (up to) 8 neighbors.\n");
1999895Ssam 		printf("Hit any key to begin.\n");
2009895Ssam 		stty (fileno(stdin), &tempttyb);
2019895Ssam 		getchar();
2029895Ssam 	}
2039895Ssam 	stty (fileno(stdin), &tempttyb);
2049895Ssam }
2059895Ssam 
2069895Ssam setup ()
2079895Ssam {
2089895Ssam 	register int i, j;
2099895Ssam 	int rd, cd, k;
2109895Ssam 	for (i=0; i<BSIZE; i++) {
2119895Ssam 		adj[i][i] = super>=2 ? 1 : 0;
2129895Ssam 		adj[BSIZE][i] = 1;
2139895Ssam 		for (j=0; j<i; j++) {
2149895Ssam 			rd = row(i)-row(j);
2159895Ssam 			cd = col(i)-col(j);
2169895Ssam 			k = 0;
2179895Ssam 			switch (rd) {
2189895Ssam 			case -1:
2199895Ssam 			case 1:
2209895Ssam 				if (-1<=cd && cd<=1)
2219895Ssam 					k = 1;
2229895Ssam 				break;
2239895Ssam 			case 0:
2249895Ssam 				if (cd==-1 || cd==1)
2259895Ssam 					k = 1;
2269895Ssam 				break;
2279895Ssam 			}
2289895Ssam 			adj[i][j] = adj[j][i] = k;
2299895Ssam 		}
2309895Ssam 	}
2319895Ssam 	stack[0].parent = &stack[0];
2329895Ssam 	stack[0].place = BSIZE;
2339895Ssam 	level[0] = &stack[0];
2349895Ssam 	level[1] = &stack[1];
2359895Ssam }
2369895Ssam 
2379895Ssam makelists ()
2389895Ssam {
2399895Ssam 	register int i, c;
2409895Ssam 	for (i=0; i<26; i++)
2419895Ssam 		occurs[i] = BSIZE;
2429895Ssam 	for (i=0; i<BSIZE; i++) {
2439895Ssam 		c = board[i];
2449895Ssam 		olink[i] = occurs[c-'a'];
2459895Ssam 		occurs[c-'a'] = i;
2469895Ssam 	}
2479895Ssam }
2489895Ssam 
2499895Ssam genboard ()
2509895Ssam {
2519895Ssam 	register int i, j;
2529895Ssam 	for (i=0; i<BSIZE; i++)
2539895Ssam 		board[i] = 0;
2549895Ssam 	for (i=0; i<BSIZE; i++) {
2559895Ssam 		j = rand()%BSIZE;
2569895Ssam 		while (board[j] != 0)
2579895Ssam 			j = (j+1)%BSIZE;
2589895Ssam 		board[j] = cube[i][rand()%6];
2599895Ssam 	}
2609895Ssam }
2619895Ssam 
2629895Ssam printboard ()
2639895Ssam {
2649895Ssam 	register int i, j;
2659895Ssam 	for (i=0; i<N; i++) {
2669895Ssam 		printf("\t\t\t\t\b\b");
2679895Ssam 		for (j=0; j<N; j++) {
2689895Ssam 			putchar ((putchar(board[i*N+j]) == 'q') ? 'u' : ' ');
2699895Ssam 			putchar(' ');
2709895Ssam 		}
2719895Ssam 		putchar('\n');
2729895Ssam 	}
2739895Ssam 	putchar('\n');
2749895Ssam }
2759895Ssam 
2769895Ssam getdword ()
2779895Ssam {
2789895Ssam 	/* input:  numsame = # chars same as last word   */
2799895Ssam 	/* output: numsame = # same chars for next word  */
2809895Ssam 	/*        word in wbuff[0]...wbuff[wlength-1]    */
2819895Ssam 	register int c;
2829895Ssam 	register char *p;
2839895Ssam 	if (numsame == EOF)
2849895Ssam 		return (0);
2859895Ssam 	p = &wbuff[numsame]+1;
2869895Ssam 	while ((*p++ = c = getc(dict)) != EOF && isalpha(c)) ;
2879895Ssam 	numsame = c;
2889895Ssam 	wlength = p - &wbuff[2];
2899895Ssam 	return (1);
2909895Ssam }
2919895Ssam 
2929895Ssam getuword ()
2939895Ssam {
2949895Ssam 	int c;
2959895Ssam 	register char *p, *q, *r;
2969895Ssam 	numsame = 0;
2979895Ssam 	while (*timept>0 && (isspace(c=getchar()) || c==EOF));
2989895Ssam 	if (*timept == 0)
2999895Ssam 		return(0);
3009895Ssam 	word[wcount++] = freesp;
3019895Ssam 	*freesp++ = '0';
3029895Ssam 	r = &wbuff[1];
3039895Ssam 	q = p = freesp;
3049895Ssam 	*p++ = c;
3059895Ssam 	while (!isspace(c = getchar())) {
3069895Ssam 		if (c == EOF)
3079895Ssam 			continue;
3089895Ssam 		if (c == origttyb.sg_erase) {
3099895Ssam 			if (p > q)
3109895Ssam 				p--;
3119895Ssam 			continue;
3129895Ssam 		}
3139895Ssam 		*p++ = c;
3149895Ssam 	}
3159895Ssam 	freesp = p;
3169895Ssam 	for (p=q; p<freesp && r<&wbuff[BSIZE]; )
3179895Ssam 		if (islower(c = *p++) && (*r++ = *q++ = c) == 'q' && *p == 'u')
3189895Ssam 			p++;
3199895Ssam 	*(freesp = q) = '0';
3209895Ssam 	wlength = r-&wbuff[1];
3219895Ssam 	return(1);
3229895Ssam }
3239895Ssam 
3249895Ssam aputuword (ways)
3259895Ssam int ways;
3269895Ssam {
3279895Ssam 	*word[wcount-1] = ways>=10 ? '*' : '0'+ways;
3289895Ssam }
3299895Ssam 
3309895Ssam aputword (ways)
3319895Ssam int ways;
3329895Ssam {
3339895Ssam 	/* store (wbuff, ways) in next slot in space */
3349895Ssam 	register int i;
3359895Ssam 	*freesp++ = ways>=10 ? '*' : '0'+ways;
3369895Ssam 	for (i=1; i<= wlength; i++)
3379895Ssam 		*freesp++ = wbuff[i];
3389895Ssam 	word[++wcount] = freesp;
3399895Ssam }
3409895Ssam 
3419895Ssam tputword (ways)
3429895Ssam int ways;
3439895Ssam {
3449895Ssam 	/* print (wbuff, ways) on terminal */
3459895Ssam 	wbuff[wlength+1] = '0';
3469895Ssam 	wbuff[0] = ways>=10 ? '*' : '0'+ways;
3479895Ssam 	outword(&wbuff[0]);
3489895Ssam }
3499895Ssam 
3509895Ssam outword (p)
3519895Ssam register char *p;
3529895Ssam {
3539895Ssam 	register int newcol;
3549895Ssam 	register char *q;
3559895Ssam 	for (q=p+1; isalpha(*q); ) {
3569895Ssam 		putchar(*q);
3579895Ssam 		if (*q++ == 'q') {
3589895Ssam 			putchar('u');
3599895Ssam 			column++;
3609895Ssam 		}
3619895Ssam 	}
3629895Ssam 	column += q-p-1;
3639895Ssam 	if (column > LWIDTH-CWIDTH) {
3649895Ssam 		putchar('\n');
3659895Ssam 		column = 0;
3669895Ssam 		return;
3679895Ssam 	}
3689895Ssam 	newcol = ((column+CWIDTH)/CWIDTH)*CWIDTH;
3699895Ssam 	while (((column+8)/8)*8 <= newcol) {
3709895Ssam 		putchar('\t');
3719895Ssam 		column = ((column+8)/8)*8;
3729895Ssam 	}
3739895Ssam 	while (column < newcol) {
3749895Ssam 		putchar(' ');
3759895Ssam 		column++;
3769895Ssam 	}
3779895Ssam }
3789895Ssam 
3799895Ssam printdiff ()
3809895Ssam {
3819895Ssam 	register int c, d, u;
3829895Ssam 	char both, donly, uonly;
3839895Ssam 	word[wcount] = freesp;
3849895Ssam 	*freesp = '0';
3859895Ssam 	both = donly = uonly = column = d = 0;
3869895Ssam 	u = ustart;
3879895Ssam 	while (d < ubotch) {
3889895Ssam 		c = u<wcount ? wordcomp (word[d], word[u]) : -1;
3899895Ssam 		if (c == 0) {
3909895Ssam 			/* dict and user found same word */
3919895Ssam 			if (both == 0) {
3929895Ssam 				both = 1;
3939895Ssam 				printf("\t\t\t   we both found:\n");
3949895Ssam 			}
3959895Ssam 			outword(word[d]);
3969895Ssam 			word[d++] = NULL;
3979895Ssam 			word[u++] = NULL;
3989895Ssam 		} else if (c < 0) {
3999895Ssam 			/* dict found it, user didn't */
4009895Ssam 			donly = 1;
4019895Ssam 			d++;
4029895Ssam 		} else {
4039895Ssam 			/* user found it, dict didn't */
4049895Ssam 			uonly = 1;
4059895Ssam 			u++;
4069895Ssam 		}
4079895Ssam 	}
4089895Ssam 	endline();
4099895Ssam 	if (donly) {
4109895Ssam 		printf("\n\t\t\tI alone found these:\n");
4119895Ssam 		for (d=0; d<ubotch; d++)
4129895Ssam 			if (word[d] != NULL)
4139895Ssam 				outword(word[d]);
4149895Ssam 		endline();
4159895Ssam 	}
4169895Ssam 	if (uonly) {
4179895Ssam 		printf("\n\t\t\tyou alone found these:\n");
4189895Ssam 		for (u=ustart; u<wcount; u++)
4199895Ssam 			if (word[u] != NULL)
4209895Ssam 				outword(word[u]);
4219895Ssam 		endline();
4229895Ssam 	}
4239895Ssam 	if (ubotch < ustart) {
4249895Ssam 		printf("\n\t\t\t  you botched these:\n");
4259895Ssam 		for (u=ubotch; u<ustart; u++)
4269895Ssam 			outword(word[u]);
4279895Ssam 		endline();
4289895Ssam 	}
4299895Ssam }
4309895Ssam 
4319895Ssam numways (leaf, last)
4329895Ssam register struct frame *leaf;
4339895Ssam struct frame *last;
4349895Ssam {
4359895Ssam 	int count;
4369895Ssam 	register char *p;
4379895Ssam 	register struct frame *node;
4389895Ssam 	if (super > 0)
4399895Ssam 		return(last-leaf);
4409895Ssam 	count = 0;
4419895Ssam 	present[BSIZE] = 1;
4429895Ssam 	while (leaf < last) {
4439895Ssam 		for (p = &present[0]; p < &present[BSIZE]; *p++ = 0);
4449895Ssam 		for (node = leaf; present[node->place]++ == 0; node = node->parent);
4459895Ssam 		if (node == &stack[0])
4469895Ssam 			count++;
4479895Ssam 		leaf++;
4489895Ssam 	}
4499895Ssam 	return(count);
4509895Ssam }
4519895Ssam 
4529895Ssam evalboard (getword, putword)
4539895Ssam int (*getword)(), (*putword)();
4549895Ssam {
4559895Ssam 	register struct frame *top;
4569895Ssam 	register int l, q;
4579895Ssam 	int fo, found;
4589895Ssam 	struct frame *parent, *lastparent;
4599895Ssam 	char *padj;
4609895Ssam 
4619895Ssam 	numsame = found = 0;
4629895Ssam 	makelists ();
4639895Ssam 
4649895Ssam 	while (1) {
4659895Ssam 		l = numsame;
4669895Ssam 		if (!(*getword) ())
4679895Ssam 			break;
4689895Ssam 		top = level[l+1];
4699895Ssam 
4709895Ssam 		while (1) {
4719895Ssam 			level[l+1] = lastparent = top;
4729895Ssam 			/* wbuff[1]...wbuff[l] have been matched */
4739895Ssam 			/* level[0],...,level[l] of tree built */
4749895Ssam 			if (l == wlength) {
4759895Ssam 				if (wlength >= 3 && (q = numways(level[l], top)) != 0) {
4769895Ssam 					(*putword) (q);
4779895Ssam 					found++;
4789895Ssam 				}
4799895Ssam 				l = BSIZE+1;
4809895Ssam 				break;
4819895Ssam 			}
4829895Ssam 			if ((fo = occurs[wbuff[++l]-'a']) == BSIZE)
4839895Ssam 				break;
4849895Ssam 			/* wbuff[1]...wbuff[l-1] have been matched */
4859895Ssam 			/* level[0],...,level[l-1] of tree built */
4869895Ssam 			for (parent=level[l-1]; parent<lastparent; parent++) {
4879895Ssam 				padj = &adj[parent->place][0];
4889895Ssam 				for (q=fo; q!=BSIZE; q=olink[q])
4899895Ssam 					if (padj[q]) {
4909895Ssam 						top->parent = parent;
4919895Ssam 						top->place = q;
4929895Ssam 						if (++top >= &stack[SSIZE]) {
4939895Ssam 							printf("stack overflow\n");
4949895Ssam 							goodbye(1);
4959895Ssam 						}
4969895Ssam 					}
4979895Ssam 			}
4989895Ssam 			/* were any nodes added? */
4999895Ssam 			if (top == lastparent)
5009895Ssam 				break;
5019895Ssam 		}
5029895Ssam 
5039895Ssam 		/* advance until first l characters of next word are different */
5049895Ssam 		while (numsame >= l && (*getword)()) ;
5059895Ssam 	}
5069895Ssam 	return(found);
5079895Ssam }
5089895Ssam 
5099895Ssam main (argc, argv)
5109895Ssam int argc;
5119895Ssam char **argv;
5129895Ssam {
5139895Ssam 	char *q;
5149895Ssam 	register char *p;
5159895Ssam 	register int i, c;
5169895Ssam 
5179895Ssam 	gtty (fileno(stdin), &origttyb);
5189895Ssam 	setbuf(stdin, NULL);
5199895Ssam 	tempttyb = origttyb;
5209895Ssam 	if (setjmp(env) != 0)
5219895Ssam 		goodbye(0);
5229895Ssam 	signal (SIGINT, interrupt);
52346734Sbostic 	timein = time((time_t *)NULL);
52446734Sbostic 	if (argv[0][0] != 'a' && (logfile = open(_PATH_BOGLOG, 1)) >= 0) {
5259895Ssam 		p = &logbuff[5];
5269895Ssam 		q = getlogin();
5279895Ssam 		while (*p++ = *q++);
5289895Ssam 		p[-1] = '\t';
5299895Ssam 		q = ctime(&timein);
5309895Ssam 		while (*p++ = *q++);
5319895Ssam 		logloc = lseek(logfile, 0L, 2);
5329895Ssam 		write(logfile, &logbuff[0], p-&logbuff[1]);
5339895Ssam 	}
53441169Sbostic 	if ((dict = fopen(_PATH_DICTIONARY, "r")) == NULL) {
53541169Sbostic 		printf("can't open %s\n", _PATH_DICTIONARY);
5369895Ssam 		goodbye (2);
5379895Ssam 	}
5389895Ssam 	while ( argc > 1 && ( argv[1][0] == '+' || argv[1][0] == '-' ) ) {
5399895Ssam 		if (argv[1][0]=='+') {
5409895Ssam 			while(*(argv[1]++) == '+')
5419895Ssam 				super++;
5429895Ssam 			argc--;
5439895Ssam 			argv++;
5449895Ssam 		}
5459895Ssam 		if ( argv[1][0] == '-' ) {
5469895Ssam 			timeint[0] = 60 * ( atol( &argv[1][1] ) - 2 );
5479895Ssam 			if ( timeint[0] <= 0 ) {
5489895Ssam 				timeint[0] = 60;
5499895Ssam 			}
5509895Ssam 			argc--;
5519895Ssam 			argv++;
5529895Ssam 		}
5539895Ssam 	}
5549895Ssam 	setup ();
5559895Ssam 	switch (argc) {
5569895Ssam 	default:  punt:
5579895Ssam 		printf("usage: boggle [+[+]] [row1 row2 row3 row4]\n");
5589895Ssam 		goodbye (3);
5599895Ssam 	case 5:
5609895Ssam 		for (i=0; i<BSIZE; i++) {
5619895Ssam 			board[i] = c = argv[row(i)+1][col(i)];
5629895Ssam 			if (!islower(c)) {
5639895Ssam 				printf("bad board\n");
5649895Ssam 				goto punt;
5659895Ssam 			}
5669895Ssam 		}
5679895Ssam 		printboard();
5689895Ssam 		column = 0;
5699895Ssam 		evalboard(getdword, tputword);
5709895Ssam 		endline();
5719895Ssam 		if (logfile >= 0) {
5729895Ssam 			strncpy(&logbuff[0], "eval", 4);
5739895Ssam 			lseek(logfile, logloc, 0);
5749895Ssam 			write(logfile, &logbuff[0], 4);
5759895Ssam 		}
5769895Ssam 		goodbye(0);
5779895Ssam 	case 1:
5789895Ssam 		tempttyb.sg_flags |= CBREAK;
5799895Ssam 		if ( ioctl( fileno(stdin), TIOCLGET, &ctlecho ) == 0 ) {
5809895Ssam 			if ( ctlecho & LCTLECH ) {
5819895Ssam 				ioctl( fileno(stdin), TIOCLBIC, &lctlech );
5829895Ssam 			}
5839895Ssam 		}
5849895Ssam 		printinst();
5859895Ssam 		srand((int) timein);
5869895Ssam 		while (setjmp(env) == 0) {
5879895Ssam 			errno = 0;
5889895Ssam 			if (pipe(&pipefd[0]) != 0) {
5899895Ssam 				printf("can't create pipe\n");
5909895Ssam 				goodbye(4);
5919895Ssam 			}
5929895Ssam 			genboard();
5939895Ssam 			delct = wcount = 0;
5949895Ssam 			word[0] = freesp = &space[0];
5959895Ssam 			if ((master = fork()) == 0) {
5969895Ssam 				close(pipefd[0]);
5979895Ssam 				clearscreen();
5989895Ssam 				printboard();
5999895Ssam 				signal(SIGALRM, timeout);
6009895Ssam 				timept = &timeint[0];
6019895Ssam 				alarm(*timept++);
6029895Ssam 				evalboard(getuword, aputuword);
6039895Ssam 				clearscreen();
6049895Ssam 				qsort(&word[0], wcount, sizeof (int), compare);
6059895Ssam 				for (i=0; i<wcount; i++)
6069895Ssam 					if (i==0 || wordcomp(word[i], word[i-1])!=0) {
6079895Ssam 						p = word[i];
6089895Ssam 						while (isalpha(*++p)) ;
6099895Ssam 						write (pipefd[1], word[i], p-word[i]);
6109895Ssam 					}
6119895Ssam 				close(pipefd[1]);
6129895Ssam 				goodbye(0);
6139895Ssam 			}
6149895Ssam 			close(pipefd[1]);
6159895Ssam 			rewind(dict);
6169895Ssam 			getc(dict);
6179895Ssam 			evalboard(getdword, aputword);
6189895Ssam 			p = freesp;
6199895Ssam 			while ((i = read(pipefd[0], freesp, 512)) != 0) {
6209895Ssam 				if (i < 0)
6219895Ssam 					if (errno != EINTR)
6229895Ssam 						break;
6239895Ssam 					else
6249895Ssam 						i = 0;
6259895Ssam 				freesp += i;
6269895Ssam 			}
6279895Ssam 			close(pipefd[0]);
6289895Ssam 			ustart = ubotch = wcount;
6299895Ssam 			while (p < freesp) {
6309895Ssam 				word[wcount++] = p;
6319895Ssam 				if (*p == '0')
6329895Ssam 					ustart = wcount;
6339895Ssam 				while (isalpha(*++p));
6349895Ssam 			}
6359895Ssam 			wait(&status);
6369895Ssam 			if (status != 0)
6379895Ssam 				goodbye (5);
6389895Ssam 			delct = 1;
6399895Ssam 			printdiff();
6409895Ssam 			printboard();
6419895Ssam 			games++;
6429895Ssam 			if (logfile >= 0) {
64332490Sbostic 				(void)sprintf(&logbuff[0], "%4d", games);
6449895Ssam 				lseek(logfile, logloc, 0);
6459895Ssam 				write(logfile, &logbuff[0], 4);
6469895Ssam 			}
6479895Ssam 			stty (fileno(stdin), &tempttyb);
6489895Ssam 			printf("\nanother game?");
6499895Ssam 			if (getchar() != 'y') {
6509895Ssam 				putchar('\n');
6519895Ssam 				break;
6529895Ssam 			}
6539895Ssam 			stty (fileno(stdin), &tempttyb);
6549895Ssam 		}
6559895Ssam 		goodbye(0);
6569895Ssam 	}
6579895Ssam }
658