|
|
1.1 ! root 1: #include <ctype.h> ! 2: #include <errno.h> ! 3: #include <setjmp.h> ! 4: #include <sgtty.h> ! 5: #include <signal.h> ! 6: #include <stdio.h> ! 7: ! 8: /* basic parameters */ ! 9: #define N 4 ! 10: #define SSIZE 200 ! 11: #define MAXWORDS 1000 ! 12: #define CWIDTH 10 ! 13: #define LWIDTH 80 ! 14: ! 15: /* parameters defined in terms of above */ ! 16: #define BSIZE (N*N) ! 17: #define row(x) (x/N) ! 18: #define col(x) (x%N) ! 19: ! 20: /* word being searched for */ ! 21: int wlength; ! 22: int numsame; ! 23: char wbuff [BSIZE+1]; ! 24: ! 25: /* tty and process control */ ! 26: extern int errno; ! 27: int status; ! 28: int pipefd[2]; ! 29: int super = 0; ! 30: int delct = 1; ! 31: int zero = 0; ! 32: int master = 1; ! 33: int column; ! 34: int *timept; ! 35: int timeint[] = {60,60,50,7,1,1,1,0}; ! 36: long timein; ! 37: extern long int time(); ! 38: struct sgttyb origttyb, tempttyb; ! 39: jmp_buf env; ! 40: ! 41: /* monitoring variables */ ! 42: int games; ! 43: int logfile = -1; ! 44: long logloc; ! 45: char logbuff[100] = {"inst\t"}; ! 46: extern char *ctime(), *getlogin(); ! 47: extern long lseek(); ! 48: ! 49: /* dictionary interface */ ! 50: char defname[] = "/usr/games/bogdict"; ! 51: char *dictname = &defname[0]; ! 52: FILE *dict; ! 53: ! 54: /* structures for doing matching */ ! 55: struct frame { ! 56: struct frame *parent; ! 57: int place; ! 58: }; ! 59: struct frame stack [SSIZE]; ! 60: struct frame *level [BSIZE+1]; ! 61: ! 62: /* the board and subsidiary structures */ ! 63: char present [BSIZE+1]; ! 64: char board [BSIZE]; ! 65: char olink [BSIZE]; ! 66: char adj [BSIZE+1][BSIZE]; ! 67: char occurs [26]; ! 68: ! 69: /* the boggle cubes */ ! 70: char *cube [BSIZE] = { ! 71: "forixb", "moqabj", "gurilw", "setupl", ! 72: "cmpdae", "acitao", "slcrae", "romash", ! 73: "nodesw", "hefiye", "onudtk", "tevign", ! 74: "anedvz", "pinesh", "abilyt", "gkyleu" ! 75: }; ! 76: ! 77: ! 78: /* storage for words found */ ! 79: int ubotch, ustart, wcount; ! 80: char *word [MAXWORDS]; ! 81: char *freesp; ! 82: char space[10000]; ! 83: ! 84: endline () ! 85: { ! 86: if (column != 0) { ! 87: putchar('\n'); ! 88: column = 0; ! 89: } ! 90: } ! 91: ! 92: timeout () ! 93: { ! 94: if (*timept > 0) { ! 95: signal (SIGALRM, timeout); ! 96: alarm(*timept++); ! 97: } ! 98: putchar('\007'); ! 99: } ! 100: ! 101: interrupt () ! 102: { ! 103: signal(SIGINT, interrupt); ! 104: if (delct++ >= 1) ! 105: longjmp(&env, 1); ! 106: timept = &zero; ! 107: } ! 108: ! 109: goodbye (stat) ! 110: int stat; ! 111: { ! 112: if (master != 0) { ! 113: wait(&status); ! 114: stty(fileno(stdin), &origttyb); ! 115: } ! 116: exit(stat); ! 117: } ! 118: ! 119: clearscreen () ! 120: { ! 121: stty (fileno(stdin), &tempttyb); ! 122: printf("\n\033\f\r"); ! 123: } ! 124: ! 125: compare (a, b) ! 126: char **a, **b; ! 127: { ! 128: return(wordcomp(*a, *b)); ! 129: } ! 130: ! 131: wordcomp (p, q) ! 132: register char *p, *q; ! 133: { ! 134: if (*p=='0' && *q!='0') ! 135: return(-1); ! 136: if (*p!='0' && *q=='0') ! 137: return(1); ! 138: while (*++p == *++q && isalpha(*p)) ; ! 139: if (!isalpha(*p)) ! 140: return(-isalpha(*q)); ! 141: if (!isalpha(*q)) ! 142: return(1); ! 143: return(*p-*q); ! 144: } ! 145: ! 146: printinst () ! 147: { ! 148: stty (fileno(stdin), &tempttyb); ! 149: printf("instructions?"); ! 150: if (getchar() == 'y') { ! 151: clearscreen(); ! 152: printf(" The object of Boggle (TM Parker Bros.) is to find, within 3\n"); ! 153: printf("minutes, as many words as possible in a 4 by 4 grid of letters. Words\n"); ! 154: printf("may be formed from any sequence of 3 or more adjacent letters in the\n"); ! 155: printf("grid. The letters may join horizontally, vertically, or diagonally.\n"); ! 156: printf("However, no position in the grid may be used more than once within any\n"); ! 157: printf("one word. In competitive play amongst humans, each player is given\n"); ! 158: printf("credit for those of his words which no other player has found.\n"); ! 159: printf(" This program is intended for people wishing to sharpen their\n"); ! 160: printf("skills at Boggle. If you invoke the program with 4 arguments of 4\n"); ! 161: printf("letters each, (e.g. \"boggle appl epie moth erhd\") the program forms the\n"); ! 162: printf("obvious Boggle grid and lists all the words from /usr/dict/words found\n"); ! 163: printf("therein. If you invoke the program without arguments, it will generate\n"); ! 164: printf("a board for you, let you enter words for 3 minutes, and then tell you\n"); ! 165: printf("how well you did relative to /usr/dict/words.\n"); ! 166: printf(" In interactive play, enter your words separated by spaces, tabs,\n"); ! 167: printf("or newlines. A bell will ring when there is 2:00, 1:00, 0:10, 0:02,\n"); ! 168: printf("0:01, and 0:00 time left. You may complete any word started before the\n"); ! 169: printf("expiration of time. You can surrender before time is up by hitting\n"); ! 170: printf("'break'. While entering words, your erase character is only effective\n"); ! 171: printf("within the current word and your line kill character is ignored.\n"); ! 172: printf(" Advanced players may wish to invoke the program with 1 or 2 +'s as\n"); ! 173: printf("the first argument. The first + removes the restriction that postions\n"); ! 174: printf("can only be used once in each word. The second + causes a position to\n"); ! 175: printf("be considered adjacent to itself as well as its (up to) 8 neighbors.\n"); ! 176: printf("Hit any key to begin.\n"); ! 177: stty (fileno(stdin), &tempttyb); ! 178: getchar(); ! 179: } ! 180: stty (fileno(stdin), &tempttyb); ! 181: } ! 182: ! 183: setup () ! 184: { ! 185: register int i, j; ! 186: int rd, cd, k; ! 187: for (i=0; i<BSIZE; i++) { ! 188: adj[i][i] = super>=2 ? 1 : 0; ! 189: adj[BSIZE][i] = 1; ! 190: for (j=0; j<i; j++) { ! 191: rd = row(i)-row(j); ! 192: cd = col(i)-col(j); ! 193: k = 0; ! 194: switch (rd) { ! 195: case -1: ! 196: case 1: ! 197: if (-1<=cd && cd<=1) ! 198: k = 1; ! 199: break; ! 200: case 0: ! 201: if (cd==-1 || cd==1) ! 202: k = 1; ! 203: break; ! 204: } ! 205: adj[i][j] = adj[j][i] = k; ! 206: } ! 207: } ! 208: stack[0].parent = &stack[0]; ! 209: stack[0].place = BSIZE; ! 210: level[0] = &stack[0]; ! 211: level[1] = &stack[1]; ! 212: } ! 213: ! 214: makelists () ! 215: { ! 216: register int i, c; ! 217: for (i=0; i<26; i++) ! 218: occurs[i] = BSIZE; ! 219: for (i=0; i<BSIZE; i++) { ! 220: c = board[i]; ! 221: olink[i] = occurs[c-'a']; ! 222: occurs[c-'a'] = i; ! 223: } ! 224: } ! 225: ! 226: genboard () ! 227: { ! 228: register int i, j; ! 229: for (i=0; i<BSIZE; i++) ! 230: board[i] = 0; ! 231: for (i=0; i<BSIZE; i++) { ! 232: j = rand()%BSIZE; ! 233: while (board[j] != 0) ! 234: j = (j+1)%BSIZE; ! 235: board[j] = cube[i][rand()%6]; ! 236: } ! 237: } ! 238: ! 239: printboard () ! 240: { ! 241: register int i, j; ! 242: for (i=0; i<N; i++) { ! 243: printf("\t\t\t\t\b\b"); ! 244: for (j=0; j<N; j++) { ! 245: putchar ((putchar(board[i*N+j]) == 'q') ? 'u' : ' '); ! 246: putchar(' '); ! 247: } ! 248: putchar('\n'); ! 249: } ! 250: putchar('\n'); ! 251: } ! 252: ! 253: getdword () ! 254: { ! 255: /* input: numsame = # chars same as last word */ ! 256: /* output: numsame = # same chars for next word */ ! 257: /* word in wbuff[0]...wbuff[wlength-1] */ ! 258: register int c; ! 259: register char *p; ! 260: if (numsame == EOF) ! 261: return (0); ! 262: p = &wbuff[numsame]+1; ! 263: while ((*p++ = c = getc(dict)) != EOF && isalpha(c)) ; ! 264: numsame = c; ! 265: wlength = p - &wbuff[2]; ! 266: return (1); ! 267: } ! 268: ! 269: getuword () ! 270: { ! 271: int c; ! 272: register char *p, *q, *r; ! 273: numsame = 0; ! 274: while (*timept>0 && (isspace(c=getchar()) || c==EOF)); ! 275: if (*timept == 0) ! 276: return(0); ! 277: word[wcount++] = freesp; ! 278: *freesp++ = '0'; ! 279: r = &wbuff[1]; ! 280: q = p = freesp; ! 281: *p++ = c; ! 282: while (!isspace(c = getchar())) { ! 283: if (c == EOF) ! 284: continue; ! 285: if (c == origttyb.sg_erase) { ! 286: if (p > q) ! 287: p--; ! 288: continue; ! 289: } ! 290: *p++ = c; ! 291: } ! 292: freesp = p; ! 293: for (p=q; p<freesp && r<&wbuff[BSIZE]; ) ! 294: if (islower(c = *p++) && (*r++ = *q++ = c) == 'q' && *p == 'u') ! 295: p++; ! 296: *(freesp = q) = '0'; ! 297: wlength = r-&wbuff[1]; ! 298: return(1); ! 299: } ! 300: ! 301: aputuword (ways) ! 302: int ways; ! 303: { ! 304: *word[wcount-1] = ways>=10 ? '*' : '0'+ways; ! 305: } ! 306: ! 307: aputword (ways) ! 308: int ways; ! 309: { ! 310: /* store (wbuff, ways) in next slot in space */ ! 311: register int i; ! 312: *freesp++ = ways>=10 ? '*' : '0'+ways; ! 313: for (i=1; i<= wlength; i++) ! 314: *freesp++ = wbuff[i]; ! 315: word[++wcount] = freesp; ! 316: } ! 317: ! 318: tputword (ways) ! 319: int ways; ! 320: { ! 321: /* print (wbuff, ways) on terminal */ ! 322: wbuff[wlength+1] = '0'; ! 323: wbuff[0] = ways>=10 ? '*' : '0'+ways; ! 324: outword(&wbuff[0]); ! 325: } ! 326: ! 327: outword (p) ! 328: register char *p; ! 329: { ! 330: register int newcol; ! 331: register char *q; ! 332: for (q=p+1; isalpha(*q); ) { ! 333: putchar(*q); ! 334: if (*q++ == 'q') { ! 335: putchar('u'); ! 336: column++; ! 337: } ! 338: } ! 339: column += q-p-1; ! 340: if (column > LWIDTH-CWIDTH) { ! 341: putchar('\n'); ! 342: column = 0; ! 343: return; ! 344: } ! 345: newcol = ((column+CWIDTH)/CWIDTH)*CWIDTH; ! 346: while (((column+8)/8)*8 <= newcol) { ! 347: putchar('\t'); ! 348: column = ((column+8)/8)*8; ! 349: } ! 350: while (column < newcol) { ! 351: putchar(' '); ! 352: column++; ! 353: } ! 354: } ! 355: ! 356: printdiff () ! 357: { ! 358: register int c, d, u; ! 359: char both, donly, uonly; ! 360: word[wcount] = freesp; ! 361: *freesp = '0'; ! 362: both = donly = uonly = column = d = 0; ! 363: u = ustart; ! 364: while (d < ubotch) { ! 365: c = u<wcount ? wordcomp (word[d], word[u]) : -1; ! 366: if (c == 0) { ! 367: /* dict and user found same word */ ! 368: if (both == 0) { ! 369: both = 1; ! 370: printf("\t\t\t we both found:\n"); ! 371: } ! 372: outword(word[d]); ! 373: word[d++] = NULL; ! 374: word[u++] = NULL; ! 375: } else if (c < 0) { ! 376: /* dict found it, user didn't */ ! 377: donly = 1; ! 378: d++; ! 379: } else { ! 380: /* user found it, dict didn't */ ! 381: uonly = 1; ! 382: u++; ! 383: } ! 384: } ! 385: endline(); ! 386: if (donly) { ! 387: printf("\n\t\t\tI alone found these:\n"); ! 388: for (d=0; d<ubotch; d++) ! 389: if (word[d] != NULL) ! 390: outword(word[d]); ! 391: endline(); ! 392: } ! 393: if (uonly) { ! 394: printf("\n\t\t\tyou alone found these:\n"); ! 395: for (u=ustart; u<wcount; u++) ! 396: if (word[u] != NULL) ! 397: outword(word[u]); ! 398: endline(); ! 399: } ! 400: if (ubotch < ustart) { ! 401: printf("\n\t\t\t you botched these:\n"); ! 402: for (u=ubotch; u<ustart; u++) ! 403: outword(word[u]); ! 404: endline(); ! 405: } ! 406: } ! 407: ! 408: numways (leaf, last) ! 409: register struct frame *leaf; ! 410: struct frame *last; ! 411: { ! 412: int count; ! 413: register char *p; ! 414: register struct frame *node; ! 415: if (super > 0) ! 416: return(last-leaf); ! 417: count = 0; ! 418: present[BSIZE] = 1; ! 419: while (leaf < last) { ! 420: for (p = &present[0]; p < &present[BSIZE]; *p++ = 0); ! 421: for (node = leaf; present[node->place]++ == 0; node = node->parent); ! 422: if (node == &stack[0]) ! 423: count++; ! 424: leaf++; ! 425: } ! 426: return(count); ! 427: } ! 428: ! 429: evalboard (getword, putword) ! 430: int (*getword)(), (*putword)(); ! 431: { ! 432: register struct frame *top; ! 433: register int l, q; ! 434: int fo, found; ! 435: struct frame *parent, *lastparent; ! 436: char *padj; ! 437: ! 438: numsame = found = 0; ! 439: makelists (); ! 440: ! 441: while (1) { ! 442: l = numsame; ! 443: if (!(*getword) ()) ! 444: break; ! 445: top = level[l+1]; ! 446: ! 447: while (1) { ! 448: level[l+1] = lastparent = top; ! 449: /* wbuff[1]...wbuff[l] have been matched */ ! 450: /* level[0],...,level[l] of tree built */ ! 451: if (l == wlength) { ! 452: if (wlength >= 3 && (q = numways(level[l], top)) != 0) { ! 453: (*putword) (q); ! 454: found++; ! 455: } ! 456: l = BSIZE+1; ! 457: break; ! 458: } ! 459: if ((fo = occurs[wbuff[++l]-'a']) == BSIZE) ! 460: break; ! 461: /* wbuff[1]...wbuff[l-1] have been matched */ ! 462: /* level[0],...,level[l-1] of tree built */ ! 463: for (parent=level[l-1]; parent<lastparent; parent++) { ! 464: padj = &adj[parent->place][0]; ! 465: for (q=fo; q!=BSIZE; q=olink[q]) ! 466: if (padj[q]) { ! 467: top->parent = parent; ! 468: top->place = q; ! 469: if (++top >= &stack[SSIZE]) { ! 470: printf("stack overflow\n"); ! 471: goodbye(1); ! 472: } ! 473: } ! 474: } ! 475: /* were any nodes added? */ ! 476: if (top == lastparent) ! 477: break; ! 478: } ! 479: ! 480: /* advance until first l characters of next word are different */ ! 481: while (numsame >= l && (*getword)()) ; ! 482: } ! 483: return(found); ! 484: } ! 485: ! 486: main (argc, argv) ! 487: int argc; ! 488: char **argv; ! 489: { ! 490: char *q; ! 491: register char *p; ! 492: register int i, c; ! 493: ! 494: gtty (fileno(stdin), &origttyb); ! 495: setbuf(fileno(stdin), NULL); ! 496: tempttyb = origttyb; ! 497: if (setjmp(&env) != 0) ! 498: goodbye(0); ! 499: signal (SIGINT, interrupt); ! 500: timein = time(0L); ! 501: if (argv[0][0] != 'a' && (logfile = open("/usr/games/boglog", 1)) >= 0) { ! 502: p = &logbuff[5]; ! 503: q = getlogin(); ! 504: if (q == NULL) ! 505: q = "unknown"; ! 506: while (*p++ = *q++); ! 507: p[-1] = '\t'; ! 508: q = ctime(&timein); ! 509: while (*p++ = *q++); ! 510: logloc = lseek(logfile, 0L, 2); ! 511: write(logfile, &logbuff[0], p-&logbuff[1]); ! 512: } ! 513: if ((dict = fopen(dictname, "r")) == NULL) { ! 514: printf("can't open %s\n", dictname); ! 515: goodbye (2); ! 516: } ! 517: if (argc>1 && argv[1][0]=='+') { ! 518: while(*(argv[1]++) == '+') ! 519: super++; ! 520: argc--; ! 521: argv++; ! 522: } ! 523: setup (); ! 524: switch (argc) { ! 525: default: punt: ! 526: printf("usage: boggle [+[+]] [row1 row2 row3 row4]\n"); ! 527: goodbye (3); ! 528: case 5: ! 529: for (i=0; i<BSIZE; i++) { ! 530: board[i] = c = argv[row(i)+1][col(i)]; ! 531: if (!islower(c)) { ! 532: printf("bad board\n"); ! 533: goto punt; ! 534: } ! 535: } ! 536: printboard(); ! 537: column = 0; ! 538: evalboard(getdword, tputword); ! 539: endline(); ! 540: if (logfile >= 0) { ! 541: strncpy(&logbuff[0], "eval", 4); ! 542: lseek(logfile, logloc, 0); ! 543: write(logfile, &logbuff[0], 4); ! 544: } ! 545: goodbye(0); ! 546: case 1: ! 547: tempttyb.sg_flags |= CBREAK; ! 548: printinst(); ! 549: srand((int) timein); ! 550: while (setjmp(&env) == 0) { ! 551: errno = 0; ! 552: if (pipe(&pipefd[0]) != 0) { ! 553: printf("can't create pipe\n"); ! 554: goodbye(4); ! 555: } ! 556: genboard(); ! 557: delct = wcount = 0; ! 558: word[0] = freesp = &space[0]; ! 559: if ((master = fork()) == 0) { ! 560: close(pipefd[0]); ! 561: clearscreen(); ! 562: printboard(); ! 563: signal(SIGALRM, timeout); ! 564: timept = &timeint[0]; ! 565: alarm(*timept++); ! 566: evalboard(getuword, aputuword); ! 567: clearscreen(); ! 568: qsort(&word[0], wcount, sizeof (int), compare); ! 569: for (i=0; i<wcount; i++) ! 570: if (i==0 || wordcomp(word[i], word[i-1])!=0) { ! 571: p = word[i]; ! 572: while (isalpha(*++p)) ; ! 573: write (pipefd[1], word[i], p-word[i]); ! 574: } ! 575: close(pipefd[1]); ! 576: goodbye(0); ! 577: } ! 578: close(pipefd[1]); ! 579: rewind(dict); ! 580: getc(dict); ! 581: evalboard(getdword, aputword); ! 582: p = freesp; ! 583: while ((i = read(pipefd[0], freesp, 512)) != 0) { ! 584: if (i < 0) ! 585: if (errno != EINTR) ! 586: break; ! 587: else ! 588: i = 0; ! 589: freesp += i; ! 590: } ! 591: close(pipefd[0]); ! 592: ustart = ubotch = wcount; ! 593: while (p < freesp) { ! 594: word[wcount++] = p; ! 595: if (*p == '0') ! 596: ustart = wcount; ! 597: while (isalpha(*++p)); ! 598: } ! 599: wait(&status); ! 600: if (status != 0) ! 601: goodbye (5); ! 602: delct = 1; ! 603: printdiff(); ! 604: printboard(); ! 605: games++; ! 606: if (logfile >= 0) { ! 607: sprintf(&logbuff[0], "%4d", games); ! 608: lseek(logfile, logloc, 0); ! 609: write(logfile, &logbuff[0], 4); ! 610: } ! 611: stty (fileno(stdin), &tempttyb); ! 612: printf("\nanother game?"); ! 613: if (getchar() != 'y') { ! 614: putchar('\n'); ! 615: break; ! 616: } ! 617: stty (fileno(stdin), &tempttyb); ! 618: } ! 619: goodbye(0); ! 620: } ! 621: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.