From 013ac7742311556022304e8b30ca170d48b3a016 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Thu, 7 May 2015 16:32:32 -0400 Subject: initial commit --- boggle/Makefile | 40 +++ boggle/README | 66 +++++ boggle/boggle/Makefile | 19 ++ boggle/boggle/bog.c | 714 +++++++++++++++++++++++++++++++++++++++++++++++ boggle/boggle/bog.h | 83 ++++++ boggle/boggle/boggle.6 | 127 +++++++++ boggle/boggle/extern.h | 62 ++++ boggle/boggle/help.c | 105 +++++++ boggle/boggle/helpfile | 92 ++++++ boggle/boggle/mach.c | 665 +++++++++++++++++++++++++++++++++++++++++++ boggle/boggle/prtable.c | 127 +++++++++ boggle/boggle/timer.c | 119 ++++++++ boggle/boggle/word.c | 215 ++++++++++++++ boggle/mkdict/Makefile | 10 + boggle/mkdict/mkdict.c | 124 ++++++++ boggle/mkindex/Makefile | 10 + boggle/mkindex/mkindex.c | 131 +++++++++ 17 files changed, 2709 insertions(+) create mode 100644 boggle/Makefile create mode 100644 boggle/README create mode 100644 boggle/boggle/Makefile create mode 100644 boggle/boggle/bog.c create mode 100644 boggle/boggle/bog.h create mode 100644 boggle/boggle/boggle.6 create mode 100644 boggle/boggle/extern.h create mode 100644 boggle/boggle/help.c create mode 100644 boggle/boggle/helpfile create mode 100644 boggle/boggle/mach.c create mode 100644 boggle/boggle/prtable.c create mode 100644 boggle/boggle/timer.c create mode 100644 boggle/boggle/word.c create mode 100644 boggle/mkdict/Makefile create mode 100644 boggle/mkdict/mkdict.c create mode 100644 boggle/mkindex/Makefile create mode 100644 boggle/mkindex/mkindex.c (limited to 'boggle') diff --git a/boggle/Makefile b/boggle/Makefile new file mode 100644 index 0000000..4671c08 --- /dev/null +++ b/boggle/Makefile @@ -0,0 +1,40 @@ +# $NetBSD: Makefile,v 1.22 2003/10/21 10:01:19 lukem Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/11/93 + +.include + +SUBDIR= boggle mkdict mkindex + +MKDICTDIR!= cd $(.CURDIR)/mkdict; ${PRINTOBJDIR} +MKDICT=${MKDICTDIR}/mkdict +MKINDEXDIR!= cd $(.CURDIR)/mkindex; ${PRINTOBJDIR} +MKINDEX=${MKINDEXDIR}/mkindex +# 20150209 bkw: look for dictionary words here: +WORDS=/usr/share/dict/words +DICTFILES=dictionary dictindex +.if ${MKSHARE} != "no" +FILES=${DICTFILES} +FILESDIR=/usr/share/games/boggle +.endif +CLEANFILES+=${DICTFILES} + +realall: ${FILES} + +${MKDICT}: + @cd ${.CURDIR}/mkdict && ${MAKE} + +${MKINDEX}: + @cd ${.CURDIR}/mkindex && ${MAKE} + +dictionary: ${WORDS} ${MKDICT} + ${_MKTARGET_CREATE} + rm -f ${.TARGET} + ./mkdict/${MKDICT} < ${WORDS} > ${.TARGET} + +dictindex: dictionary ${MKINDEX} + ${_MKTARGET_CREATE} + rm -f ${.TARGET} + ./mkindex/${MKINDEX} < dictionary > ${.TARGET} + +.include +.include diff --git a/boggle/README b/boggle/README new file mode 100644 index 0000000..fc38842 --- /dev/null +++ b/boggle/README @@ -0,0 +1,66 @@ +$NetBSD: README,v 1.2 1995/03/21 12:14:21 cgd Exp $ + +Bog is a fairly portable simulation of Parker Brother's game of Boggle and +is similar to the 4.[23] BSD "boggle" and Sun's "boggletool". +Bog has not been derived from any proprietary code. +It has been tested on the Sun 3 under SunOS 3.2 and on the Atari 1040ST (MWC). + +What You Need + +You will need curses/termcap and a large word list. +The minix word list or /usr/dict/words will do nicely. +The word list must already be sorted (you can use "sort -c" to check). + +Contents + + README - this file + Makefile + bog.man - half-hearted man page (use the game's help command) + bog.h - configuration and header info + bog.c - machine independent game code + word.c - machine independent word list routines + help.c - (curses) help routine + mach.c - (curses) display code + prtable.c - ditto + timer.c - machine dependent (os) input polling + mkdict.c - convert a word list to a bog dictionary + mkindex.c - create an index file for the bog dictionary + showdict.c - print a bog dictionary to stdout + +Portability + +- I've tried to make bog.c (the program logic) independent of the I/O. + My plan was to make it straightforward to adapt the game to run under a + windowing system (eg., Suntools, GEM). I have no plan to actually do this. + I've stuck to a small subset of the curses routines. +- The program runs with the input in raw mode. +- If you want the running timer you must #define TIMER in bog.h + and insert the input polling code in timer.c for your system. There is + already code there for BSD, SYSV, and ATARI. + +Setup + +1. Check bog.h and Makefile and edit to fit your environment +2. "make all" + This will make all the binaries and create the dictionary and index files +3. Move "dict", "dict.ind", and "helpfile" to where you specified in bog.h +4. Play away + +Distribution + +You may use this software for your enjoyment and you may share it with others. +You may not sell this software or use it for any commercial purposes +whatsoever. All modified versions of the software that you redistribute must +clearly indicate your changes. + +If you come across any bugs or make any changes you'd like to share please +send mail to me rather than posting to the net. + +Enjoy. [But beware: boggle can be addictive!] + +----- +Barry Brachman | UUCP: {alberta,uw-beaver,uunet}! +Dept. of Computer Science| ubc-vision!ubc-csgrads!brachman +Univ. of British Columbia| Internet: brachman@cs.ubc.ca +Vancouver, B.C. V6T 1W5 | brachman%ubc.csnet@csnet-relay.arpa +(604) 228-5010 | brachman@ubc.csnet diff --git a/boggle/boggle/Makefile b/boggle/boggle/Makefile new file mode 100644 index 0000000..400b438 --- /dev/null +++ b/boggle/boggle/Makefile @@ -0,0 +1,19 @@ +# $NetBSD: Makefile,v 1.10 2010/02/06 23:45:25 he Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/11/93 + +.include + +PROG= boggle +SRCS= bog.c help.c mach.c prtable.c timer.c word.c +DPADD= ${LIBCURSES} ${LIBTERMINFO} +# 20150209 bkw: removed -lterminfo from LDADD, added -lbsd +LDADD= -lcurses -lbsd +HIDEGAME=hidegame +MAN= boggle.6 +.if ${MKSHARE} != "no" +FILES= helpfile +FILESDIR=/usr/share/games/boggle +.endif + +.include "../../Makefile.inc" +.include diff --git a/boggle/boggle/bog.c b/boggle/boggle/bog.c new file mode 100644 index 0000000..e24d9e2 --- /dev/null +++ b/boggle/boggle/bog.c @@ -0,0 +1,714 @@ +/* $NetBSD: bog.c,v 1.29 2014/03/22 23:39:04 dholland Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1993\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)bog.c 8.2 (Berkeley) 5/4/95"; +#else +__RCSID("$NetBSD: bog.c,v 1.29 2014/03/22 23:39:04 dholland Exp $"); +#endif +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bog.h" +#include "extern.h" + +static char *batchword(FILE *); +static void playgame(void); +static int validword(const char *); +static void checkdict(void); +static void newgame(const char *); +static int compar(const void *, const void *); +static void clearwordpath(int full); +static void usage(void) __dead; + +struct dictindex dictindex[26]; + +/* + * Cube position numbering: + * + * 0 1 2 3 + * 4 5 6 7 + * 8 9 A B + * C D E F + */ +static int adjacency[16][16] = { +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + { 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 0 */ + { 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1 */ + { 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 2 */ + { 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 3 */ + { 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, /* 4 */ + { 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, /* 5 */ + { 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 }, /* 6 */ + { 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0 }, /* 7 */ + { 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0 }, /* 8 */ + { 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0 }, /* 9 */ + { 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1 }, /* A */ + { 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1 }, /* B */ + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 }, /* C */ + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0 }, /* D */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1 }, /* E */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 } /* F */ +}; + +static int letter_map[26][16]; + +char board[17]; +int wordpath[MAXWORDLEN + 1]; +int wordlen; /* Length of last word returned by nextword() */ +int usedbits; + +const char *pword[MAXPWORDS]; +static char pwords[MAXPSPACE], *pwordsp; +int npwords; + +const char *mword[MAXMWORDS]; +static char mwords[MAXMSPACE], *mwordsp; +int nmwords; + +int ngames = 0; +int tnmwords = 0, tnpwords = 0; + +#include +jmp_buf env; + +time_t start_t; +int debug; +int tlimit; + +static FILE *dictfp; +static int batch; +static int minlength; +static int reuse; + +int +main(int argc, char *argv[]) +{ + long seed; + int ch, done, i, selfuse, sflag; + char *bspec, *p; + + /* revoke setgid privileges */ + setgid(getgid()); + + seed = 0; + batch = debug = reuse = selfuse = sflag = 0; + bspec = NULL; + minlength = 3; + tlimit = 180; /* 3 minutes is standard */ + + while ((ch = getopt(argc, argv, "bds:t:w:")) != -1) + switch(ch) { + case 'b': + batch = 1; + break; + case 'd': + debug = 1; + break; + case 's': + sflag = 1; + seed = atol(optarg); + break; + case 't': + if ((tlimit = atoi(optarg)) < 1) + errx(1, "bad time limit"); + break; + case 'w': + if ((minlength = atoi(optarg)) < 3) + errx(1, "min word length must be > 2"); + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + /* process final arguments */ + if (argc > 0) { + if (strcmp(argv[0], "+") == 0) + reuse = 1; + else if (strcmp(argv[0], "++") == 0) + selfuse = 1; + } + + if (reuse || selfuse) { + argc -= 1; + argv += 1; + } + + if (argc > 0) { + if (islower((unsigned char)argv[0][0])) { + if (strlen(argv[0]) != 16) { + usage(); + } else { + /* This board is assumed to be valid... */ + bspec = argv[0]; + } + } else { + usage(); + } + } + + if (batch && bspec == NULL) + errx(1, "must give both -b and a board setup"); + + if (selfuse) + for (i = 0; i < 16; i++) + adjacency[i][i] = 1; + + if (batch) { + newgame(bspec); + while ((p = batchword(stdin)) != NULL) + (void) printf("%s\n", p); + exit (0); + } + setup(sflag, seed); + prompt("Loading the dictionary..."); + if ((dictfp = opendict(DICT)) == NULL) { + warn("%s", DICT); + cleanup(); + exit(1); + } +#ifdef LOADDICT + if (loaddict(dictfp) < 0) { + warnx("can't load %s", DICT); + cleanup(); + exit(1); + } + (void)fclose(dictfp); + dictfp = NULL; +#endif + if (loadindex(DICTINDEX) < 0) { + warnx("can't load %s", DICTINDEX); + cleanup(); + exit(1); + } + + prompt("Type to begin..."); + while (inputch() != ' '); + + for (done = 0; !done;) { + newgame(bspec); + bspec = NULL; /* reset for subsequent games */ + playgame(); +#ifdef NEW_STYLE + prompt("Type uit, locate, any other key to continue..."); +#else + prompt("Type to continue, any cap to quit..."); +#endif + delay(50); /* wait for user to quit typing */ + flushin(stdin); + for (;;) { + ch = inputch(); +#ifdef NEW_STYLE + if (ch == '\e') + findword(); + else if (ch == CTRL('l') || ch == CTRL('r')) + redraw(); + else { + if (ch == 'q') { + done = 1; + break; + } else { + break; + } + } +#else + if (ch == '\e') + findword(); + else if (ch == CTRL('l') || ch == CTRL('r')) + redraw(); + else { + if (isupper(ch)) { + done = 1; + break; + } + if (ch == ' ') + break; + } +#endif + } + } + cleanup(); + exit (0); +} + +/* + * Read a line from the given stream and check if it is legal + * Return a pointer to a legal word or a null pointer when EOF is reached + */ +static char * +batchword(FILE *fp) +{ + char *w; + + clearwordpath(1); + while ((w = nextword(fp)) != NULL) { + if (wordlen < minlength) + continue; + clearwordpath(0); + usedbits = 0; + if (checkword(w, -1, wordpath) != -1) + return (w); + } + return (NULL); +} + +/* + * Play a single game + * Reset the word lists from last game + * Keep track of the running stats + */ +static void +playgame(void) +{ + int i; + time_t t; + char buf[MAXWORDLEN + 1]; + + ngames++; + npwords = 0; + pwordsp = pwords; + nmwords = 0; + mwordsp = mwords; + + time(&start_t); + + clearwordpath(1); + showboard(board); + startwords(); + if (setjmp(env)) { + badword(); + goto timesup; + } + + while (1) { + if (get_line(buf) == NULL) { + if (feof(stdin)) + clearerr(stdin); + break; + } + time(&t); + if (t - start_t >= tlimit) { + badword(); + break; + } + if (buf[0] == '\0') { + int remaining; + + remaining = tlimit - (int) (t - start_t); + (void)snprintf(buf, sizeof(buf), + "%d:%02d", remaining / 60, remaining % 60); + showstr(buf, 1); + continue; + } + if (strlen(buf) < (size_t)minlength) { + badword(); + continue; + } + + clearwordpath(0); + usedbits = 0; + + if (checkword(buf, -1, wordpath) < 0) + badword(); + else { + if (debug) { + (void) printf("["); + for (i = 0; wordpath[i] != -1; i++) + (void) printf(" %d", wordpath[i]); + (void) printf(" ]\n"); + } + for (i = 0; i < npwords; i++) { + if (strcmp(pword[i], buf) == 0) + break; + } + if (i != npwords) { /* already used the word */ + badword(); + showword(i); + } + else if (!validword(buf)) + badword(); + else { + size_t len; + + len = strlen(buf) + 1; + if (npwords == MAXPWORDS - 1 || + pwordsp + len >= &pwords[MAXPSPACE]) { + warnx("Too many words!"); + cleanup(); + exit(1); + } + pword[npwords++] = pwordsp; + (void) strcpy(pwordsp, buf); + pwordsp += len; + addword(buf); + } + } + } + +timesup: ; + + /* + * Sort the player's words and terminate the list with a null + * entry to help out checkdict() + */ + qsort(pword, npwords, sizeof(pword[0]), compar); + pword[npwords] = NULL; + + /* + * These words don't need to be sorted since the dictionary is sorted + */ + checkdict(); + + tnmwords += nmwords; + tnpwords += npwords; + + results(); +} + +/* + * Check if the given word is present on the board, with the constraint + * that the first letter of the word is adjacent to square 'prev' + * Keep track of the current path of squares for the word + * A 'q' must be followed by a 'u' + * Words must end with a null + * Return 1 on success, -1 on failure + */ +int +checkword(const char *word, int prev, int *path) +{ + const char *p; + char *q; + int i, *lm; + + if (debug) { + (void) printf("checkword(%s, %d, [", word, prev); + for (i = 0; wordpath[i] != -1; i++) + (void) printf(" %d", wordpath[i]); + (void) printf(" ]\n"); + } + + if (*word == '\0') + return (1); + + lm = letter_map[*word - 'a']; + + if (prev == -1) { + char subword[MAXWORDLEN + 1]; + + /* + * Check for letters not appearing in the cube to eliminate some + * recursive calls + * Fold 'qu' into 'q' + */ + p = word; + q = subword; + while (*p != '\0') { + if (*letter_map[*p - 'a'] == -1) + return (-1); + *q++ = *p; + if (*p++ == 'q') { + if (*p++ != 'u') + return (-1); + } + } + *q = '\0'; + while (*lm != -1) { + *path = *lm; + usedbits |= (1 << *lm); + if (checkword(subword + 1, *lm, path + 1) > 0) + return (1); + usedbits &= ~(1 << *lm); + lm++; + } + return (-1); + } + + /* + * A cube is only adjacent to itself in the adjacency matrix if selfuse + * was set, so a cube can't be used twice in succession if only the + * reuse flag is set + */ + for (i = 0; lm[i] != -1; i++) { + if (adjacency[prev][lm[i]]) { + int used; + + used = 1 << lm[i]; + /* + * If necessary, check if the square has already + * been used. + */ + if (!reuse && (usedbits & used)) + continue; + *path = lm[i]; + usedbits |= used; + if (checkword(word + 1, lm[i], path + 1) > 0) + return (1); + usedbits &= ~used; + } + } + *path = -1; /* in case of a backtrack */ + return (-1); +} + +/* + * A word is invalid if it is not in the dictionary + * At this point it is already known that the word can be formed from + * the current board + */ +static int +validword(const char *word) +{ + int j; + const char *q, *w; + + j = word[0] - 'a'; + if (dictseek(dictfp, dictindex[j].start, SEEK_SET) < 0) { + (void) fprintf(stderr, "Seek error\n"); + cleanup(); + exit(1); + } + + while ((w = nextword(dictfp)) != NULL) { + int ch; + + if (*w != word[0]) /* end of words starting with word[0] */ + break; + q = word; + while ((ch = *w++) == *q++ && ch != '\0') + ; + if (*(w - 1) == '\0' && *(q - 1) == '\0') + return (1); + } + if (dictfp != NULL && feof(dictfp)) /* Special case for z's */ + clearerr(dictfp); + return (0); +} + +/* + * Check each word in the dictionary against the board + * Delete words from the machine list that the player has found + * Assume both the dictionary and the player's words are already sorted + */ +static void +checkdict(void) +{ + char *p, *w; + const char **pw; + int i; + int prevch, previndex, st; + + mwordsp = mwords; + nmwords = 0; + pw = pword; + prevch ='a'; + + (void) dictseek(dictfp, 0L, SEEK_SET); + while ((w = nextword(dictfp)) != NULL) { + if (wordlen < minlength) + continue; + if (*w != prevch) { + /* + * If we've moved on to a word with a different first + * letter then we can speed things up by skipping all + * words starting with a letter that doesn't appear in + * the cube. + */ + i = (int) (*w - 'a'); + while (i < 26 && letter_map[i][0] == -1) + i++; + if (i == 26) + break; + previndex = prevch - 'a'; + prevch = i + 'a'; + /* + * Fall through if the word's first letter appears in + * the cube (i.e., if we can't skip ahead), otherwise + * seek to the beginning of words in the dictionary + * starting with the next letter (alphabetically) + * appearing in the cube and then read the first word. + */ + if (i != previndex + 1) { + if (dictseek(dictfp, + dictindex[i].start, SEEK_SET) < 0) { + warnx("seek error in checkdict()"); + cleanup(); + exit(1); + } + continue; + } + } + + clearwordpath(0); + usedbits = 0; + if (checkword(w, -1, wordpath) == -1) + continue; + + st = 1; + while (*pw != NULL && (st = strcmp(*pw, w)) < 0) + pw++; + if (st == 0) /* found it */ + continue; + if (nmwords == MAXMWORDS || + mwordsp + wordlen + 1 >= &mwords[MAXMSPACE]) { + warnx("too many words!"); + cleanup(); + exit(1); + } + mword[nmwords++] = mwordsp; + p = w; + while ((*mwordsp++ = *p++) != '\0') + ; + } +} + +/* + * Crank up a new game + * If the argument is non-null then it is assumed to be a legal board spec + * in ascending cube order, oth. make a random board + */ +static void +newgame(const char *b) +{ + int i, p, q; + const char *tmp; + int *lm[26]; + static const char *cubes[16] = { + "ednosw", "aaciot", "acelrs", "ehinps", + "eefhiy", "elpstu", "acdemp", "gilruw", + "egkluy", "ahmors", "abilty", "adenvz", + "bfiorx", "dknotu", "abjmoq", "egintv" + }; + + if (b == NULL) { + /* + * Shake the cubes and make the board + */ + i = 0; + while (i < 100) { + p = (int) (random() % 16); + q = (int) (random() % 16); + if (p != q) { + tmp = cubes[p]; + cubes[p] = cubes[q]; + cubes[q] = tmp; + i++; + } + /* else try again */ + } + + for (i = 0; i < 16; i++) + board[i] = cubes[i][random() % 6]; + } + else { + for (i = 0; i < 16; i++) + board[i] = b[i]; + } + board[16] = '\0'; + + /* + * Set up the map from letter to location(s) + * Each list is terminated by a -1 entry + */ + for (i = 0; i < 26; i++) { + lm[i] = letter_map[i]; + *lm[i] = -1; + } + + for (i = 0; i < 16; i++) { + int j; + + j = (int) (board[i] - 'a'); + *lm[j] = i; + *(++lm[j]) = -1; + } + + if (debug) { + for (i = 0; i < 26; i++) { + int ch, j; + + (void) printf("%c:", 'a' + i); + for (j = 0; (ch = letter_map[i][j]) != -1; j++) + (void) printf(" %d", ch); + (void) printf("\n"); + } + } + +} + +/* + * Clear wordpath[]. + */ +static void +clearwordpath(int full) +{ + size_t pos; + const size_t max = MAXWORDLEN + 1; + + for (pos = 0; pos < max && (full || wordpath[pos] != -1); pos++) { + wordpath[pos] = -1; + } +} + +static int +compar(const void *p, const void *q) +{ + return (strcmp(*(const char *const *)p, *(const char *const *)q)); +} + +static void +usage(void) +{ + (void) fprintf(stderr, + "usage: %s [-bd] [-s#] [-t#] [-w#] [+[+]] [boardspec]\n", + getprogname()); + exit(1); +} diff --git a/boggle/boggle/bog.h b/boggle/boggle/bog.h new file mode 100644 index 0000000..06d2f5b --- /dev/null +++ b/boggle/boggle/bog.h @@ -0,0 +1,83 @@ +/* $NetBSD: bog.h,v 1.3 2003/08/07 09:37:05 agc Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bog.h 8.1 (Berkeley) 6/11/93 + */ + +#define LOADDICT 1 /* Load the dictionary for speed */ + +/* + * Locations for the dictionary (generated by mkdict), + * index (generated by mkindex), and helpfile + */ +#define DICT "/usr/share/games/boggle/dictionary" +#define DICTINDEX "/usr/share/games/boggle/dictindex" +#define HELPFILE "/usr/share/games/boggle/helpfile" + +/* + * The theoretical maximum for MAXWORDLEN is ('a' - 1) == 96 + */ +#define MAXWORDLEN 40 /* Maximum word length */ +#define MAXPWORDS 200 /* Maximum number of player's words */ +#define MAXMWORDS 200 /* Maximum number of machine's words */ +#define MAXPSPACE 2000 /* Space for player's words */ +#define MAXMSPACE 4000 /* Space for machines's words */ + +#define MAXCOLS 20 + +/* + * The following determine the screen layout + */ +#define PROMPT_COL 20 +#define PROMPT_LINE 2 + +#define BOARD_COL 0 +#define BOARD_LINE 0 + +#define SCORE_COL 20 +#define SCORE_LINE 0 + +#define LIST_COL 0 +#define LIST_LINE 10 + +#define TIMER_COL 20 +#define TIMER_LINE 2 + +/* + * Internal dictionary index + * Initialized from the file created by mkindex + */ +struct dictindex { + long start; + long length; +}; diff --git a/boggle/boggle/boggle.6 b/boggle/boggle/boggle.6 new file mode 100644 index 0000000..f5812ff --- /dev/null +++ b/boggle/boggle/boggle.6 @@ -0,0 +1,127 @@ +.\" $NetBSD: boggle.6,v 1.9 2006/09/24 01:38:57 jmcneill Exp $ +.\" +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Barry Brachman. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)boggle.6 8.1 (Berkeley) 6/11/93 +.\" +.Dd September 23, 2006 +.Dt BOGGLE 6 +.Os +.Sh NAME +.Nm boggle +.Nd word search game +.Sh SYNOPSIS +.Nm +.Op Fl bd +.Op Fl s Ar seed +.Op Fl t Ar time +.Op Fl w Ar length +.Op + Op + +.Op boardspec +.Sh DESCRIPTION +The object of +.Nm +is to find as many words as possible on the Boggle board within the three +minute time limit. +A Boggle board is a four by four arrangement of Boggle cubes, each side of +each cube displaying a letter of the alphabet or `qu'. +Words are formed by finding a sequence of cubes (letters) that are in the +game's dictionary. +The (N+1)th cube in the word must be horizontally, +vertically, or diagonally adjacent to the Nth cube. +Cubes cannot be reused. +Words consist solely of lower case letters and must be at least 3 letters long. +.Pp +Command line flags can be given to change the rules of the game. +.Bl -tag -width boardspec +.It Fl b +Run +.Nm +in batch mode. +A +.Ar boardspec +must also be given. +The dictionary is read from stdin and a list of words appearing in +.Ar boardspec +is printed to stdout. +.It Fl d +Enable debugging output. +.It Fl s Ar seed +Specify a seed +.Ar seed +other than the time of day. +.It Fl t Ar time +Set the time limit for each game from the default 3 minutes to +.Ar time +seconds. +.It Fl w Ar length +Change the minimum word length from 3 letters to +.Ar length . +.It Ar + +This flag allows a cube to be used multiple times, but not in succession. +.It Ar ++ +This flag allows the same cubes to be considered adjacent to itself. +.It Ar boardspec +A starting board position can be specified on the command line by +listing the board left to right and top to bottom. +.El +.Pp +Help is available during play by typing +.Sq Ic \&? . +More detailed information on the game is given there. +.Sh AUTHORS +Boggle is a trademark of Parker Brothers. +.Pp +Barry Brachman +.Pp +Dept. of Computer Science +.Pp +University of British Columbia +.Sh BUGS +If there are a great many words in the cube the final display of the words +may scroll off of the screen. +(On a 25 line screen about 130 words can be displayed.) +.Pp +No word can contain a +.Sq q +that is not immediately followed by a +.Sq u . +.Pp +When using the +.Ar + +or +.Ar ++ +options the display of words found in the board doesn't indicate reused cubes. +.Pp +The dictionary that +.Nx +installs omits many words that belong in the English language, most +notably inflected forms. diff --git a/boggle/boggle/extern.h b/boggle/boggle/extern.h new file mode 100644 index 0000000..ee9a340 --- /dev/null +++ b/boggle/boggle/extern.h @@ -0,0 +1,62 @@ +/* $NetBSD: extern.h,v 1.11 2009/08/12 05:29:40 dholland Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.1 (Berkeley) 6/11/93 + */ + +#include + +void addword(const char *); +void badword(void); +int checkword(const char *, int, int *); +void cleanup(void); +void delay(int); +long dictseek(FILE *, long, int); +void findword(void); +void flushin(FILE *); +char *get_line(char *); +int help(void); +int inputch(void); +int loaddict(FILE *); +int loadindex(const char *); +char *nextword(FILE *); +FILE *opendict(const char *); +void prompt(const char *); +void prtable(const char *const [], + int, int, int, void (*)(const char *const [], int), + int (*)(const char *const [], int)); +void redraw(void); +void results(void); +int setup(int, time_t); +void showboard(const char *); +void showstr(const char *, int); +void showword(int); +void startwords(void); +int timerch(void); diff --git a/boggle/boggle/help.c b/boggle/boggle/help.c new file mode 100644 index 0000000..0310683 --- /dev/null +++ b/boggle/boggle/help.c @@ -0,0 +1,105 @@ +/* $NetBSD: help.c,v 1.7 2011/08/31 16:24:55 plunky Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)help.c 8.1 (Berkeley) 6/11/93"; +#else +__RCSID("$NetBSD: help.c,v 1.7 2011/08/31 16:24:55 plunky Exp $"); +#endif +#endif /* not lint */ + +#include +#include + +#include "bog.h" +#include "extern.h" + +extern int nlines; + +int +help(void) +{ + int eof, i; + FILE *fp; + WINDOW *win; + char buf[BUFSIZ]; + + if ((fp = fopen(HELPFILE, "r")) == NULL) + return(-1); + win = newwin(0, 0, 0, 0); + clearok(win, 1); + + eof = 0; + if (ungetc(getc(fp), fp) == EOF) { + wprintw(win, "There doesn't seem to be any help."); + eof = 1; /* Nothing there... */ + } + + while (!eof) { + for (i = 0; i < nlines - 3; i++) { + if (fgets(buf, sizeof(buf), fp) == NULL) { + eof = 1; + break; + } + if (buf[0] == '.' && buf[1] == '\n') + break; + wprintw(win, "%s", buf); + } + if (eof || ungetc(getc(fp), fp) == EOF) { + eof = 1; + break; + } + wmove(win, nlines - 1, 0); + wprintw(win, + "Type to continue, anything else to quit..."); + wrefresh(win); + if ((inputch() & 0177) != ' ') + break; + wclear(win); + } + + fclose(fp); + if (eof) { + wmove(win, nlines - 1, 0); + wprintw(win, "Hit any key to continue..."); + wrefresh(win); + inputch(); + } + delwin(win); + clearok(stdscr, 1); + refresh(); + return(0); +} diff --git a/boggle/boggle/helpfile b/boggle/boggle/helpfile new file mode 100644 index 0000000..c511efe --- /dev/null +++ b/boggle/boggle/helpfile @@ -0,0 +1,92 @@ + +Commands: + +Enter word: or or +Delete previous character: or +Delete line: <^u> or <^w> +Redraw screen: <^l> or <^r> +Pause game: <^s> +Resume game: <^q> or <^s> +Suspend game (BSD only): <^z> +Give up on current cube: <^d> +Show remaining time: first thing on a line +Show help: ? (Suspends timer until done) +Exit game: <^c> + +(^u means "control u", etc.) + +[Note for users of versions of this program that do not display a timer: +The first word entered after the timer has run out causes a list of all the +words you found, the words you missed, and your running statistics to be +displayed.] + +Any time you are prompted while the board is displayed you can type: + word +to see where "word" is on the board. + +Usage: + bog [-b] [-d] [-s#] [-t#] [-w#] [+[+]] [boardspec] + + -b: batch mode (boardspec must be present); dictionary read from stdin + -d: debug mode + -s#: use # as the random number seed + -t#: time limit is # seconds instead of default 180 + -w#: minimum word length is # letters instead of default 3 + +: can reuse a cube, but not twice in succession + ++: can reuse cubes arbitrarily + boardspec: the first board to use (use 'q' for 'qu'); e.g.: + bog nolezeebnqieegei +. + Default Rules + +A Boggle board is a four by four arrangement of Boggle cubes. +You have 3 minutes to find as many words as possible in the Boggle board. +Words are formed by finding a sequence of cubes (letters) that are in the +game's dictionary. The (N+1)th cube in the word must be horizontally, +vertically, or diagonally adjacent to the Nth cube. Cubes cannot be reused. +Words consist solely of lower case letters and must be at least 3 letters long. +. + Options + +Command line flags can be given to change the rules of the game. +The '+' flag allows a cube to be used multiple times, but not in succession. +The '++' flag makes each cube adjacent to itself. +The time limit can be changed from the default 3 minutes by using the flag +'-t#', where # is the duration (in seconds) of each game. +The minimum word length can be changed from 3 letters by specifying 'w#', +where # is the minimum number of letters to use. +. + Bugs and Limitations + +The following bugs and problems are known to exist: + +- If there are a great many words in the cube the final display of the words + may scroll off of the screen. (On a 25 line screen about 130 words can be + displayed.) + +- Computing the complete word list can be too slow on small machines. + +- No word can contain a 'q' that is not immediately followed by a 'u'. + +- When using the '+' or '++' options the display of words found in the board + doesn't indicate reused cubes. +. + About This Program + +Permission is given to freely copy and distribute this software providing: + +1) You do not sell it, +2) You do not use it for commercial advantage, +3) If you pass the program on you must make the source code available, and +4) This notice must accompany the distribution + +Please notify the author of any bugs or if you have any suggestions. + +Copyright (c) 1988 +Barry Brachman | UUCP: {alberta,uw-beaver,uunet}! +Dept. of Computer Science| ubc-vision!ubc-csgrads!brachman +Univ. of British Columbia| Internet: brachman@cs.ubc.ca +Vancouver, B.C. V6T 1W5 | brachman%ubc.csnet@csnet-relay.arpa +(604) 228-5010 | brachman@ubc.csnet + +Boggle is a trademark of Parker Brothers. diff --git a/boggle/boggle/mach.c b/boggle/boggle/mach.c new file mode 100644 index 0000000..7c86176 --- /dev/null +++ b/boggle/boggle/mach.c @@ -0,0 +1,665 @@ +/* $NetBSD: mach.c,v 1.21 2011/08/31 16:24:55 plunky Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)mach.c 8.1 (Berkeley) 6/11/93"; +#else +__RCSID("$NetBSD: mach.c,v 1.21 2011/08/31 16:24:55 plunky Exp $"); +#endif +#endif /* not lint */ + +/* + * Terminal interface + * + * Input is raw and unechoed + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bog.h" +#include "extern.h" + +static int ccol, crow, maxw; +static int colstarts[MAXCOLS], ncolstarts; +static int lastline; +static int ncols; +int nlines; + +extern const char *pword[], *mword[]; +extern int ngames, nmwords, npwords, tnmwords, tnpwords; +extern char board[]; +extern int usedbits, wordpath[]; +extern time_t start_t; +extern int debug; + +static void cont_catcher(int); +static int prwidth(const char *const [], int); +static void prword(const char *const [], int); +static void stop_catcher(int); +static void tty_cleanup(void); +static int tty_setup(void); +static void tty_showboard(const char *); +static void winch_catcher(int); +static void getword(char *); +static void starttime(void); +static void stoptime(void); + + +/* + * Do system dependent initialization + * This is called once, when the program starts + */ +int +setup(int sflag, time_t seed) +{ + if (tty_setup() < 0) + return(-1); + + if (!sflag) + time(&seed); + srandom(seed); + if (debug) + (void) printf("seed = %ld\n", (long) seed); + return(0); +} + +/* + * Do system dependent clean up + * This is called once, just before the program terminates + */ +void +cleanup(void) +{ + tty_cleanup(); +} + +/* + * Display the player's word list, the list of words not found, and the running + * stats + */ +void +results(void) +{ + int col, row; + int denom1, denom2; + + move(LIST_LINE, LIST_COL); + clrtobot(); + printw("Words you found (%d):", npwords); + refresh(); + move(LIST_LINE + 1, LIST_COL); + prtable(pword, npwords, 0, ncols, prword, prwidth); + + getyx(stdscr, row, col); + move(row + 1, col); + printw("Words you missed (%d):", nmwords); + refresh(); + move(row + 2, col); + prtable(mword, nmwords, 0, ncols, prword, prwidth); + + denom1 = npwords + nmwords; + denom2 = tnpwords + tnmwords; + + move(SCORE_LINE, SCORE_COL); + printw("Percentage: %0.2f%% (%0.2f%% over %d game%s)\n", + denom1 ? (100.0 * npwords) / (double) (npwords + nmwords) : 0.0, + denom2 ? (100.0 * tnpwords) / (double) (tnpwords + tnmwords) : 0.0, + ngames, ngames > 1 ? "s" : ""); +} + +static void +prword(const char *const base[], int indx) +{ + printw("%s", base[indx]); +} + +static int +prwidth(const char *const base[], int indx) +{ + return (strlen(base[indx])); +} + +/* + * Main input routine + * + * - doesn't accept words longer than MAXWORDLEN or containing caps + */ +char * +get_line(char *q) +{ + int ch, done; + char *p; + int row, col; + + p = q; + done = 0; + while (!done) { + ch = timerch(); + switch (ch) { + case '\n': + case '\r': + case ' ': + done = 1; + break; + case '\e': + findword(); + break; + case '\177': /* */ + case CTRL('h'): /* */ + if (p == q) + break; + p--; + getyx(stdscr, row, col); + move(row, col - 1); + clrtoeol(); + refresh(); + break; + case CTRL('u'): /* <^u> */ + case CTRL('w'): /* <^w> */ + if (p == q) + break; + getyx(stdscr, row, col); + move(row, col - (int) (p - q)); + p = q; + clrtoeol(); + refresh(); + break; +#ifdef SIGTSTP + case CTRL('z'): /* <^z> */ + stop_catcher(0); + break; +#endif + case CTRL('s'): /* <^s> */ + stoptime(); + printw(""); + refresh(); + while ((ch = inputch()) != '\021' && ch != '\023') + ; + move(crow, ccol); + clrtoeol(); + refresh(); + starttime(); + break; + case CTRL('c'): /* <^c> */ + cleanup(); + exit(0); + /*NOTREACHED*/ + case CTRL('d'): /* <^d> */ + done = 1; + ch = EOF; + break; + case CTRL('r'): /* <^l> */ + case CTRL('l'): /* <^r> */ + redraw(); + break; + case '?': + stoptime(); + if (help() < 0) + showstr("Can't open help file", 1); + touchwin(stdscr); + starttime(); + break; + default: + if (!islower(ch)) + break; + if ((int) (p - q) == MAXWORDLEN) { + p = q; + badword(); + break; + } + *p++ = ch; + addch(ch); + refresh(); + break; + } + } + *p = '\0'; + if (ch == EOF) + return (NULL); + return(q); +} + +int +inputch(void) +{ + return (getch() & 0177); +} + +void +redraw(void) +{ + clearok(stdscr, 1); + refresh(); +} + +void +flushin(FILE *fp) +{ + + (void) tcflush(fileno(fp), TCIFLUSH); +} + +static int gone; + +/* + * Stop the game timer + */ +static void +stoptime(void) +{ + time_t t; + + (void)time(&t); + gone = (int) (t - start_t); +} + +/* + * Restart the game timer + */ +static void +starttime(void) +{ + time_t t; + + (void)time(&t); + start_t = t - (long) gone; +} + +/* + * Initialize for the display of the player's words as they are typed + * This display starts at (LIST_LINE, LIST_COL) and goes "down" until the last + * line. After the last line a new column is started at LIST_LINE + * Keep track of each column position for showword() + * There is no check for exceeding COLS + */ +void +startwords(void) +{ + crow = LIST_LINE; + ccol = LIST_COL; + maxw = 0; + ncolstarts = 1; + colstarts[0] = LIST_COL; + move(LIST_LINE, LIST_COL); + refresh(); +} + +/* + * Add a word to the list and start a new column if necessary + * The maximum width of the current column is maintained so we know where + * to start the next column + */ +void +addword(const char *w) +{ + int n; + + if (crow == lastline) { + crow = LIST_LINE; + ccol += (maxw + 5); + colstarts[ncolstarts++] = ccol; + maxw = 0; + move(crow, ccol); + } + else { + move(++crow, ccol); + if ((n = strlen(w)) > maxw) + maxw = n; + } + refresh(); +} + +/* + * The current word is unacceptable so erase it + */ +void +badword(void) +{ + + move(crow, ccol); + clrtoeol(); + refresh(); +} + +/* + * Highlight the nth word in the list (starting with word 0) + * No check for wild arg + */ +void +showword(int n) +{ + int col, row; + + row = LIST_LINE + n % (lastline - LIST_LINE + 1); + col = colstarts[n / (lastline - LIST_LINE + 1)]; + move(row, col); + standout(); + printw("%s", pword[n]); + standend(); + move(crow, ccol); + refresh(); + delay(15); + move(row, col); + printw("%s", pword[n]); + move(crow, ccol); + refresh(); +} + +/* + * Get a word from the user and check if it is in either of the two + * word lists + * If it's found, show the word on the board for a short time and then + * erase the word + * + * Note: this function knows about the format of the board + */ +void +findword(void) +{ + int c, col, found, i, r, row; + char buf[MAXWORDLEN + 1]; + + getyx(stdscr, r, c); + getword(buf); + found = 0; + for (i = 0; i < npwords; i++) { + if (strcmp(buf, pword[i]) == 0) { + found = 1; + break; + } + } + if (!found) { + for (i = 0; i < nmwords; i++) { + if (strcmp(buf, mword[i]) == 0) { + found = 1; + break; + } + } + } + for (i = 0; i < MAXWORDLEN; i++) + wordpath[i] = -1; + usedbits = 0; + if (!found || checkword(buf, -1, wordpath) == -1) { + move(r, c); + clrtoeol(); + addstr("[???]"); + refresh(); + delay(10); + move(r, c); + clrtoeol(); + refresh(); + return; + } + + standout(); + for (i = 0; wordpath[i] != -1; i++) { + row = BOARD_LINE + (wordpath[i] / 4) * 2 + 1; + col = BOARD_COL + (wordpath[i] % 4) * 4 + 2; + move(row, col); + if (board[wordpath[i]] == 'q') + printw("Qu"); + else + printw("%c", + toupper((unsigned char)board[wordpath[i]])); + move(r, c); + refresh(); + delay(5); + } + + standend(); + + for (i = 0; wordpath[i] != -1; i++) { + row = BOARD_LINE + (wordpath[i] / 4) * 2 + 1; + col = BOARD_COL + (wordpath[i] % 4) * 4 + 2; + move(row, col); + if (board[wordpath[i]] == 'q') + printw("Qu"); + else + printw("%c", + toupper((unsigned char)board[wordpath[i]])); + } + move(r, c); + clrtoeol(); + refresh(); +} + +/* + * Display a string at the current cursor position for the given number of secs + */ +void +showstr(const char *str, int delaysecs) +{ + addstr(str); + refresh(); + delay(delaysecs * 10); + move(crow, ccol); + clrtoeol(); + refresh(); +} + +/* + * Get a valid word and put it in the buffer + */ +static void +getword(char *q) +{ + int ch, col, done, i, row; + char *p; + + done = 0; + i = 0; + p = q; + addch('['); + refresh(); + while (!done && i < MAXWORDLEN - 1) { + ch = getch() & 0177; + switch (ch) { + case '\177': /* */ + case '\010': /* */ + if (p == q) + break; + p--; + getyx(stdscr, row, col); + move(row, col - 1); + clrtoeol(); + break; + case '\025': /* <^u> */ + case '\027': /* <^w> */ + if (p == q) + break; + getyx(stdscr, row, col); + move(row, col - (int) (p - q)); + p = q; + clrtoeol(); + break; + case ' ': + case '\n': + case '\r': + done = 1; + break; + case '\014': /* <^l> */ + case '\022': /* <^r> */ + clearok(stdscr, 1); + refresh(); + break; + default: + if (islower(ch)) { + *p++ = ch; + addch(ch); + i++; + } + break; + } + refresh(); + } + *p = '\0'; + addch(']'); + refresh(); +} + +void +showboard(const char *b) +{ + tty_showboard(b); +} + +void +prompt(const char *mesg) +{ + move(PROMPT_LINE, PROMPT_COL); + printw("%s", mesg); + move(PROMPT_LINE + 1, PROMPT_COL); + refresh(); +} + +static int +tty_setup(void) +{ + if (!initscr()) { + fprintf(stderr, "couldn't initialize screen\n"); + exit (0); + } + raw(); + noecho(); + + /* + * Does curses look at the winsize structure? + * Should handle SIGWINCH ... + */ + nlines = LINES; + lastline = nlines - 1; + ncols = COLS; + + signal(SIGTSTP, stop_catcher); + signal(SIGCONT, cont_catcher); + signal(SIGWINCH, winch_catcher); + return(0); +} + +static void +stop_catcher(int signo __attribute__((unused))) +{ + sigset_t isigset, osigset; + + stoptime(); + noraw(); + echo(); + move(nlines - 1, 0); + refresh(); + + signal(SIGTSTP, SIG_DFL); + sigemptyset(&isigset); + sigaddset(&isigset, SIGTSTP); + sigprocmask(SIG_UNBLOCK, &isigset, &osigset); + kill(0, SIGTSTP); + sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); + signal(SIGTSTP, stop_catcher); +} + +static void +cont_catcher(int signo __attribute__((unused))) +{ + noecho(); + raw(); + clearok(stdscr, 1); + move(crow, ccol); + refresh(); + starttime(); +} + +/* + * The signal is caught but nothing is done about it... + * It would mean reformatting the entire display + */ +static void +winch_catcher(int signo __attribute__((unused))) +{ + struct winsize win; + + (void) signal(SIGWINCH, winch_catcher); + (void) ioctl(fileno(stdout), TIOCGWINSZ, &win); + /* + LINES = win.ws_row; + COLS = win.ws_col; + */ +} + +static void +tty_cleanup(void) +{ + move(nlines - 1, 0); + refresh(); + noraw(); + echo(); + endwin(); +} + +static void +tty_showboard(const char *b) +{ + int i; + int line; + + clear(); + move(BOARD_LINE, BOARD_COL); + line = BOARD_LINE; + printw("+---+---+---+---+"); + move(++line, BOARD_COL); + for (i = 0; i < 16; i++) { + if (b[i] == 'q') + printw("| Qu"); + else + printw("| %c ", toupper((unsigned char)b[i])); + if ((i + 1) % 4 == 0) { + printw("|"); + move(++line, BOARD_COL); + printw("+---+---+---+---+"); + move(++line, BOARD_COL); + } + } + move(SCORE_LINE, SCORE_COL); + printw("Type '?' for help"); + refresh(); +} diff --git a/boggle/boggle/prtable.c b/boggle/boggle/prtable.c new file mode 100644 index 0000000..63d57e1 --- /dev/null +++ b/boggle/boggle/prtable.c @@ -0,0 +1,127 @@ +/* $NetBSD: prtable.c,v 1.10 2013/10/19 17:23:08 christos Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)prtable.c 8.1 (Berkeley) 6/11/93 + */ + +#include +#ifndef lint +__RCSID("$NetBSD: prtable.c,v 1.10 2013/10/19 17:23:08 christos Exp $"); +#endif /* not lint */ + +#include + +#include "extern.h" + +#define NCOLS 5 + +static int get_maxlen(const char *const [], int, int (*)(const char *const *, int)); + +/* + * Routine to print a table + * Modified from 'ls.c' mods (BJB/83) + * Arguments: + * base - address of first entry + * num - number of entries + * d_cols - number of columns to use if > 0, "best" size if == 0 + * width - max line width if not zero + * prentry - address of the routine to call to print the string + * length - address of the routine to call to determine the length + * of string to be printed + * + * prtable and length are called with the address of the base and + * an index + */ +void +prtable(const char *const base[], int num, int d_cols, int width, + void (*prentry)(const char *const [], int), + int (*length)(const char *const [], int)) +{ + int c, j; + int a, b, cols, loc, maxlen, nrows, z; + int col, row; + + if (num == 0) + return; + maxlen = get_maxlen(base, num, length) + 1; + if (d_cols > 0) + cols = d_cols; + else + cols = width / maxlen; + if (cols == 0) + cols = NCOLS; + nrows = (num - 1) / cols + 1; + for (a = 1; a <= nrows; a++) { + b = c = z = loc = 0; + for (j = 0; j < num; j++) { + c++; + if (c >= a + b) + break; + } + while (j < num) { + (*prentry)(base, j); + loc += (*length)(base, j); + z++; + b += nrows; + for (j++; j < num; j++) { + c++; + if (c >= a + b) + break; + } + if (j < num) { + while (loc < z * maxlen) { + addch(' '); + loc++; + } + } + } + getyx(stdscr, row, col); + __USE(col); + move(row + 1, 0); + } + refresh(); +} + +static int +get_maxlen(const char *const base[], int num, + int (*length)(const char *const *, int)) +{ + int i, len, max; + + max = (*length)(base, 0); + for (i = 0; i < num; i++) { + if ((len = (*length)(base, i)) > max) + max = len; + } + return(max); +} diff --git a/boggle/boggle/timer.c b/boggle/boggle/timer.c new file mode 100644 index 0000000..dc4dc69 --- /dev/null +++ b/boggle/boggle/timer.c @@ -0,0 +1,119 @@ +/* $NetBSD: timer.c,v 1.10 2005/07/01 16:38:24 jmc Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)timer.c 8.2 (Berkeley) 2/22/94"; +#else +__RCSID("$NetBSD: timer.c,v 1.10 2005/07/01 16:38:24 jmc Exp $"); +#endif +#endif /* not lint */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "bog.h" +#include "extern.h" + +static int waitch(int); + +extern int tlimit; +extern time_t start_t; +extern jmp_buf env; + +/* + * Update the display of the remaining time while waiting for a character + * If time runs out do a longjmp() to the game controlling routine, returning + * non-zero; oth. return the character + * Leave the cursor where it was initially + */ +int +timerch(void) +{ + time_t prevt, t; + int col, remaining, row; + + getyx(stdscr, row, col); + prevt = 0L; + for (;;) { + if (waitch(1) == 1) + break; + time(&t); + if (t == prevt) + continue; + prevt = t; + remaining = tlimit - (int) (t - start_t); + if (remaining < 0) { + longjmp(env, 1); + /*NOTREACHED*/ + } + move(TIMER_LINE, TIMER_COL); + printw("%d:%02d", remaining / 60, remaining % 60); + move(row, col); + refresh(); + } + return (getch() & 0177); +} + +/* + * Wait up to 'delay' microseconds for input to appear + * Returns 1 if input is ready, 0 oth. + */ +static int +waitch(int tdelay) +{ + struct pollfd set[1]; + + set[0].fd = STDIN_FILENO; + set[0].events = POLLIN; + return (poll(set, 1, tdelay)); +} + +void +delay(int tenths) +{ + struct timespec duration; + + duration.tv_nsec = (tenths % 10 ) * 100000000L; + duration.tv_sec = (long) (tenths / 10); + nanosleep(&duration, NULL); +} diff --git a/boggle/boggle/word.c b/boggle/boggle/word.c new file mode 100644 index 0000000..abcc479 --- /dev/null +++ b/boggle/boggle/word.c @@ -0,0 +1,215 @@ +/* $NetBSD: word.c,v 1.9 2006/03/18 09:40:46 rtr Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)word.c 8.1 (Berkeley) 6/11/93"; +#else +__RCSID("$NetBSD: word.c,v 1.9 2006/03/18 09:40:46 rtr Exp $"); +#endif +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include + +#include "bog.h" +#include "extern.h" + +static char *dictspace, *dictend; +static char *sp; + +static int first = 1, lastch = 0; + +extern struct dictindex dictindex[]; +extern int wordlen; + +/* + * Return the next word in the compressed dictionary in 'buffer' or + * NULL on end-of-file + */ +char * +nextword(FILE *fp) +{ + int ch, pcount; + char *p; + static char buf[MAXWORDLEN + 1]; + + if (fp == NULL) { + if (sp == dictend) + return (NULL); + + p = buf + (int) *sp++; + + /* + * The dictionary ends with a null byte + */ + while (*sp >= 'a') + if ((*p++ = *sp++) == 'q') + *p++ = 'u'; + } else { + if (first) { + if ((pcount = getc(fp)) == EOF) + return (NULL); + first = 0; + } else if ((pcount = lastch) == EOF) + return (NULL); + + p = buf + pcount; + + while ((ch = getc(fp)) != EOF && ch >= 'a') + if ((*p++ = ch) == 'q') + *p++ = 'u'; + lastch = ch; + } + wordlen = (int) (p - buf); + *p = '\0'; + return (buf); +} + +/* + * Reset the state of nextword() and do the fseek() + */ +long +dictseek(FILE *fp, long offset, int ptrname) +{ + if (fp == NULL) { + if ((sp = dictspace + offset) >= dictend) + return (-1); + return (0); + } + + first = 1; + return (fseek(fp, offset, ptrname)); +} + +FILE * +opendict(const char *dict) +{ + FILE *fp; + + if ((fp = fopen(dict, "r")) == NULL) + return (NULL); + return (fp); +} + +/* + * Load the given dictionary and initialize the pointers + */ +int +loaddict(FILE *fp) +{ + struct stat statb; + long n; + int st; + char *p; + + if (fstat(fileno(fp), &statb) < 0) { + (void)fclose(fp); + return (-1); + } + + /* + * An extra character (a sentinel) is allocated and set to null + * to improve the expansion loop in nextword(). + */ + if ((dictspace = malloc(statb.st_size + 1)) == NULL) { + (void)fclose(fp); + return (-1); + } + n = (long)statb.st_size; + sp = dictspace; + dictend = dictspace + n; + + p = dictspace; + st = -1; + while (n > 0 && (st = fread(p, 1, BUFSIZ, fp)) > 0) { + p += st; + n -= st; + } + if (st < 0) { + (void)fclose(fp); + warnx("Error reading dictionary"); + return (-1); + } + *p = '\0'; + return (0); +} + +/* + * Dependent on the exact format of the index file: + * Starting offset field begins in column 1 and length field in column 9 + * Taking the easy way out, the input buffer is made "large" and a check + * is made for lines that are too long + */ +int +loadindex(const char *indexfile) +{ + int i, j; + char buf[BUFSIZ]; + FILE *fp; + + if ((fp = fopen(indexfile, "r")) == NULL) { + warn("Can't open '%s'", indexfile); + return (-1); + } + i = 0; + while (fgets(buf, sizeof(buf), fp) != NULL) { + if (strchr(buf, '\n') == NULL) { + warnx("A line in the index file is too long"); + (void) fclose(fp); + return(-1); + } + j = *buf - 'a'; + if (i != j) { + warnx("Bad index order"); + (void) fclose(fp); + return(-1); + } + dictindex[j].start = atol(buf + 1); + dictindex[j].length = atol(buf + 9) - dictindex[j].start; + i++; + } + (void) fclose(fp); + if (i != 26) { + warnx("Bad index length"); + return(-1); + } + return(0); +} diff --git a/boggle/mkdict/Makefile b/boggle/mkdict/Makefile new file mode 100644 index 0000000..079fbd0 --- /dev/null +++ b/boggle/mkdict/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.12 2002/09/18 06:16:40 lukem Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/11/93 + +NOMAN= # defined + +# 20150209 bkw: PROG instead of HOSTPROG +PROG= mkdict +CPPFLAGS+= -I${.CURDIR}/../boggle + +.include diff --git a/boggle/mkdict/mkdict.c b/boggle/mkdict/mkdict.c new file mode 100644 index 0000000..6dc083b --- /dev/null +++ b/boggle/mkdict/mkdict.c @@ -0,0 +1,124 @@ +/* $NetBSD: mkdict.c,v 1.11 2005/07/01 16:38:24 jmc Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = + "@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#if 0 +static char sccsid[] = "@(#)mkdict.c 8.1 (Berkeley) 6/11/93"; +#else +static const char rcsid[] = + "$NetBSD: mkdict.c,v 1.11 2005/07/01 16:38:24 jmc Exp $"; +#endif +#endif /* not lint */ + +/* + * Filter out words that: + * 1) Are not completely made up of lower case letters + * 2) Contain a 'q' not immediately followed by a 'u' + * 3) Are less that 3 characters long + * 4) Are greater than MAXWORDLEN characters long + */ + +#include +#include +#include +#include + +#include "bog.h" + +int +main(int argc, char *argv[]) +{ + char *p, *q; + int ch, common, nwords; + int current, len, prev, qcount; + char buf[2][MAXWORDLEN + 1]; + + prev = 0; + current = 1; + buf[prev][0] = '\0'; + + for (nwords = 1; + fgets(buf[current], MAXWORDLEN + 1, stdin) != NULL; ++nwords) { + if ((p = strchr(buf[current], '\n')) == NULL) { + fprintf(stderr, "word too long: %s\n", buf[current]); + while ((ch = getc(stdin)) != EOF && ch != '\n') + ; + if (ch == EOF) + break; + continue; + } + len = 0; + for (p = buf[current]; *p != '\n'; p++) { + if (!islower((unsigned char)*p)) + break; + if (*p == 'q') { + q = p + 1; + if (*q != 'u') + break; + else { + while ((*q = *(q + 1))) + q++; + } + len++; + } + len++; + } + if (*p != '\n' || len < 3 || len > MAXWORDLEN) + continue; + if (argc == 2 && nwords % atoi(argv[1])) + continue; + + *p = '\0'; + p = buf[current]; + q = buf[prev]; + qcount = 0; + while ((ch = *p++) == *q++ && ch != '\0') + if (ch == 'q') + qcount++; + common = p - buf[current] - 1; + printf("%c%s", common + qcount, p - 1); + prev = !prev; + current = !current; + } + fprintf(stderr, "%d words\n", nwords); + fflush(stdout); + if (ferror(stdout)) { + perror("error writing standard output"); + exit(1); + } + exit(0); +} diff --git a/boggle/mkindex/Makefile b/boggle/mkindex/Makefile new file mode 100644 index 0000000..8f55079 --- /dev/null +++ b/boggle/mkindex/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.10 2002/09/18 06:16:40 lukem Exp $ +# @(#)Makefile 8.1 (Berkeley) 6/11/93 + +NOMAN= # defined + +# 20150209 bkw: PROG instead of HOSTPROG +PROG= mkindex +CPPFLAGS+= -I${.CURDIR}/../boggle + +.include diff --git a/boggle/mkindex/mkindex.c b/boggle/mkindex/mkindex.c new file mode 100644 index 0000000..ddda2bd --- /dev/null +++ b/boggle/mkindex/mkindex.c @@ -0,0 +1,131 @@ +/* $NetBSD: mkindex.c,v 1.11 2009/08/12 05:29:40 dholland Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = "@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; + +#if 0 +static char sccsid[] = "@(#)mkindex.c 8.1 (Berkeley) 6/11/93"; +#else +static char rcsid[] = + "$NetBSD: mkindex.c,v 1.11 2009/08/12 05:29:40 dholland Exp $"; +#endif +#endif /* not lint */ + +#include +#include + +#include "bog.h" + +static char *nextword(FILE *, char *, int *, int *); + +int +main(void) +{ + int clen, rlen, prev, i; + long off, start; + char buf[MAXWORDLEN + 1]; + + prev = '\0'; + off = start = 0L; + while (nextword(stdin, buf, &clen, &rlen) != NULL) { + if (*buf != prev) { + /* + * Boggle expects a full index even if the dictionary + * had no words beginning with some letters. + * So we write out entries for every letter from prev + * to *buf. + */ + if (prev != '\0') + printf("%c %6ld %6ld\n", prev, start, off - 1); + for (i = (prev ? prev + 1 : 'a'); i < *buf; i++) + printf("%c %6ld %6ld\n", i, off, off - 1); + prev = *buf; + start = off; + } + off += clen + 1; + } + printf("%c %6ld %6ld\n", prev, start, off - 1); + for (i = prev + 1; i <= 'z'; i++) + printf("%c %6ld %6ld\n", i, off, off - 1); + fflush(stdout); + if (ferror(stdout)) { + perror("error writing standard output"); + exit(1); + } + exit(0); +} + +/* + * Return the next word in the compressed dictionary in 'buffer' or + * NULL on end-of-file + * Also set clen to the length of the compressed word (for mkindex) and + * rlen to the strlen() of the real word + */ +static char * +nextword(FILE *fp, char *buffer, int *clen, int *rlen) +{ + int ch, pcount; + char *p, *q; + static char buf[MAXWORDLEN + 1]; + static int first = 1; + static int lastch = 0; + + if (first) { + if ((pcount = getc(fp)) == EOF) + return (NULL); + first = 0; + } + else if ((pcount = lastch) == EOF) + return (NULL); + + p = buf + (*clen = pcount); + + while ((ch = getc(fp)) != EOF && ch >= 'a') + *p++ = ch; + lastch = ch; + *p = '\0'; + + *rlen = (int) (p - buf); + *clen = *rlen - *clen; + + p = buf; + q = buffer; + while ((*q++ = *p) != '\0') { + if (*p++ == 'q') + *q++ = 'u'; + } + return (buffer); +} -- cgit v1.2.3