/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #if !defined(lint) && defined(DOSCCS) char copyright[] = "@(#) Copyright (c) 1980 Regents of the University of California.\n\ All rights reserved.\n"; static char sccsid[] = "@(#)boggle.c 5.1.1 (2.11BSD) 1997/10/2"; #endif #include #include #include #include #include #include #include #include /* basic parameters */ #define N 4 #define SSIZE 200 #define MAXWORDS 1000 #define CWIDTH 10 #define LWIDTH 80 /* parameters defined in terms of above */ #define BSIZE (N*N) #define row(x) (x/N) #define col(x) (x%N) /* word being searched for */ int wlength; int numsame; char wbuff [BSIZE+1]; /* tty and process control */ extern int errno; int status; int pipefd[2]; int super = 0; int delct = 1; int zero = 0; int master = 1; int column; int *timept; int timeint[] = {60,60,50,7,1,1,1,0}; long timein; struct sgttyb origttyb, tempttyb; int ctlecho = 0; int lctlech = LCTLECH; jmp_buf env; /* monitoring variables */ int games; int logfile = -1; long logloc; char logbuff[100] = {"inst\t"}; /* dictionary interface */ char defname[] = "/usr/games/lib/bogdict"; char *dictname = &defname[0]; FILE *dict; /* structures for doing matching */ struct frame { struct frame *parent; int place; }; struct frame stack [SSIZE]; struct frame *level [BSIZE+1]; /* the board and subsidiary structures */ char present [BSIZE+1]; char board [BSIZE]; char olink [BSIZE]; char adj [BSIZE+1][BSIZE]; char occurs [26]; /* the boggle cubes */ char *cube [BSIZE] = { "forixb", "moqabj", "gurilw", "setupl", "cmpdae", "acitao", "slcrae", "romash", "nodesw", "hefiye", "onudtk", "tevign", "anedvz", "pinesh", "abilyt", "gkyleu" }; /* storage for words found */ int ubotch, ustart, wcount; char *word [MAXWORDS]; char *freesp; char space[10000]; endline () { if (column != 0) { putchar('\n'); column = 0; } } timeout () { if (*timept > 0) { signal (SIGALRM, timeout); alarm(*timept++); } putchar('\007'); } interrupt () { signal(SIGINT, interrupt); if (delct++ >= 1) longjmp(env, 1); timept = &zero; } goodbye (stat) int stat; { if (master != 0) { wait(&status); if ( ctlecho & LCTLECH ) { ioctl( fileno(stdin), TIOCLBIS, &lctlech ); } stty(fileno(stdin), &origttyb); } exit(stat); } clearscreen () { stty (fileno(stdin), &tempttyb); printf("\n\f\r"); } compare (a, b) char **a, **b; { return(wordcomp(*a, *b)); } wordcomp (p, q) register char *p, *q; { if (*p=='0' && *q!='0') return(-1); if (*p!='0' && *q=='0') return(1); while (*++p == *++q && isalpha(*p)) ; if (!isalpha(*p)) return(-isalpha(*q)); if (!isalpha(*q)) return(1); return(*p-*q); } printinst () { stty (fileno(stdin), &tempttyb); printf("instructions?"); if (getchar() == 'y') { clearscreen(); printf(" The object of Boggle (TM Parker Bros.) is to find, within 3\n"); printf("minutes, as many words as possible in a 4 by 4 grid of letters. Words\n"); printf("may be formed from any sequence of 3 or more adjacent letters in the\n"); printf("grid. The letters may join horizontally, vertically, or diagonally.\n"); printf("However, no position in the grid may be used more than once within any\n"); printf("one word. In competitive play amongst humans, each player is given\n"); printf("credit for those of his words which no other player has found.\n"); printf(" This program is intended for people wishing to sharpen their\n"); printf("skills at Boggle. If you invoke the program with 4 arguments of 4\n"); printf("letters each, (e.g. \"boggle appl epie moth erhd\") the program forms the\n"); printf("obvious Boggle grid and lists all the words from /usr/dict/words found\n"); printf("therein. If you invoke the program without arguments, it will generate\n"); printf("a board for you, let you enter words for 3 minutes, and then tell you\n"); printf("how well you did relative to /usr/dict/words.\n"); printf(" In interactive play, enter your words separated by spaces, tabs,\n"); printf("or newlines. A bell will ring when there is 2:00, 1:00, 0:10, 0:02,\n"); printf("0:01, and 0:00 time left. You may complete any word started before the\n"); printf("expiration of time. You can surrender before time is up by hitting\n"); printf("'break'. While entering words, your erase character is only effective\n"); printf("within the current word and your line kill character is ignored.\n"); printf(" Advanced players may wish to invoke the program with 1 or 2 +'s as\n"); printf("the first argument. The first + removes the restriction that positions\n"); printf("can only be used once in each word. The second + causes a position to\n"); printf("be considered adjacent to itself as well as its (up to) 8 neighbors.\n"); printf("Hit any key to begin.\n"); stty (fileno(stdin), &tempttyb); getchar(); } stty (fileno(stdin), &tempttyb); } setup () { register int i, j; int rd, cd, k; for (i=0; i=2 ? 1 : 0; adj[BSIZE][i] = 1; for (j=0; j0 && (isspace(c=getchar()) || c==EOF)); if (*timept == 0) return(0); word[wcount++] = freesp; *freesp++ = '0'; r = &wbuff[1]; q = p = freesp; *p++ = c; while (!isspace(c = getchar())) { if (c == EOF) continue; if (c == origttyb.sg_erase) { if (p > q) p--; continue; } *p++ = c; } freesp = p; for (p=q; p=10 ? '*' : '0'+ways; } aputword (ways) int ways; { /* store (wbuff, ways) in next slot in space */ register int i; *freesp++ = ways>=10 ? '*' : '0'+ways; for (i=1; i<= wlength; i++) *freesp++ = wbuff[i]; word[++wcount] = freesp; } tputword (ways) int ways; { /* print (wbuff, ways) on terminal */ wbuff[wlength+1] = '0'; wbuff[0] = ways>=10 ? '*' : '0'+ways; outword(&wbuff[0]); } outword (p) register char *p; { register int newcol; register char *q; for (q=p+1; isalpha(*q); ) { putchar(*q); if (*q++ == 'q') { putchar('u'); column++; } } column += q-p-1; if (column > LWIDTH-CWIDTH) { putchar('\n'); column = 0; return; } newcol = ((column+CWIDTH)/CWIDTH)*CWIDTH; while (((column+8)/8)*8 <= newcol) { putchar('\t'); column = ((column+8)/8)*8; } while (column < newcol) { putchar(' '); column++; } } printdiff () { register int c, d, u; char both, donly, uonly; word[wcount] = freesp; *freesp = '0'; both = donly = uonly = column = d = 0; u = ustart; while (d < ubotch) { c = u 0) return(last-leaf); count = 0; present[BSIZE] = 1; while (leaf < last) { for (p = &present[0]; p < &present[BSIZE]; *p++ = 0); for (node = leaf; present[node->place]++ == 0; node = node->parent); if (node == &stack[0]) count++; leaf++; } return(count); } evalboard (getword, putword) int (*getword)(), (*putword)(); { register struct frame *top; register int l, q; int fo, found; struct frame *parent, *lastparent; char *padj; numsame = found = 0; makelists (); while (1) { l = numsame; if (!(*getword) ()) break; top = level[l+1]; while (1) { level[l+1] = lastparent = top; /* wbuff[1]...wbuff[l] have been matched */ /* level[0],...,level[l] of tree built */ if (l == wlength) { if (wlength >= 3 && (q = numways(level[l], top)) != 0) { (*putword) (q); found++; } l = BSIZE+1; break; } if ((fo = occurs[wbuff[++l]-'a']) == BSIZE) break; /* wbuff[1]...wbuff[l-1] have been matched */ /* level[0],...,level[l-1] of tree built */ for (parent=level[l-1]; parentplace][0]; for (q=fo; q!=BSIZE; q=olink[q]) if (padj[q]) { top->parent = parent; top->place = q; if (++top >= &stack[SSIZE]) { printf("stack overflow\n"); goodbye(1); } } } /* were any nodes added? */ if (top == lastparent) break; } /* advance until first l characters of next word are different */ while (numsame >= l && (*getword)()) ; } return(found); } main (argc, argv) int argc; char **argv; { char *q; register char *p; register int i, c; gtty (fileno(stdin), &origttyb); setbuf(stdin, NULL); tempttyb = origttyb; if (setjmp(env) != 0) goodbye(0); signal (SIGINT, interrupt); timein = time(0L); if (argv[0][0] != 'a' && (logfile = open("/usr/games/lib/boglog", 1)) >= 0) { p = &logbuff[5]; q = getlogin(); while (*p++ = *q++); p[-1] = '\t'; q = ctime(&timein); while (*p++ = *q++); logloc = lseek(logfile, 0L, 2); write(logfile, &logbuff[0], p-&logbuff[1]); } if ((dict = fopen(dictname, "r")) == NULL) { printf("can't open %s\n", dictname); goodbye (2); } while ( argc > 1 && ( argv[1][0] == '+' || argv[1][0] == '-' ) ) { if (argv[1][0]=='+') { while(*(argv[1]++) == '+') super++; argc--; argv++; } if ( argv[1][0] == '-' ) { timeint[0] = 60 * ( atol( &argv[1][1] ) - 2 ); if ( timeint[0] <= 0 ) { timeint[0] = 60; } argc--; argv++; } } setup (); switch (argc) { default: punt: printf("usage: boggle [+[+]] [row1 row2 row3 row4]\n"); goodbye (3); case 5: for (i=0; i= 0) { strncpy(&logbuff[0], "eval", 4); lseek(logfile, logloc, 0); write(logfile, &logbuff[0], 4); } goodbye(0); case 1: tempttyb.sg_flags |= CBREAK; if ( ioctl( fileno(stdin), TIOCLGET, &ctlecho ) == 0 ) { if ( ctlecho & LCTLECH ) { ioctl( fileno(stdin), TIOCLBIC, &lctlech ); } } printinst(); srand((int) timein); while (setjmp(env) == 0) { errno = 0; if (pipe(&pipefd[0]) != 0) { printf("can't create pipe\n"); goodbye(4); } genboard(); delct = wcount = 0; word[0] = freesp = &space[0]; if ((master = fork()) == 0) { close(pipefd[0]); clearscreen(); printboard(); signal(SIGALRM, timeout); timept = &timeint[0]; alarm(*timept++); evalboard(getuword, aputuword); clearscreen(); qsort(&word[0], wcount, sizeof (int), compare); for (i=0; i= 0) { sprintf(&logbuff[0], "%4d", games); lseek(logfile, logloc, 0); write(logfile, &logbuff[0], 4); } stty (fileno(stdin), &tempttyb); printf("\nanother game?"); if (getchar() != 'y') { putchar('\n'); break; } stty (fileno(stdin), &tempttyb); } goodbye(0); } }