/* * ********************* * * B O G G L E . C * * ********************* */ /*)BUILD $(PROGRAM) = boggle $(STACK) = 3000 $(TKBOPTIONS) = { STACK = 1024 ACTFIL = 6 UNITS = 6 } */ /* * * * * Written by: * Bob Denny * Creative System Design Co. * Pasadena, CA 91107 * * N O T E: * This version doesn't handle "Qu" cube face, * and it is for "Big Boggle", 5x5 board. * * Edits: * X02.00 25-Aug-81 RBD Major changes from 2 phase boggle. */ /* #define biggerdebug */ /* #define bigdebug */ /* #define debug */ #include #define UNUSED 0 #define USED 1 /* * Static data structures */ char board [5] [6]; /* BOGGLE board letter layout */ int flags [5] [5]; /* "letter used" flags for board */ char word [18]; /* Test word buffer */ char dicwrd[18]; /* Current dictionary word */ int maxw = 7; /* Max length word to generate */ int nwords = 0; /* No. of words generated */ long tstart, tstop; /* Start/stop times */ FILE *ofp; /* Output file */ FILE *dfp; /* Dictionary file */ /* * External functions which return other than integers */ extern char tolower(); extern long ftell(); extern long time(); /* * This turns off C's argv prompt */ #ifdef decus int $$narg = 1; #endif /* * Main program */ main(argc,argv) int argc; char *argv[]; { register int row, col; char ch; long dicpos; /* Dictionary file position */ #ifdef debug ofp = stdout; #else if((ofp = fopen("BOGGLE.OUT", "w")) == NULL) error("Failed to open output file BOGGLE.OUT\n"); #endif if((dfp = fopen("BOGGLE.DIC", "r")) == NULL) error("Failed to open dictionary file BOGGLE.DIC\n"); printf("Welcome to BOGGLE:\n"); printf("My words will be written to the screen and to file BOGGLE.OUT\n\n"); printf("Enter cube letters one row at a time:\n"); for(row=0; row<5; row++) { again: printf("Row %d: ", row); /* Prompt for a row */ gets(board[row]); /* Get a row */ for(col=0; col<5; col++) /* Fold to upper case */ { if(isalpha(board[row][col]) != TRUE) { printf("\"%c\" is not a letter!\n", board[row][col]); goto again; } else board[row][col] = tolower(board[row][col]); } } fprintf(ofp, "%c %c %c %c %c\n",board[0][0],board[0][1],board[0][2], board[0][3],board[0][4]); fprintf(ofp, "%c %c %c %c %c\n",board[1][0],board[1][1],board[1][2], board[1][3],board[1][4]); fprintf(ofp, "%c %c %c %c %c\n",board[2][0],board[2][1],board[2][2], board[2][3],board[2][4]); fprintf(ofp, "%c %c %c %c %c\n",board[3][0],board[3][1],board[3][2], board[3][3],board[3][4]); fprintf(ofp, "%c %c %c %c %c\n\n",board[4][0],board[4][1],board[4][2], board[4][3],board[4][4]); /* * Load first dictionary word. */ dicpos = 0; fgetss(dicwrd, 18, dfp); /* * Start words in ASCII order. */ printf("\nOK ... here goes\n"); tstart = time(0); /* Mark start time */ for(ch = 'a'; ch <= 'z'; ch++) /* ASCII dependent */ { while(dicwrd[0] < ch) /* Sync dictionary to start letter */ { dicpos = ftell(dfp); /* Save dict. position for start ltr */ fgetss(dicwrd, 18, dfp); } #ifdef debug printf("Checking for letter \'%c\' dict at \"%s\"\n", ch, dicwrd); #endif for(row = 0; row < 5; row++) for(col = 0; col<5; col++) if ((word[0] = board[row][col]) == ch) { fseek(dfp, dicpos, 0); /* Resync dictionary file */ clear(); /* Clear the flags board */ flags[row][col] = USED; /* Mark starting cell used */ #ifdef debug printf("Starting [%d,%d] = \"%c\"\n", row, col, ch); #endif extend(row, col, 0, dicpos); /* Gen/check words recursively */ } } fclose(dfp); #ifndef debug fclose(ofp); #endif tstop = time(0); printf("\nI\'m finished. %d words generated in %ld sec.\n", nwords, tstop-tstart); } /**** END OF MAIN PROGRAM ****/ /* * Clear out the flags board. Initialize all cells to UNUSED. */ clear() { register int row,col; for(row=0; row<5; row++) for(col=0; col<5; col++) flags[row][col] = UNUSED; } /* * Form possible words by recursive descent. * On entry, 'index' is the string index in 'word' of the * terminating character. */ extend(row, col, index, dicpos) int row, col, index; long dicpos; { register int i, j; int rowp1, colp1; register char ch; int cmpval; rowp1 = row + 1; colp1 = col + 1; if(index++ > maxw-2) return; /* Word too long. (bump index) */ #ifdef debug printf("Extend: Index = %d Word = \"%s\"\n", index, word); #endif for(ch = 'a'; ch <= 'z'; ch++) { word[index] = ch; /* Add this letter to word */ word[index+1] = '\0'; while(ccmp(dicwrd, word, index+1) < 0) /* Advance dict. appropriately */ { dicpos = ftell(dfp); /* Save dict. position for start ltr */ fgetss(dicwrd, 18, dfp); } #ifdef bigdebug printf(" ch = \'%c\' dict advanced to \"%s\"\n", ch, dicwrd); #endif for(i = row-1; i <= rowp1; i++) { if(i<0 || i>4) continue; /* Handle boundary conditions */ for(j = col-1; j <= colp1; j++) { #ifdef biggerdebug printf(" row %d, col %d\n", i, j); #endif if(j<0 || j>4) continue; /* Handle boundary conditions */ #ifdef biggerdebug i, j, flags[i][j], i, j, board[i][j]); #endif if(flags[i][j] == UNUSED && (board[i][j]) == ch) { #ifdef debug printf(" cell [%d,%d]:\n", i, j); printf(" trial word is \"%s\"\n", word); #endif fseek(dfp, dicpos, 0); /* Back up to prev. start point */ fgetss(dicwrd, 18, dfp); while((cmpval = ccmp(dicwrd, word, index+1)) < 0) /* Scan fwd. */ fgetss(dicwrd, 18, dfp); #ifdef debug printf(" dict resync'd to \"%s\"\n", dicwrd); #endif if(cmpval == 0) { if(dicwrd[index+1] == '\0') /* If they match exactly */ { fputss(dicwrd, ofp); /* Write out the good word */ puts(dicwrd); nwords++; /* Count a good word */ fgetss(dicwrd, 18, dfp); /* Get another dict. word */ } flags[i][j] = USED; /* Mark this cell used */ extend(i, j, index, dicpos);/* Try to extend the word */ flags[i][j] = UNUSED; /* Unmark the cell */ word[index+1] = '\0'; /* Chop the word back */ } } } } } #ifdef debug printf("----- end extend ----\n"); #endif } /**** WOW ****/ dummy() {} /* * ccmp() * * Compare first n characters in strings. * return like strcmp(). */ int ccmp(s1, s2, n) register char *s1; register char *s2; int n; { register int diff; while(n--) { if((diff = *s1++ - *s2++) != 0) return(diff); } return(0); }