Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

v04i001: bog - the game of boggle

2 views
Skip to first unread message

games-...@tekred.tek.com

unread,
Mar 9, 1988, 7:36:23 PM3/9/88
to
Submitted by: Barry Brachman <uunet!ubc-vision!cs.ubc.ca!brachman>
Comp.sources.games: Volume 4, Issue 1
Archive-name: bog

[I compiled and ran this OK on a Sun 3/60. -br]

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: README Makefile bog.man bog.h bog.c help.c mach.c mkdict.c
# mkindex.c prtable.c showdict.c timer.c word.c helpfile
# Wrapped by billr@saab on Tue Mar 1 17:16:48 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f README -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(2494 characters\)
sed "s/^X//" >README <<'END_OF_README'
X
XBog is a fairly portable simulation of Parker Brother's game of Boggle and
Xis similar to the 4.[23] BSD "boggle" and Sun's "boggletool".
XBog has not been derived from any proprietary code.
XIt has been tested on the Sun 3 under SunOS 3.2 and on the Atari 1040ST (MWC).
X
XWhat You Need
X
XYou will need curses/termcap and a large word list.
XThe minix word list or /usr/dict/words will do nicely.
XThe word list must already be sorted (you can use "sort -c" to check).
X
XContents
X
X README - this file
X Makefile
X bog.man - half-hearted man page (use the game's help command)
X bog.h - configuration and header info
X bog.c - machine independent game code
X word.c - machine independent word list routines
X help.c - (curses) help routine
X mach.c - (curses) display code
X prtable.c - ditto
X timer.c - machine dependent (os) input polling
X mkdict.c - convert a word list to a bog dictionary
X mkindex.c - create an index file for the bog dictionary
X showdict.c - print a bog dictionary to stdout
X
XPortability
X
X- I've tried to make bog.c (the program logic) independent of the I/O.
X My plan was to make it straightforward to adapt the game to run under a
X windowing system (eg., Suntools, GEM). I have no plan to actually do this.
X I've stuck to a small subset of the curses routines.
X- The program runs with the input in raw mode.
X- If you want the running timer you must #define TIMER in bog.h
X and insert the input polling code in timer.c for your system. There is
X already code there for BSD, SYSV, and ATARI.
X
XSetup
X
X1. Check bog.h and Makefile and edit to fit your environment
X2. "make all"
X This will make all the binaries and create the dictionary and index files
X3. Move "dict", "dict.ind", and "helpfile" to where you specified in bog.h
X4. Play away
X
XDistribution
X
XYou may use this software for your enjoyment and you may share it with others.
XYou may not sell this software or use it for any commercial purposes
Xwhatsoever. All modified versions of the software that you redistribute must
Xclearly indicate your changes.
X
XIf you come across any bugs or make any changes you'd like to share please
Xsend mail to me rather than posting to the net.
X
XEnjoy. [But beware: boggle can be addictive!]
X
X-----
XBarry Brachman | {ihnp4!alberta,uw-beaver,uunet}!
XDept. of Computer Science| ubc-vision!ubc-csgrads!brachman
XUniv. of British Columbia| brac...@grads.cs.ubc.cdn
XVancouver, B.C. V6T 1W5 | brachman%ubc....@csnet-relay.arpa
X(604) 228-4327 | brac...@ubc.csnet
X
END_OF_README
if test 2494 -ne `wc -c <README`; then
echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(830 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X
X# See bog.h for configuration
X
XOBJS=bog.o help.o mach.o prtable.o timer.o word.o
X
XCFLAGS=-O
XLIBS=-lcurses -ltermlib
X
X# DICT is the dictionary that will be used to construct the word list used
X# by bog
XDICT=/usr/dict/words
X
Xbog: $(OBJS)
X cc $(CFLAGS) -s -o bog $(OBJS) $(LIBS)
X
Xall: bog mkdict mkindex dict
X
Xmkdict: mkdict.c
X cc -s -O -o mkdict mkdict.c
X
Xmkindex: mkindex.c
X cc -s -O -o mkindex mkindex.c
X
Xshowdict: showdict.o word.o
X cc -s -O -o showdict showdict.o word.o
X rm -f showdict.o
X
Xdict: mkdict mkindex
X ./mkdict < $(DICT) > dict
X ./mkindex < dict > dict.ind
X
X$(OBJS): bog.h
X
Xinstall: all
X @echo "Move dict, dict.ind, and the helpfile to where you specified in bog.h"
X @echo "Move bog.man to where you want the manual page to go"
X
Xclean:
X rm -f *.o bog
X
Xlint:
X lint -abchx bog.c help.c mach.c prtable.c timer.c word.c
X
END_OF_Makefile
if test 830 -ne `wc -c <Makefile`; then
echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f bog.man -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"bog.man\"
else
echo shar: Extracting \"bog.man\" \(2748 characters\)
sed "s/^X//" >bog.man <<'END_OF_bog.man'
X.TH BOG 1-LOCAL "22 February 1988"
X.UC
X.SH NAME
Xbog \- Word search game
X.SH SYNOPSIS
Xbog [-b] [-d] [-s#] [-t#] [-w#] [+[+]] [boardspec]
X.br
Xmkdict
X.br
Xmkindex
X.SH DESCRIPTION
XThe object of
X.I bog
Xis to find as many words as possible on the Boggle board within the three
Xminute time limit.
XA Boggle board is a four by four arrangement of Boggle cubes, each side of
Xeach cube displaying a letter of the alphabet or `qu'.
XWords are formed by finding a sequence of cubes (letters) that are in the
Xgame's dictionary.
XThe (N+1)th cube in the word must be horizontally,
Xvertically, or diagonally adjacent to the Nth cube.
XCubes cannot be reused.
XWords consist solely of lower case letters and must be at least 3 letters long.
X.PP
XCommand line flags can be given to change the rules of the game.
XThe
X.B +
Xflag allows a cube to be used multiple times, but not in succession.
XThe
X.B ++
Xflag allows the same cubes to be considered adjacent to itself.
X.B
XA seed other than the time of day is specified by
X.B -s#,
Xwhere
X.B #
Xis the seed.
XThe time limit can be changed from the default 3 minutes by using the flag
X.B -t#,
Xwhere
X.B #
Xis the duration (in seconds) of each game.
XThe minimum word length can be changed from 3 letters by specifying
X.B -w#,
Xwhere
X.B #
Xis the minimum number of letters to use.
X.PP
XA starting board position can be specified on the command line by
Xlisting the board left to right and top to bottom.
X.PP
XThe
X.B -b
Xflag puts
X.I bog
Xin batch mode.
XA
X.B boardspec
Xmust also be given.
XThe dictionary is read from stdin and a list of words appearing in
X.B boardspec
Xis printed to stdout.
X.PP
XHelp is available during play by typing `?'.
XMore detailed information on the game is given there.
X.PP
X.I Mkdict
Xreads a word list from stdin, one word per line, and writes a dictionary
Xusable by
X.I bog
Xto stdout.
XThe dictionary is assumed to be sorted.
XImproper words are filtered out.
X.PP
X.I Mkindex
Xreads a dictionary produced by
X.I mkdict
Xfrom stdin
Xand writes an index file usable by
X.I bog
Xto stdout.
X.SH FILES
X.I Bog
Xaccesses a dictionary file, a dictionary index file, and a helpfile.
XLocations are system dependent.
XThe dictionary file must have been created by
X.I mkdict
Xand the index file by
X.I mkindex.
X.SH SEE ALSO
Xboggle(6), boggletool(6)
X.SH BUGS
XIf there are a great many words in the cube the final display of the words
Xmay scroll off of the screen. (On a 25 line screen about 130 words can be
Xdisplayed.)
X.sp 2
XNo word can contain a 'q' that is not immediately followed by a 'u'.
X.sp 2
XWhen using the '+' or '++' options the display of words found in the board
Xdoesn't indicate reused cubes.
X.SH AUTHOR
XBoggle is a trademark of Parker Brothers.
X.sp 2
XBarry Brachman
X.br
XDept. of Computer Science
X.br
XUniversity of British Columbia
END_OF_bog.man
if test 2748 -ne `wc -c <bog.man`; then
echo shar: \"bog.man\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f bog.h -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"bog.h\"
else
echo shar: Extracting \"bog.h\" \(1177 characters\)
sed "s/^X//" >bog.h <<'END_OF_bog.h'
X/* vi: set tabstop=4 : */
X
X/*
X * Configuration
X */
X
X#define BSD42 1 /* BSD 4.[23] */
X/* #define ATARI 1 /* Atari ST */
X/* #define SYSV 1 /* System V */
X
X/*
X * If you don't have random() and srandom() #define what you have
X */
X/* #define random lrand48 /* Sys V */
X/* #define srandom srand48 /* Sys V */
X
X/* #define random rand /* Not good but generally available */
X/* #define srandom(x) srand((int) x) /* */
X
X#define TIMER 1 /* Use tty polling (see timer.c) */
X#define LOADDICT 1 /* Load the dictionary for speed */
X
X#define DICT "/usr/cna/billr/games/bog/dict"
X#define DICTINDEX "/usr/cna/billr/games/bog/dict.ind"
X#define HELPFILE "/usr/cna/billr/games/bog/helpfile"
X
X/*
X * The theoretical maximum for MAXWORDLEN is ('a' - 1) == 96
X */
X#define MAXWORDLEN 40
X#define MAXPWORDS 200
X#define MAXMWORDS 200
X#define MAXPSPACE 2000
X#define MAXMSPACE 4000
X
X#define MAXCOLS 20
X
X#define PROMPT_COL 20
X#define PROMPT_LINE 2
X
X#define BOARD_COL 0
X#define BOARD_LINE 0
X
X#define SCORE_COL 20
X#define SCORE_LINE 0
X
X#define LIST_COL 0
X#define LIST_LINE 10
X
X#define TIMER_COL 20
X#define TIMER_LINE 2
X
Xstruct dictindex {
X long start;
X long length;
X};
X
END_OF_bog.h
if test 1177 -ne `wc -c <bog.h`; then
echo shar: \"bog.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f bog.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"bog.c\"
else
echo shar: Extracting \"bog.c\" \(13598 characters\)
sed "s/^X//" >bog.c <<'END_OF_bog.c'
X/* vi: set tabstop=4 : */
X
X#include "bog.h"
X
X#include <ctype.h>
X#include <stdio.h>
X
Xchar *version[] = "bog V1.0 brac...@ubc.csnet 23-Feb-88";
X
Xstruct dictindex dictindex[26];
X
X/*
X * Cube position numbering:
X *
X * 0 1 2 3
X * 4 5 6 7
X * 8 9 A B
X * C D E F
X */
Xstatic int adjacency[16][16] = {
X/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
X { 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 0 */
X { 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1 */
X { 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 2 */
X { 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 3 */
X { 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, /* 4 */
X { 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, /* 5 */
X { 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 }, /* 6 */
X { 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0 }, /* 7 */
X { 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0 }, /* 8 */
X { 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0 }, /* 9 */
X { 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1 }, /* A */
X { 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1 }, /* B */
X { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 }, /* C */
X { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0 }, /* D */
X { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1 }, /* E */
X { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 } /* F */
X};
X
Xstatic int letter_map[26][16];
X
Xchar board[17];
Xint wordpath[MAXWORDLEN + 1];
Xint wordlen; /* Length of last word returned by nextword() */
Xint usedbits;
X
Xchar *pword[MAXPWORDS], pwords[MAXPSPACE], *pwordsp;
Xint npwords;
X
Xchar *mword[MAXMWORDS], mwords[MAXMSPACE], *mwordsp;
Xint nmwords;
X
Xint ngames = 0;
Xint tnmwords = 0, tnpwords = 0;
X
X#ifdef TIMER
X#include <setjmp.h>
X
Xjmp_buf env;
X#endif TIMER
X
Xlong start_t;
X
Xstatic FILE *dictfp = (FILE *) NULL;
X
Xint batch;
Xint debug;
Xint minlength;
Xint reuse;
Xint tlimit;
X
Xchar *batchword(), *getline();
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X int done, i, selfuse;
X char *bspec, *p;
X long t;
X long atol();
X FILE *opendict();
X
X debug = 0;
X bspec = (char *) NULL;
X reuse = 0;
X batch = 0;
X selfuse = 0;
X minlength = 3;
X tlimit = 180; /* 3 minutes is standard */
X time(&t);
X
X for (i = 1; i < argc; i++) {
X if (argv[i][0] == '-') {
X switch (argv[i][1]) {
X case 'b':
X batch = 1;
X break;
X case 'd':
X debug = 1;
X break;
X case 's':
X t = atol(&argv[i][2]);
X break;
X case 't':
X if ((tlimit = atoi(&argv[i][2])) < 1) {
X (void) fprintf(stderr, "Bad time limit\n");
X exit(1);
X }
X break;
X case 'w':
X if ((minlength = atoi(&argv[i][2])) < 3) {
X (void) fprintf(stderr, "Min word length must be > 2\n");
X exit(1);
X }
X break;
X default:
X usage();
X /*NOTREACHED*/
X }
X }
X else if (strcmp(argv[i], "+") == 0)
X reuse = 1;
X else if (strcmp(argv[i], "++") == 0)
X selfuse = 1;
X else if (islower(argv[i][0])) {
X if (strlen(argv[i]) != 16) {
X usage();
X /*NOTREACHED*/
X }
X /* This board is assumed to be valid... */
X bspec = argv[i];
X }
X else {
X usage();
X /*NOREACHED*/
X }
X }
X
X if (batch && bspec == (char *) NULL) {
X (void) fprintf(stderr, "Must give both -b and a board setup\n");
X exit(1);
X }
X
X if (selfuse) {
X for (i = 0; i < 16; i++)
X adjacency[i][i] = 1;
X }
X
X if (batch) {
X newgame(bspec);
X while ((p = batchword(stdin)) != (char *) NULL)
X (void) printf("%s\n", p);
X }
X else {
X if (debug)
X (void) printf("seed = %ld\n", t);
X setup();
X prompt("Loading the dictionary...");
X if ((dictfp = opendict(DICT)) == (FILE *) NULL) {
X (void) fprintf(stderr, "Can't load %s\n", DICT);
X cleanup();
X exit(1);
X }
X#ifdef LOADDICT
X if (loaddict(dictfp) < 0) {
X (void) fprintf(stderr, "Can't load %s\n", DICT);
X cleanup();
X exit(1);
X }
X (void) fclose(dictfp);
X dictfp = (FILE *) NULL;
X#endif
X if (loadindex(DICTINDEX) < 0) {
X (void) fprintf(stderr, "Can't load %s\n", DICTINDEX);
X cleanup();
X exit(1);
X }
X srandom(t);
X
X prompt("Type <space> to begin...");
X while (inputch() != ' ')
X ;
X
X done = 0;
X while (!done) {
X newgame(bspec);
X bspec = (char *) NULL; /* reset for subsequent games */
X playgame();
X prompt("Type <space> to continue, any cap to quit...");
X flushin(stdin);
X while (1) {
X int ch;
X
X ch = inputch();
X if (ch == '\033')
X findword();
X else {
X if (isupper(ch)) {
X done = 1;
X break;
X }
X if (ch == ' ')
X break;
X }
X }
X }
X cleanup();
X }
X exit(0);
X}
X
X/*
X * Read a line from the given stream and check if it is legal
X * Return a pointer to a legal word or a null pointer when EOF is reached
X */
Xchar *
Xbatchword(fp)
XFILE *fp;
X{
X register int *p, *q;
X register char *w;
X char *nextword();
X
X q = &wordpath[MAXWORDLEN + 1];
X p = wordpath;
X while (p < q)
X *p++ = -1;
X while ((w = nextword(fp)) != (char *) NULL) {
X if (wordlen < minlength)
X continue;
X p = wordpath;
X while (p < q && *p != -1)
X *p++ = -1;
X usedbits = 0;
X if (checkword(w, -1, wordpath) != -1)
X return(w);
X }
X return((char *) NULL);
X}
X
X/*
X * Play a single game
X * Reset the word lists from last game
X * Keep track of the running stats
X */
Xplaygame()
X{
X /* Can't use register variables if setjmp() is used! */
X int i, *p, *q;
X long t;
X char buf[MAXWORDLEN + 1];
X int compar();
X
X ngames++;
X npwords = 0;
X pwordsp = pwords;
X nmwords = 0;
X mwordsp = mwords;
X
X time(&start_t);
X
X q = &wordpath[MAXWORDLEN + 1];
X p = wordpath;
X while (p < q)
X *p++ = -1;
X showboard(board);
X startwords();
X if (setjmp(env)) {
X badword();
X goto timesup;
X }
X
X while (1) {
X if (getline(buf) == (char *) NULL) {
X if (feof(stdin))
X clearerr(stdin);
X break;
X }
X time(&t);
X if (t - start_t >= tlimit) {
X badword();
X break;
X }
X if (buf[0] == '\0') {
X int remaining;
X
X remaining = tlimit - (int) (t - start_t);
X (void) sprintf(buf, "%d:%02d", remaining / 60, remaining % 60);
X showstr(buf, 1);
X continue;
X }
X if (strlen(buf) < minlength) {
X badword();
X continue;
X }
X
X p = wordpath;
X while (p < q && *p != -1)
X *p++ = -1;
X usedbits = 0;
X
X if (checkword(buf, -1, wordpath) < 0)
X badword();
X else {
X if (debug) {
X (void) printf("[");
X for (i = 0; wordpath[i] != -1; i++)
X (void) printf(" %d", wordpath[i]);
X (void) printf(" ]\n");
X }
X for (i = 0; i < npwords; i++) {
X if (strcmp(pword[i], buf) == 0)
X break;
X }
X if (i != npwords) { /* already used the word */
X badword();
X showword(i);
X }
X else if (!validword(buf))
X badword();
X else {
X int len;
X
X len = strlen(buf) + 1;
X if (npwords == MAXPWORDS - 1 ||
X pwordsp + len >= &pwords[MAXPSPACE]) {
X (void) fprintf(stderr, "Too many words!\n");
X cleanup();
X exit(1);
X }
X pword[npwords++] = pwordsp;
X (void) strcpy(pwordsp, buf);
X pwordsp += len;
X addword(buf);
X }
X }
X }
X
Xtimesup: ;
X
X /*
X * Sort the player's words and terminate the list with a null
X * entry to help out checkdict()
X */
X qsort(pword, npwords, sizeof(pword[0]), compar);
X pword[npwords] = (char *) NULL;
X
X /*
X * These words don't need to be sorted since the dictionary is sorted
X */
X checkdict();
X
X tnmwords += nmwords;
X tnpwords += npwords;
X
X results();
X}
X
X/*
X * Check if the given word is present on the board, with the constraint
X * that the first letter of the word is adjacent to square 'prev'
X * Keep track of the current path of squares for the word
X * A 'q' must be followed by a 'u'
X * Words must end with a null
X * Return 1 on success, -1 on failure
X */
Xcheckword(word, prev, path)
Xchar *word;
Xint prev, *path;
X{
X register char *p, *q;
X register int i, *lm;
X
X if (debug) {
X (void) printf("checkword(%s, %d, [", word, prev);
X for (i = 0; wordpath[i] != -1; i++)
X (void) printf(" %d", wordpath[i]);
X (void) printf(" ]\n");
X }
X
X if (*word == '\0')
X return(1);
X
X lm = letter_map[*word - 'a'];
X
X if (prev == -1) {
X char subword[MAXWORDLEN + 1];
X
X /*
X * Check for letters not appearing in the cube to eliminate some
X * recursive calls
X * Fold 'qu' into 'q'
X */
X p = word;
X q = subword;
X while (*p != '\0') {
X if (*letter_map[*p - 'a'] == -1)
X return(-1);
X *q++ = *p;
X if (*p++ == 'q') {
X if (*p++ != 'u')
X return(-1);
X }
X }
X *q = '\0';
X while (*lm != -1) {
X *path = *lm;
X usedbits |= (1 << *lm);
X if (checkword(subword + 1, *lm, path + 1) > 0)
X return(1);
X usedbits &= ~(1 << *lm);
X lm++;
X }
X return(-1);
X }
X
X /*
X * A cube is only adjacent to itself in the adjacency matrix if selfuse
X * was set, so a cube can't be used twice in succession if only the reuse
X * flag is set
X */
X for (i = 0; lm[i] != -1; i++) {
X if (adjacency[prev][lm[i]]) {
X int used;
X
X used = 1 << lm[i];
X /* If necessary, check if the square has already been used */
X if (!reuse && (usedbits & used))
X continue;
X *path = lm[i];
X usedbits |= used;
X if (checkword(word + 1, lm[i], path + 1) > 0)
X return(1);
X usedbits &= ~used;
X }
X }
X *path = -1; /* in case of a backtrack */
X return(-1);
X}
X
X/*
X * A word is invalid if it is not in the dictionary
X * At this point it is already known that the word can be formed from
X * the current board
X */
Xvalidword(word)
Xchar *word;
X{
X register int j;
X register char *q, *w;
X char *nextword();
X
X j = word[0] - 'a';
X if (dictseek(dictfp, dictindex[j].start, 0) < 0) {
X (void) fprintf(stderr, "Seek error\n");
X cleanup();
X exit(1);
X }
X
X while ((w = nextword(dictfp)) != (char *) NULL) {
X int ch;
X
X if (*w != word[0]) /* end of words starting with word[0] */
X break;
X q = word;
X while ((ch = *w++) == *q++ && ch != '\0')
X ;
X if (*(w - 1) == '\0' && *(q - 1) == '\0')
X return(1);
X }
X if (dictfp != (FILE *) NULL && feof(dictfp)) /* Special case for z's */
X clearerr(dictfp);
X return(0);
X}
X
X/*
X * Check each word in the dictionary against the board
X * Delete words from the machine list that the player has found
X * Assume both the dictionary and the player's words are already sorted
X */
Xcheckdict()
X{
X register char *p, **pw, *w;
X register int i;
X int prevch, previndex, *pi, *qi, st;
X
X mwordsp = mwords;
X nmwords = 0;
X pw = pword;
X prevch ='a';
X qi = &wordpath[MAXWORDLEN + 1];
X
X (void) dictseek(dictfp, 0L, 0);
X while ((w = nextword(dictfp)) != (char *) NULL) {
X if (wordlen < minlength)
X continue;
X if (*w != prevch) {
X /*
X * If we've moved on to a word with a different first letter
X * then we can speed things up by skipping all words starting
X * with a letter that doesn't appear in the cube
X */
X i = (int) (*w - 'a');
X while (i < 26 && letter_map[i][0] == -1)
X i++;
X if (i == 26)
X break;
X previndex = prevch - 'a';
X prevch = i + 'a';
X /*
X * Fall through if the word's first letter appears in the cube
X * (i.e., if we can't skip ahead), otherwise seek to the
X * beginning of words in the dictionary starting with the
X * next letter (alphabetically) appearing in the cube and then
X * read the first word
X */
X if (i != previndex + 1) {
X if (dictseek(dictfp, dictindex[i].start, 0) < 0) {
X (void) fprintf(stderr, "Seek error in checkdict()\n");
X cleanup();
X exit(1);
X }
X continue;
X }
X }
X
X pi = wordpath;
X while (pi < qi && *pi != -1)
X *pi++ = -1;
X usedbits = 0;
X if (checkword(w, -1, wordpath) == -1)
X continue;
X
X st = 1;
X while (*pw != (char *) NULL && (st = strcmp(*pw, w)) < 0)
X pw++;
X if (st == 0) /* found it */
X continue;
X if (nmwords == MAXMWORDS ||
X mwordsp + wordlen + 1 >= &mwords[MAXMSPACE]) {
X (void) fprintf(stderr, "Too many words!\n");
X cleanup();
X exit(1);
X }
X mword[nmwords++] = mwordsp;
X p = w;
X while (*mwordsp++ = *p++)
X ;
X }
X}
X
X/*
X * Crank up a new game
X * If the argument is non-null then it is assumed to be a legal board spec
X * in ascending cube order, oth. make a random board
X */
Xnewgame(b)
Xchar *b;
X{
X register int i, p, q;
X char *tmp;
X int *lm[26];
X long random();
X static char *cubes[16] = {
X "ednosw", "aaciot", "acelrs", "ehinps",
X "eefhiy", "elpstu", "acdemp", "gilruw",
X "egkluy", "ahmors", "abilty", "adenvz",
X "bfiorx", "dknotu", "abjmoq", "egintv"
X };
X
X if (b == (char *) NULL) {
X /*
X * Shake the cubes and make the board
X */
X i = 0;
X while (i < 100) {
X p = (int) (random() % 16);
X q = (int) (random() % 16);
X if (p != q) {
X tmp = cubes[p];
X cubes[p] = cubes[q];
X cubes[q] = tmp;
X i++;
X }
X /* else try again */
X }
X
X for (i = 0; i < 16; i++)
X board[i] = cubes[i][random() % 6];
X }
X else {
X for (i = 0; i < 16; i++)
X board[i] = b[i];
X }
X board[16] = '\0';
X
X /*
X * Set up the map from letter to location(s)
X * Each list is terminated by a -1 entry
X */
X for (i = 0; i < 26; i++) {
X lm[i] = letter_map[i];
X *lm[i] = -1;
X }
X
X for (i = 0; i < 16; i++) {
X register int j;
X
X j = (int) (board[i] - 'a');
X *lm[j] = i;
X *(++lm[j]) = -1;
X }
X
X if (debug) {
X for (i = 0; i < 26; i++) {
X int ch, j;
X
X (void) printf("%c:", 'a' + i);
X for (j = 0; (ch = letter_map[i][j]) != -1; j++)
X (void) printf(" %d", ch);
X (void) printf("\n");
X }
X }
X
X}
X
Xcompar(p, q)
Xchar **p, **q;
X{
X return(strcmp(*p, *q));
X}
X
Xusage()
X{
X(void) fprintf(stderr,
X"Usage: bog [-b] [-d] [-s#] [-t#] [-w#] [+[+]] [boardspec]\n");
X(void) fprintf(stderr, "-b: 'batch mode' (boardspec must be present)\n");
X(void) fprintf(stderr, "-d: debug\n");
X(void) fprintf(stderr, "-s#: use # as the random number seed\n");
X(void) fprintf(stderr, "-t#: time limit is # seconds\n");
X(void) fprintf(stderr, "-w#: minimum word length is # letters\n");
X(void) fprintf(stderr, "+: can reuse a cube, but not twice in succession\n");
X(void) fprintf(stderr, "++: can reuse cubes arbitrarily\n");
X(void) fprintf(stderr, "boardspec: the first board to use (use 'q' for 'qu')\n");
X exit(1);
X}
X
END_OF_bog.c
if test 13598 -ne `wc -c <bog.c`; then
echo shar: \"bog.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f help.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"help.c\"
else
echo shar: Extracting \"help.c\" \(1149 characters\)
sed "s/^X//" >help.c <<'END_OF_help.c'
X/* vi: set tabstop=4 : */
X
X#include <curses.h>
X#include <stdio.h>
X
X#include "bog.h"
X
Xhelp()
X{
X int eof, i;
X FILE *fp;
X WINDOW *win;
X char buf[BUFSIZ];
X extern int ncols, nlines;
X
X if ((fp = fopen(HELPFILE, "r")) == (FILE *) NULL)
X return(-1);
X win = newwin(0, 0, 0, 0);
X clearok(win, 1);
X
X eof = 0;
X if (ungetc(getc(fp), fp) == EOF) {
X wprintw(win, "There doesn't seem to be any help.");
X eof = 1; /* Nothing there... */
X }
X
X while (!eof) {
X for (i = 0; i < nlines - 3; i++) {
X if (fgets(buf, sizeof(buf), fp) == (char *) NULL) {
X eof = 1;
X break;
X }
X if (buf[0] == '.' && buf[1] == '\n')
X break;
X wprintw(win, "%s", buf);
X }
X if (eof || ungetc(getc(fp), fp) == EOF) {
X eof = 1;
X break;
X }
X wmove(win, nlines - 1, 0);
X wprintw(win, "Type <space> to continue, anything else to quit...");
X wrefresh(win);
X if ((inputch() & 0177) != ' ')
X break;
X wclear(win);
X }
X
X fclose(fp);
X if (eof) {
X extern char *version;
X
X wprintw(win, "%s", version);
X wmove(win, nlines - 1, 0);
X wprintw(win, "Hit any key to continue...");
X wrefresh(win);
X inputch();
X }
X delwin(win);
X clearok(stdscr, 1);
X refresh();
X return(0);
X}
X
END_OF_help.c
if test 1149 -ne `wc -c <help.c`; then
echo shar: \"help.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f mach.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"mach.c\"
else
echo shar: Extracting \"mach.c\" \(10502 characters\)
sed "s/^X//" >mach.c <<'END_OF_mach.c'
X/* vi: set tabstop=4 : */
X
X/*
X * Terminal interface
X *
X * Input is raw and unechoed
X */
X
X#ifdef unix
X#include <sgtty.h>
X#endif
X#include <signal.h>
X#include <curses.h>
X#include <ctype.h>
X#include <stdio.h>
X
X#include "bog.h"
X
Xstatic int ccol, crow, maxw;
Xstatic int colstarts[MAXCOLS], ncolstarts;
Xstatic int lastline;
Xint ncols, nlines;
X
X/*
X * Do system dependent initialization
X * This is called once, when the program starts
X */
Xsetup()
X{
X
X if (tty_setup() < 0)
X return(-1);
X return(0);
X}
X
X/*
X * Do system dependent clean up
X * This is called once, just before the program terminates
X */
Xcleanup()
X{
X
X tty_cleanup();
X}
X
X/*
X * Display the player's word list, the list of words not found, and the running
X * stats
X */
Xresults()
X{
X int col, row;
X int denom1, denom2;
X extern int ngames, nmwords, npwords, tnmwords, tnpwords;
X extern char *pword[], *mword[];
X int prwidth(), prword();
X
X move(LIST_LINE, LIST_COL);
X clrtobot();
X printw("Words you found (%d):", npwords);
X refresh();
X move(LIST_LINE + 1, LIST_COL);
X prtable(pword, npwords, 0, ncols, prword, prwidth);
X
X getyx(stdscr, row, col);
X move(row + 1, col);
X printw("Words you missed (%d):", nmwords);
X refresh();
X move(row + 2, col);
X prtable(mword, nmwords, 0, ncols, prword, prwidth);
X
X denom1 = npwords + nmwords;
X denom2 = tnpwords + tnmwords;
X
X move(SCORE_LINE, SCORE_COL);
X printw("Percentage: %0.2f%% (%0.2f%% over %d game%s)\n",
X denom1 ? (100.0 * npwords) / (double) (npwords + nmwords) : 0.0,
X denom2 ? (100.0 * tnpwords) / (double) (tnpwords + tnmwords) : 0.0,
X ngames, ngames > 1 ? "s" : "");
X}
X
Xstatic
Xprword(base, index)
Xchar **base;
Xint index;
X{
X
X printw("%s", base[index]);
X}
X
Xstatic
Xprwidth(base, index)
Xchar **base;
Xint index;
X{
X
X return(strlen(base[index]));
X}
X
X/*
X * Main input routine
X *
X * - doesn't accept words longer than MAXWORDLEN or containing caps
X */
Xchar *
Xgetline(q)
Xchar *q;
X{
X register int ch, done;
X register char *p;
X int row, col;
X
X p = q;
X done = 0;
X while (!done) {
X ch = rawch();
X switch (ch) {
X case '\n':
X case '\r':
X case ' ':
X done = 1;
X break;
X case '\033':
X findword();
X break;
X case '\177': /* <del> */
X case '\010': /* <bs> */
X if (p == q)
X break;
X p--;
X getyx(stdscr, row, col);
X move(row, col - 1);
X clrtoeol();
X refresh();
X break;
X case '\025': /* <^u> */
X case '\027': /* <^w> */
X if (p == q)
X break;
X getyx(stdscr, row, col);
X move(row, col - (int) (p - q));
X p = q;
X clrtoeol();
X refresh();
X break;
X#ifdef SIGTSTP
X case '\032': /* <^z> */
X stop_catcher();
X break;
X#endif
X case '\023': /* <^s> */
X stoptime();
X printw("<PAUSE>");
X refresh();
X while ((ch = inputch()) != '\021' && ch != '\023')
X ;
X move(crow, ccol);
X clrtoeol();
X refresh();
X starttime();
X break;
X case '\003': /* <^c> */
X cleanup();
X exit(0);
X /*NOTREACHED*/
X case '\004': /* <^d> */
X done = 1;
X ch = EOF;
X break;
X case '\014': /* <^l> */
X case '\022': /* <^r> */
X clearok(stdscr, 1);
X refresh();
X break;
X case '?':
X stoptime();
X if (help() < 0)
X showstr("Can't open help file", 1);
X starttime();
X break;
X default:
X if (!islower(ch))
X break;
X if ((int) (p - q) == MAXWORDLEN) {
X p = q;
X badword();
X break;
X }
X *p++ = ch;
X addch(ch);
X refresh();
X break;
X }
X }
X *p = '\0';
X if (ch == EOF)
X return((char *) NULL);
X return(q);
X}
X
Xinputch()
X{
X
X return(getch() & 0177);
X}
X
X#ifdef XXX
X/*
X * Flush all pending input
X */
Xflushin(fp)
XFILE *fp;
X{
X
X flushinp();
X}
X#endif XXX
X
X#ifdef TIOCFLUSH
X#include <sys/file.h>
X
Xflushin(fp)
XFILE *fp;
X{
X int arg;
X
X arg = FREAD;
X (void) ioctl(fileno(fp), TIOCFLUSH, &arg);
X}
X#endif TIOCFLUSH
X
X#ifdef ATARI
X#include <osbind.h>
X
X/*ARGSUSED*/
Xflushin(fp)
XFILE *fp;
X{
X
X while (Cconis() == -1)
X ;
X}
X#endif ATARI
X
Xstatic int gone;
X
X/*
X * Stop the game timer
X */
Xstoptime()
X{
X long t;
X extern long start_t;
X
X time(&t);
X gone = (int) (t - start_t);
X}
X
X/*
X * Restart the game timer
X */
Xstarttime()
X{
X long t;
X extern long start_t;
X
X time(&t);
X start_t = t - (long) gone;
X}
X
X/*
X * Initialize for the display of the player's words as they are typed
X * This display starts at (LIST_LINE, LIST_COL) and goes "down" until the last
X * line. After the last line a new column is started at LIST_LINE
X * Keep track of each column position for showword()
X * There is no check for exceeding COLS
X */
Xstartwords()
X{
X
X crow = LIST_LINE;
X ccol = LIST_COL;
X maxw = 0;
X ncolstarts = 1;
X colstarts[0] = LIST_COL;
X move(LIST_LINE, LIST_COL);
X refresh();
X}
X
X/*
X * Add a word to the list and start a new column if necessary
X * The maximum width of the current column is maintained so we know where
X * to start the next column
X */
Xaddword(w)
Xchar *w;
X{
X int n;
X
X if (crow == lastline) {
X crow = LIST_LINE;
X ccol += (maxw + 5);
X colstarts[ncolstarts++] = ccol;
X maxw = 0;
X move(crow, ccol);
X }
X else {
X move(++crow, ccol);
X if ((n = strlen(w)) > maxw)
X maxw = n;
X }
X refresh();
X}
X
X/*
X * The current word is unacceptable so erase it
X */
Xbadword()
X{
X
X move(crow, ccol);
X clrtoeol();
X refresh();
X}
X
X/*
X * Highlight the nth word in the list (starting with word 0)
X * No check for wild arg
X */
Xshowword(n)
Xint n;
X{
X int col, row;
X
X row = LIST_LINE + n % (lastline - LIST_LINE + 1);
X col = colstarts[n / (lastline - LIST_LINE + 1)];
X move(row, col);
X standout();
X printw("%s", pword[n]);
X standend();
X move(crow, ccol);
X refresh();
X sleep(1);
X move(row, col);
X printw("%s", pword[n]);
X move(crow, ccol);
X refresh();
X}
X
X/*
X * Get a word from the user and check if it is in either of the two
X * word lists
X * If it's found, show the word on the board for a short time and then
X * erase the word
X *
X * Note: this function knows about the format of the board
X */
Xfindword()
X{
X int c, col, found, i, r, row;
X char buf[MAXWORDLEN + 1];
X extern char board[];
X extern int usedbits, wordpath[];
X extern char *mword[], *pword[];
X extern int nmwords, npwords;
X
X getyx(stdscr, r, c);
X getword(buf);
X found = 0;
X for (i = 0; i < npwords; i++) {
X if (strcmp(buf, pword[i]) == 0) {
X found = 1;
X break;
X }
X }
X if (!found) {
X for (i = 0; i < nmwords; i++) {
X if (strcmp(buf, mword[i]) == 0) {
X found = 1;
X break;
X }
X }
X }
X for (i = 0; i < MAXWORDLEN; i++)
X wordpath[i] = -1;
X usedbits = 0;
X if (!found || checkword(buf, -1, wordpath) == -1) {
X move(r, c);
X clrtoeol();
X addstr("[???]");
X refresh();
X sleep(1);
X move(r, c);
X clrtoeol();
X refresh();
X return;
X }
X
X standout();
X for (i = 0; wordpath[i] != -1; i++) {
X row = BOARD_LINE + (wordpath[i] / 4) * 2 + 1;
X col = BOARD_COL + (wordpath[i] % 4) * 4 + 2;
X move(row, col);
X if (board[wordpath[i]] == 'q')
X printw("Qu");
X else
X printw("%c", toupper(board[wordpath[i]]));
X move(r, c);
X refresh();
X sleep(1);
X }
X
X standend();
X
X for (i = 0; wordpath[i] != -1; i++) {
X row = BOARD_LINE + (wordpath[i] / 4) * 2 + 1;
X col = BOARD_COL + (wordpath[i] % 4) * 4 + 2;
X move(row, col);
X if (board[wordpath[i]] == 'q')
X printw("Qu");
X else
X printw("%c", toupper(board[wordpath[i]]));
X }
X move(r, c);
X clrtoeol();
X refresh();
X}
X
X/*
X * Display a string at the current cursor position for the given number of secs
X */
Xshowstr(str, delay)
Xchar *str;
Xint delay;
X{
X
X addstr(str);
X refresh();
X sleep(delay);
X move(crow, ccol);
X clrtoeol();
X refresh();
X}
X
Xputstr(s)
Xchar *s;
X{
X
X addstr(s);
X}
X
X/*
X * Get a valid word and put it in the buffer
X */
Xgetword(q)
Xchar *q;
X{
X int ch, col, done, i, row;
X char *p;
X
X done = 0;
X i = 0;
X p = q;
X addch('[');
X refresh();
X while (!done && i < MAXWORDLEN - 1) {
X ch = getch() & 0177;
X switch (ch) {
X case '\177': /* <del> */
X case '\010': /* <bs> */
X if (p == q)
X break;
X p--;
X getyx(stdscr, row, col);
X move(row, col - 1);
X clrtoeol();
X break;
X case '\025': /* <^u> */
X case '\027': /* <^w> */
X if (p == q)
X break;
X getyx(stdscr, row, col);
X move(row, col - (int) (p - q));
X p = q;
X clrtoeol();
X break;
X case ' ':
X case '\n':
X case '\r':
X done = 1;
X break;
X case '\014': /* <^l> */
X case '\022': /* <^r> */
X clearok(stdscr, 1);
X refresh();
X break;
X default:
X if (islower(ch)) {
X *p++ = ch;
X addch(ch);
X i++;
X }
X break;
X }
X refresh();
X }
X *p = '\0';
X addch(']');
X refresh();
X}
X
Xshowboard(b)
Xchar *b;
X{
X
X tty_showboard(b);
X}
X
Xprompt(mesg)
Xchar *mesg;
X{
X
X move(PROMPT_LINE, PROMPT_COL);
X printw("%s", mesg);
X move(PROMPT_LINE + 1, PROMPT_COL);
X refresh();
X}
X
Xrawch()
X{
X
X#ifdef TIMER
X return(timerch());
X#else
X return(getch() & 0177);
X#endif
X}
X
Xstatic
Xtty_setup()
X{
X#ifdef SIGTSTP
X int stop_catcher(), cont_catcher();
X#endif
X#ifdef TIOCGWINSZ
X int winch_catcher();
X#endif
X
X initscr();
X raw();
X noecho();
X
X /*
X * Does curses look at the winsize structure?
X * Should handle SIGWINCH ...
X */
X nlines = LINES;
X lastline = nlines - 1;
X ncols = COLS;
X
X#ifdef SIGTSTP
X (void) signal(SIGTSTP, stop_catcher);
X (void) signal(SIGCONT, cont_catcher);
X#endif
X#ifdef TIOCGWINSZ
X (void) signal(SIGWINCH, winch_catcher);
X#endif
X
X return(0);
X}
X
X#ifdef SIGTSTP
Xstatic
Xstop_catcher()
X{
X
X stoptime();
X noraw();
X echo();
X move(nlines - 1, 0);
X refresh();
X
X (void) signal(SIGTSTP, SIG_DFL);
X#ifdef BSD42
X (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP-1)));
X#endif
X (void) kill(0, SIGTSTP);
X (void) signal(SIGTSTP, stop_catcher);
X}
X
Xstatic
Xcont_catcher()
X{
X
X (void) signal(SIGCONT, cont_catcher);
X noecho();
X raw();
X clearok(stdscr, 1);
X move(crow, ccol);
X refresh();
X starttime();
X}
X#endif SIGTSTP
X
X#ifdef SIGWINCH
X/*
X * The signal is caught but nothing is done about it...
X * It would mean reformatting the entire display
X */
Xstatic
Xwinch_catcher()
X{
X
X struct winsize win;
X
X (void) signal(SIGWINCH, winch_catcher);
X (void) ioctl(fileno(stdout), TIOCGWINSZ, &win);
X /*
X LINES = win.ws_row;
X COLS = win.ws_col;
X */
X}
X#endif
X
Xstatic
Xtty_cleanup()
X{
X
X move(nlines - 1, 0);
X refresh();
X noraw();
X echo();
X endwin();
X}
X
Xstatic
Xtty_showboard(b)
Xchar *b;
X{
X register int i;
X int line;
X
X clear();
X move(BOARD_LINE, BOARD_COL);
X line = BOARD_LINE;
X printw("+---+---+---+---+");
X move(++line, BOARD_COL);
X for (i = 0; i < 16; i++) {
X if (b[i] == 'q')
X printw("| Qu");
X else
X printw("| %c ", toupper(b[i]));
X if ((i + 1) % 4 == 0) {
X printw("|");
X move(++line, BOARD_COL);
X printw("+---+---+---+---+");
X move(++line, BOARD_COL);
X }
X }
X move(SCORE_LINE, SCORE_COL);
X printw("Type '?' for help");
X refresh();
X}
X
Xstatic
Xtty_prompt(p)
Xchar *p;
X{
X
X move(PROMPT_LINE, PROMPT_COL);
X printw("%s", p);
X clrtoeol();
X refresh();
X}
X
END_OF_mach.c
if test 10502 -ne `wc -c <mach.c`; then
echo shar: \"mach.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f mkdict.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"mkdict.c\"
else
echo shar: Extracting \"mkdict.c\" \(1207 characters\)
sed "s/^X//" >mkdict.c <<'END_OF_mkdict.c'
X/* vi: set tabstop=4 : */
X
X/*
X * Filter out words that:
X * 1) Are not completely made up of lower case letters
X * 2) Contain a 'q' not immediately followed by a 'u'
X * 3) Are less that 3 characters long
X * 4) Are greater than MAXWORDLEN characters long
X */
X
X#include <ctype.h>
X#include <stdio.h>
X
X#include "bog.h"
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X register char *p, *q, *r;
X register int ch, common, i, n;
X int current, len, prev, qcount;
X char buf[2][MAXWORDLEN + 1];
X
X prev = 0;
X current = 1;
X buf[prev][0] = '\0';
X if (argc == 2)
X n = atoi(argv[1]);
X i = 1;
X while (gets(buf[current]) != (char *) NULL) {
X if (argc == 2 && i++ % n)
X continue;
X len = 0;
X for (p = buf[current]; *p != '\0'; p++) {
X if (!islower(*p))
X break;
X if (*p == 'q') {
X q = p + 1;
X if (*q != 'u')
X break;
X else {
X while (*q = *(q + 1))
X q++;
X }
X len++;
X }
X len++;
X }
X if (*p != '\0' || len < 3 || len > MAXWORDLEN)
X continue;
X
X p = buf[current];
X q = buf[prev];
X qcount = 0;
X while ((ch = *p++) == *q++ && ch != '\0')
X if (ch == 'q')
X qcount++;
X common = p - buf[current] - 1;
X printf("%c%s", common + qcount, p - 1);
X prev = !prev;
X current = !current;
X }
X}
X
END_OF_mkdict.c
if test 1207 -ne `wc -c <mkdict.c`; then
echo shar: \"mkdict.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f mkindex.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"mkindex.c\"
else
echo shar: Extracting \"mkindex.c\" \(1377 characters\)
sed "s/^X//" >mkindex.c <<'END_OF_mkindex.c'
X/* vi: set tabstop=4 : */
X
X#include <stdio.h>
X
X#include "bog.h"
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X int clen, rlen, prev;
X long off, start;
X char buf[MAXWORDLEN + 1], *p, *nextword();
X
X prev = '\0';
X off = start = 0L;
X while (nextword(stdin, buf, &clen, &rlen) != (char *) NULL) {
X if (*buf != prev) {
X if (prev != '\0')
X printf("%c %6ld %6ld\n", prev, start, off - 1);
X prev = *buf;
X start = off;
X }
X off += clen + 1;
X }
X printf("%c %6ld %6ld\n", prev, start, off - 1);
X}
X
X/*
X * Return the next word in the compressed dictionary in 'buffer' or
X * NULL on end-of-file
X * Also set clen to the length of the compressed word (for mkindex) and
X * rlen to the strlen() of the real word
X */
Xchar *
Xnextword(fp, buffer, clen, rlen)
XFILE *fp;
Xchar *buffer;
Xint *clen, *rlen;
X{
X register int ch, pcount;
X register char *p, *q;
X static char buf[MAXWORDLEN + 1];
X static int first = 1;
X static int lastch = 0;
X
X if (first) {
X if ((pcount = getc(fp)) == EOF)
X return((char *) NULL);
X first = 0;
X }
X else if ((pcount = lastch) == EOF)
X return((char *) NULL);
X
X p = buf + (*clen = pcount);
X
X while ((ch = getc(fp)) != EOF && ch >= 'a')
X *p++ = ch;
X lastch = ch;
X *p = '\0';
X
X *rlen = (int) (p - buf);
X *clen = *rlen - *clen;
X
X p = buf;
X q = buffer;
X while ((*q++ = *p) != '\0') {
X if (*p++ == 'q')
X *q++ = 'u';
X }
X return(buffer);
X}
X
END_OF_mkindex.c
if test 1377 -ne `wc -c <mkindex.c`; then
echo shar: \"mkindex.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f prtable.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"prtable.c\"
else
echo shar: Extracting \"prtable.c\" \(2164 characters\)
sed "s/^X//" >prtable.c <<'END_OF_prtable.c'
X/* vi: set tabstop=4 : */
X
X#include <curses.h>
X
X#define NCOLS 5
X
X/*
X * Routine to print a table
X * Modified from 'ls.c' mods (BJB/83)
X * Arguments:
X * base - address of first entry
X * num - number of entries
X * d_cols - number of columns to use if > 0, "best" size if == 0
X * width - max line width if not zero
X * prentry - address of the routine to call to print the string
X * length - address of the routine to call to determine the length
X * of string to be printed
X *
X * prtable and length are called with the the address of the base and
X * an index
X */
Xprtable(base, num, d_cols, width, prentry, length)
Xchar *base;
Xint num, d_cols;
Xint (*prentry)(), (*length)();
X{
X register int c, j;
X register int a, b, cols, loc, maxlen, nrows, z;
X int col, row;
X
X if (num == 0)
X return;
X maxlen = get_maxlen(base, num, length) + 1;
X if (d_cols > 0)
X cols = d_cols;
X else
X cols = width / maxlen;
X if (cols == 0)
X cols = NCOLS;
X nrows = (num - 1) / cols + 1;
X for (a = 1; a <= nrows; a++) {
X b = c = z = loc = 0;
X for (j = 0; j < num; j++) {
X c++;
X if (c >= a + b)
X break;
X }
X while (j < num) {
X (*prentry)(base, j);
X loc += (*length)(base, j);
X z++;
X b += nrows;
X for (j++; j < num; j++) {
X c++;
X if (c >= a + b)
X break;
X }
X if (j < num) {
X while (loc < z * maxlen) {
X addch(' ');
X loc++;
X }
X }
X }
X getyx(stdscr, row, col);
X move(row + 1, 0);
X }
X refresh();
X}
X
Xstatic int
Xget_maxlen(base, num, length)
Xchar *base;
Xint num;
Xint (*length)();
X{
X register int i, len, max;
X
X max = (*length)(base, 0);
X for (i = 0; i < num; i++) {
X if ((len = (*length)(base, i)) > max)
X max = len;
X }
X return(max);
X}
X
END_OF_prtable.c
if test 2164 -ne `wc -c <prtable.c`; then
echo shar: \"prtable.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f showdict.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"showdict.c\"
else
echo shar: Extracting \"showdict.c\" \(264 characters\)
sed "s/^X//" >showdict.c <<'END_OF_showdict.c'
X/* vi: set tabstop=4 : */
X
X#include <stdio.h>
X
X#include "bog.h"
X
X/*BOGUS*/
Xstruct dictindex dictindex[1];
Xint wordlen;
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X char *p;
X char *nextword();
X
X while ((p = nextword(stdin)) != (char *) NULL)
X printf("%s\n", p);
X}
X
END_OF_showdict.c
if test 264 -ne `wc -c <showdict.c`; then
echo shar: \"showdict.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f timer.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"timer.c\"
else
echo shar: Extracting \"timer.c\" \(1799 characters\)
sed "s/^X//" >timer.c <<'END_OF_timer.c'
X/* vi: set tabstop=4 : */
X
X#include "bog.h"
X
X#ifdef TIMER
X
X#include <setjmp.h>
X#include <curses.h>
X#include <stdio.h>
X
X/*
X * Update the display of the remaining time while waiting for a character
X * If time runs out do a longjmp() to the game controlling routine, returning
X * non-zero; oth. return the character
X * Leave the cursor where it was initially
X */
Xtimerch()
X{
X int col, remaining, row;
X long prevt, t;
X extern int tlimit;
X extern long start_t;
X extern jmp_buf env;
X
X getyx(stdscr, row, col);
X prevt = 0L;
X while (1) {
X if (waitch(1000L) == 1)
X break;
X time(&t);
X if (t == prevt)
X continue;
X prevt = t;
X remaining = tlimit - (int) (t - start_t);
X if (remaining < 0) {
X longjmp(env, 1);
X /*NOTREACHED*/
X }
X move(TIMER_LINE, TIMER_COL);
X printw("%d:%02d", remaining / 60, remaining % 60);
X move(row, col);
X refresh();
X }
X return(getch() & 0177);
X}
X
X/*
X * Wait up to 'delay' microseconds for input to appear
X * Returns 1 if input is ready, 0 oth.
X */
X
X#ifdef BSD42
X
X#include <sys/time.h>
X
Xstatic
Xwaitch(delay)
Xlong delay;
X{
X int fdbits;
X struct timeval duration;
X
X duration.tv_sec = 0L;
X duration.tv_usec = delay;
X fdbits = 1;
X return(select(32, &fdbits, 0, 0, &duration));
X}
X#endif BSD42
X
X#ifdef SYSV
X
X#include <sys/ioctl.h>
X
X/*
X * This is not too efficient...
X */
Xstatic
Xwaitch(delay)
Xlong delay;
X{
X int nchars;
X
X if (ioctl(fileno(stdin), FIONREAD, &nchars) < 0) {
X perror("ioctl():");
X cleanup();
X exit(1);
X }
X return(nchars > 0);
X}
X#endif SYSV
X
X#ifdef ATARI
X
X#include <osbind.h>
X
X/*
X * The ST curses turns on the cursor only when a read is performed
X * Since there's nothing better to do at this point the cursor can
X * be enabled
X */
Xstatic
Xwaitch(delay)
Xlong delay;
X{
X
X Bconout(2, '\033');
X Bconout(2, 'e');
X return(Cconis() == -1);
X}
X#endif ATARI
X
X#endif TIMER
X
END_OF_timer.c
if test 1799 -ne `wc -c <timer.c`; then
echo shar: \"timer.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f word.c -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"word.c\"
else
echo shar: Extracting \"word.c\" \(3450 characters\)
sed "s/^X//" >word.c <<'END_OF_word.c'
X/* vi: set tabstop=4 : */
X
X#include <stdio.h>
X
X#include "bog.h"
X
X#ifdef ATARI
X#include <stat.h>
X#include <osbind.h>
X#define malloc(x) Malloc(x)
X#else
X#include <sys/types.h>
X#include <sys/stat.h>
X#endif
X
Xstatic char *dictspace, *dictend;
Xstatic char *sp;
X
Xstatic int first = 1, lastch = 0;
X
X/*
X * Return the next word in the compressed dictionary in 'buffer' or
X * NULL on end-of-file
X */
Xchar *
Xnextword(fp)
XFILE *fp;
X{
X register int ch, pcount;
X register char *p;
X static char buf[MAXWORDLEN + 1];
X extern int wordlen;
X
X if (fp == (FILE *) NULL) {
X if (sp == dictend)
X return((char *) NULL);
X
X p = buf + (int) *sp++;
X
X /*
X * The dictionary ends with a null byte
X */
X while (*sp >= 'a') {
X if ((*p++ = *sp++) == 'q')
X *p++ = 'u';
X }
X }
X else {
X if (first) {
X if ((pcount = getc(fp)) == EOF)
X return((char *) NULL);
X first = 0;
X }
X else if ((pcount = lastch) == EOF)
X return((char *) NULL);
X
X p = buf + pcount;
X
X while ((ch = getc(fp)) != EOF && ch >= 'a') {
X if ((*p++ = ch) == 'q')
X *p++ = 'u';
X }
X lastch = ch;
X }
X wordlen = (int) (p - buf);
X *p = '\0';
X return(buf);
X}
X
X/*
X * Reset the state of nextword() and do the fseek()
X */
Xdictseek(fp, offset, ptrname)
XFILE *fp;
Xlong offset;
Xint ptrname;
X{
X
X if (fp == (FILE *) NULL) {
X if ((sp = dictspace + offset) >= dictend)
X return(-1);
X return(0);
X }
X
X first = 1;
X return(fseek(fp, offset, ptrname));
X}
X
XFILE *
Xopendict(dict)
Xchar *dict;
X{
X FILE *fp;
X
X#ifdef ATARI
X if ((fp = fopen(dict, "rb")) == (FILE *) NULL)
X return((FILE *) NULL);
X#else
X if ((fp = fopen(dict, "r")) == (FILE *) NULL)
X return((FILE *) NULL);
X#endif
X return(fp);
X}
X
X/*
X * Load the given dictionary and initialize the pointers
X */
Xloaddict(fp)
XFILE *fp;
X{
X int st;
X char *p;
X long n;
X struct stat statb;
X
X#ifdef ATARI
X if (stat(DICT, &statb) < 0) {
X (void) fclose(fp);
X return(-1);
X }
X#else
X char *malloc();
X
X if (fstat(fileno(fp), &statb) < 0) {
X (void) fclose(fp);
X return(-1);
X }
X#endif
X
X /*
X * An extra character (a sentinel) is allocated and set to null to improve
X * the expansion loop in nextword()
X */
X if ((dictspace = (char *) malloc(statb.st_size + 1)) == (char *) NULL) {
X (void) fclose(fp);
X return(-1);
X }
X n = (long) statb.st_size;
X sp = dictspace;
X dictend = dictspace + n;
X
X p = dictspace;
X while (n > 0 && (st = fread(p, 1, BUFSIZ, fp)) > 0) {
X p += st;
X n -= st;
X }
X if (st < 0) {
X (void) fclose(fp);
X (void) fprintf(stderr, "Error reading dictionary\n");
X return(-1);
X }
X *p = '\0';
X return(0);
X}
X
X/*
X * Dependent on the exact format of the index file:
X * Starting offset field begins in column 1 and length field in column 9
X */
Xloadindex(indexfile)
Xchar *indexfile;
X{
X register int i, j;
X char buf[MAXWORDLEN + 1];
X FILE *fp;
X long atol();
X extern struct dictindex dictindex[];
X
X if ((fp = fopen(indexfile, "r")) == (FILE *) NULL) {
X (void) fprintf(stderr, "Can't open '%s'\n", indexfile);
X return(-1);
X }
X i = 0;
X while (fgets(buf, sizeof(buf), fp) != (char *) NULL) {
X j = *buf - 'a';
X if (i != j) {
X (void) fprintf(stderr, "Bad index order\n");
X return(-1);
X }
X dictindex[j].start = atol(buf + 1);
X dictindex[j].length = atol(buf + 9) - dictindex[j].start;
X i++;
X }
X if (i != 26) {
X (void) fprintf(stderr, "Bad index length\n");
X return(-1);
X }
X (void) fclose(fp);
X return(0);
X}
X
END_OF_word.c
if test 3450 -ne `wc -c <word.c`; then
echo shar: \"word.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f helpfile -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"helpfile\"
else
echo shar: Extracting \"helpfile\" \(3620 characters\)
sed "s/^X//" >helpfile <<'END_OF_helpfile'
X
XCommands:
X
XEnter word: <return> or <linefeed> or <space>
XDelete previous character: <delete> or <backspace>
XDelete line: <^u> or <^w>
XRedraw screen: <^l> or <^r>
XPause game: <^s>
XResume game: <^q> or <^s>
XSuspend game (BSD only): <^z>
XGive up on current cube: <^d>
XShow remaining time: <space> first thing on a line
XShow help: ? (Suspends timer until done)
XExit game: <^c>
X
X(^u means "control u", etc.)
X
X[Note for users of versions of this program that do not display a timer:
XThe first word entered after the timer has run out causes a list of all the
Xwords you found, the words you missed, and your running statistics to be
Xdisplayed.]
X
XAny time you are prompted while the board is displayed you can type:
X <esc>word
Xto see where "word" is on the board.
X
XUsage:
X bog [-b] [-d] [-s#] [-t#] [-w#] [+[+]] [boardspec]
X
X -b: batch mode (boardspec must be present); dictionary read from stdin
X -d: debug mode
X -s#: use # as the random number seed
X -t#: time limit is # seconds instead of default 180
X -w#: minimum word length is # letters instead of default 3
X +: can reuse a cube, but not twice in succession
X ++: can reuse cubes arbitrarily
X boardspec: the first board to use (use 'q' for 'qu'); e.g.:
X bog nolezeebnqieegei
X.
X Default Rules
X
XA Boggle board is a four by four arrangement of Boggle cubes.
XYou have 3 minutes to find as many words as possible in the Boggle board.
XWords are formed by finding a sequence of cubes (letters) that are in the
Xgame's dictionary. The (N+1)th cube in the word must be horizontally,
Xvertically, or diagonally adjacent to the Nth cube. Cubes cannot be reused.
XWords consist solely of lower case letters and must be at least 3 letters long.
X.
X Options
X
XCommand line flags can be given to change the rules of the game.
XThe '+' flag allows a cube to be used multiple times, but not in succession.
XThe '++' flag allows the same cubes to be considered adjacent to itself.
XThe time limit can be changed from the default 3 minutes by using the flag
X'-t#', where # is the duration (in seconds) of each game.
XThe minimum word length can be changed from 3 letters by specifying 'w#',
Xwhere # is the minimum number of letters to use.
X.
X Bugs and Limitations
X
XThe following bugs and problems are known to exist:
X
X- If there are a great many words in the cube the final display of the words
X may scroll off of the screen. (On a 25 line screen about 130 words can be
X displayed.)
X
X- Computing the complete word list can be too slow on small machines.
X
X- No word can contain a 'q' that is not immediately followed by a 'u'.
X
X- When using the '+' or '++' options the display of words found in the board
X doesn't indicate reused cubes.
X.
X About This Program
X
XPermission is given to freely copy and distribute this software providing:
X
X1) You do not sell it,
X2) You do not use it for commercial advantage,
X3) If you pass the program on you must make the source code available, and
X4) This notice must accompany the distribution
X
XPlease notify the author of any bugs or if you have any suggestions.
X
XCopyright (c) 1988:
XBarry Brachman
XDept. of Computer Science
XUniv. of British Columbia
XVancouver, B.C. V6T 1W5
X
X.. {ihnp4!alberta, uw-beaver, uunet}!ubc-vision!ubc-csgrads!brachman
Xbra...@grads.cs.ubc.cdn
Xbrachman%ubc....@csnet-relay.arpa
Xbra...@ubc.csnet
X
XBoggle is a trademark of Parker Brothers.
X
END_OF_helpfile
if test 3620 -ne `wc -c <helpfile`; then
echo shar: \"helpfile\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0

0 new messages