aboutsummaryrefslogtreecommitdiff
path: root/boggle
diff options
context:
space:
mode:
Diffstat (limited to 'boggle')
-rw-r--r--boggle/Makefile40
-rw-r--r--boggle/README66
-rw-r--r--boggle/boggle/Makefile19
-rw-r--r--boggle/boggle/bog.c714
-rw-r--r--boggle/boggle/bog.h83
-rw-r--r--boggle/boggle/boggle.6127
-rw-r--r--boggle/boggle/extern.h62
-rw-r--r--boggle/boggle/help.c105
-rw-r--r--boggle/boggle/helpfile92
-rw-r--r--boggle/boggle/mach.c665
-rw-r--r--boggle/boggle/prtable.c127
-rw-r--r--boggle/boggle/timer.c119
-rw-r--r--boggle/boggle/word.c215
-rw-r--r--boggle/mkdict/Makefile10
-rw-r--r--boggle/mkdict/mkdict.c124
-rw-r--r--boggle/mkindex/Makefile10
-rw-r--r--boggle/mkindex/mkindex.c131
17 files changed, 2709 insertions, 0 deletions
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 <bsd.own.mk>
+
+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 <bsd.prog.mk>
+.include <bsd.subdir.mk>
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 <bsd.own.mk>
+
+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 <bsd.prog.mk>
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 <sys/cdefs.h>
+#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 <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/tty.h>
+
+#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 <setjmp.h>
+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 <space> to begin...");
+ while (inputch() != ' ');
+
+ for (done = 0; !done;) {
+ newgame(bspec);
+ bspec = NULL; /* reset for subsequent games */
+ playgame();
+#ifdef NEW_STYLE
+ prompt("Type <q>uit, <esc> locate, any other key to continue...");
+#else
+ prompt("Type <space> 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 <time.h>
+
+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 <sys/cdefs.h>
+#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 <curses.h>
+#include <stdio.h>
+
+#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 <space> 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: <return> or <linefeed> or <space>
+Delete previous character: <delete> or <backspace>
+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: <space> 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:
+ <esc>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 <sys/cdefs.h>
+#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 <sys/ioctl.h>
+
+#include <ctype.h>
+#include <curses.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <time.h>
+
+#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': /* <del> */
+ case CTRL('h'): /* <bs> */
+ 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("<PAUSE>");
+ 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': /* <del> */
+ case '\010': /* <bs> */
+ 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 <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: prtable.c,v 1.10 2013/10/19 17:23:08 christos Exp $");
+#endif /* not lint */
+
+#include <curses.h>
+
+#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 <sys/cdefs.h>
+#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 <sys/param.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+
+#include <curses.h>
+#include <setjmp.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#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 <sys/cdefs.h>
+#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 <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <bsd.prog.mk>
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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <bsd.prog.mk>
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 <stdio.h>
+#include <stdlib.h>
+
+#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);
+}