games@tekred.CNA.TEK.COM (04/07/89)
Submitted-by: "Wayne A. Christopher" <faustus@dogwood.Berkeley.EDU>
Posting-number: Volume 6, Issue 46
Archive-name: scrabble/Part01
[This game needs an ANSI C compatable compiler such as gcc (or Turbo C
if you try and port it to a PC), since function prototyping is used.
Not having a copy of gcc around and not wanting to convert the source,
I haven't tested this. -br]
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 1 (of 2)."
# Contents: README MANIFEST Makefile date.h dict.c move.c refresh.c
# scrabble.c scrabble.h tty.c
# Wrapped by billr@saab on Thu Apr 6 12:40:38 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1811 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
X Scrabble 1.0, by Wayne Christopher (faustus@yew.Berkeley.EDU)
X
XThis program plays the board game Scrabble. It uses curses, but it
Xshould be easy for somebody to add X10 or X11 support (if anybody does,
Xplease tell me).
X
XIt plays a pretty strong game, usually getting scores between 350 and
X400. The major problem is its dictionary -- I have a file that
Xcontains most of /usr/dict/words along with plurals, but there are lots
Xof word modifications it doesn't know about (-ing, -ed, ...). There
Xare also "plurals" for adjectives, which are usually wrong. I'm not
Xincluding this file because it's too large, but if you pipe
X/usr/dict/words through the plural program (also in this directory) and
Xmerge the output with /usr/dict/words, and then take out things like
XRoman numerals and any other non-words you find, you should have a
Xpretty good word list. The program will remember when you tell it
Xabout a word it doesn't know, or tell it it's using a bad word (if you
Xgive the -c option), and update the dictionary file so it can learn
Xfrom experience. If anybody knows of a good wordlist, with all the
Xvarious forms of words, or for that matter a wordlist with parts of
Xspeech, please tell me about it.
X
XTo install it, update the DICT_DEF definition at the top of the
XMakefile to indicate where you have installed the dictionary (it's ok
Xto make it /usr/dict/words). You need an ANSI C compiler -- I've only
Xused gcc. The file refresh.c, which is part of curses, is included
Xbecause I had problems when I compiled the program with gcc against the
Xstandard Sun libcurses.a -- I think it has something to do with the
Xfact that refresh.c uses register function arguments. In any case, it
Xwent away when I gcc'ed refresh.c also. On another machine you could
Xprobably take this file out of the Makefile.
X
END_OF_FILE
if test 1811 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(672 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X File Name Archive # Description
X-----------------------------------------------------------
X MANIFEST 1 This shipping list
X Makefile 1
X README 1
X board.c 2
X curses.ext 2
X date.h 1
X dict.c 1
X move.c 1
X player.c 2
X plural.c 2
X refresh.c 1
X savegame.c 2
X scrabble.c 1
X scrabble.h 1
X tty.c 1
X user.c 2
X util.c 2
X util.h 2
END_OF_FILE
if test 672 -ne `wc -c <'MANIFEST'`; then
echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(4846 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X
X# RCS Info: $Revision: 1.2 $ on $Date: 89/03/15 11:16:17 $
X# $Source: /yew3/faustus/src/scrabble/RCS/Makefile,v $
X# Copyright (c) 1987 Wayne A. Christopher, U. C. Berkeley CAD Group
X#
X# Program Makefile
X#
X# This makefile has the standard options "clean", "require", and "install".
X# Also available are "lint", "depend", "tags", "opt", "debug", and "prof".
X# "opt" causes the program to be compiled optimized, "debug" with -g, and
X# "prof" with -pg. As an added bonus, the Makefile remembers the last of
X# these options given.
X
Xwhat: all
X
X#---- Tool specific stuff ----
X
XDICT_DEF = -DDICT_FILE=\"dictionary\"
X
XPROGRAM = scrabble
X
XSRC = \
X board.c \
X dict.c \
X move.c \
X player.c \
X savegame.c \
X scrabble.c \
X tty.c \
X user.c \
X util.c refresh.c
X
XOBJ = \
X board.o \
X dict.o \
X move.o \
X player.o \
X savegame.o \
X scrabble.o \
X tty.o \
X user.o \
X util.o refresh.o
X
XHDR = \
X scrabble.h \
X util.h
X
XSUPPORT = plural
X
XSABER_HDR = scrabble.h
X
XREQUIRE =
X
XSPEC_OPT_LIBS =
X
XSPEC_DEBUG_LIBS =
X
XSPEC_PROF_LIBS =
X
XSPEC_LINT_LIBS =
X
XSPEC_INCLUDE = -I. -I../include
X
XSPEC_DEFINES = $(DICT_DEF)
X
XMAN_SECTION = 1
X
XDOC =
X
XMISC =
X
XCC = gcc -W -fwritable-strings
X
XOPT_LIBS = $(SPEC_OPT_LIBS)
X
XDEBUG_LIBS = $(SPEC_DEBUG_LIBS)
X
XPROF_LIBS = $(SPEC_PROF_LIBS)
X
XOPT_LDFLAGS = -lcurses -ltermlib -lX -lm -O
X
XDEBUG_LDFLAGS = -lcurses -ltermlib -lX -lm -g
X
XPROF_LDFLAGS = -lcurses -ltermlib -lX_p -lm_p -pg
X
XMAN_PAGE = $(PROGRAM).$(MAN_SECTION)
X
X#---- State ----
X
XCFLAGS=-O -g
XLIBS=$(OPT_LIBS)
XLDFLAGS=$(OPT_LDFLAGS)
X
X#---- Generic stuff ----
X
X# EXTDEFINES are things that come from a higher-level Makefile
X
XEXTDEFINES =
X
XDEFINES = $(EXT_DEFINES) $(SPEC_DEFINES)
X
XINCLUDE = $(SPEC_INCLUDE)
X
XLINT_LIBS = $(SPEC_LINT_LIB)
X
XLINT_FLAGS = -DLINT -u -z -lc
X
X.c.o: $*.c
X $(CC) $(DEFINES) $(INCLUDE) $(CFLAGS) -c $*.c
X
Xall: date.h $(PROGRAM) $(SUPPORT) .saberinit
X @echo "All done."
X
X$(PROGRAM): $(OBJ) $(LIBS)
X rm -f $(PROGRAM)
X $(CC) -o $(PROGRAM) $(OBJ) $(LIBS) $(LDFLAGS)
X
X$(SUPPORT): $(SUPPORT).o
X rm -f $(SUPPORT)
X $(CC) -o $(SUPPORT) $(SUPPORT).o $(LIBS) $(LDFLAGS)
X
Xdate.h: /tmp
X @echo \#define DATE \"`date`\" > date.h
X @echo \#define HOST \"`hostname`\" >> date.h
X @echo \#define USER \"`whoami`\" >> date.h
X
X#---- Stuff that changes our state ----
X
Xopt:
X @-if egrep -s '^CFLAGS=-O' Makefile ; then \
X echo already -O ... ; \
X else echo converting from $(CFLAGS) to -O ; \
X sed -e 's/^CFLAGS=.*$$/CFLAGS=-O/' \
X -e 's/^LIBS=.*$$/LIBS=\$$\(OPT_LIBS\)/' \
X -e 's/^LDFLAGS=.*$$/LDFLAGS=\$$\(OPT_LDFLAGS\)/' \
X < Makefile > mktemp ; \
X mv mktemp Makefile ; \
X rm *.o ; \
X fi
X @make $(MFLAGS)
X
Xdebug:
X @-if egrep -s '^CFLAGS=-g' Makefile ; then \
X echo already -g ... ; \
X else echo converting from $(CFLAGS) to -g ; \
X sed -e 's/^CFLAGS=.*$$/CFLAGS=-g/' \
X -e 's/^LIBS=.*$$/LIBS=\$$\(DEBUG_LIBS\)/' \
X -e 's/^LDFLAGS=.*$$/LDFLAGS=\$$\(DEBUG_LDFLAGS\)/' \
X < Makefile > mktemp ; \
X mv mktemp Makefile ; \
X rm *.o ; \
X fi
X @make $(MFLAGS)
X
Xprof:
X @-if egrep -s '^CFLAGS=-pg' Makefile ; then \
X echo already -pg -O ... ; \
X else echo converting from $(CFLAGS) to -pg -O ; \
X sed -e 's/^CFLAGS=.*$$/CFLAGS=-pg -O/' \
X -e 's/^LIBS=.*$$/LIBS=\$$\(PROF_LIBS\)/' \
X -e 's/^LDFLAGS=.*$$/LDFLAGS=\$$\(PROF_LDFLAGS\)/' \
X < Makefile > mktemp ; \
X mv mktemp Makefile ; \
X rm *.o ; \
X fi
X @make $(MFLAGS)
X
Xcheckin:
X ci $(SRC) $(HDR) $(MAN_PAGE) Makefile $(DOC) $(MISC) </dev/null
X rcs -U $(SRC) $(HDR) $(MAN_PAGE) Makefile $(DOC) $(MISC)
X
Xcheckout:
X co $(SRC) $(HDR) $(MAN_PAGE) $(DOC) $(MISC) </dev/null
X
X#---- Stuff for lint ----
X
Xlint: $(SRC) $(HDR)
X lint $(LINT_FLAGS) $(DEFINES) $(INCLUDE) $(SRC) $(LINT_LIBS)
X
X#---- Stuff for "make install" ----
X
X#install: $(INSTALLED) $(MAN_INSTALLED)
X#
X#$(INSTALLED): $(TARGET)
X# cp $(TARGET) $(INSTALLED)
X# strip $(TARGET) $(INSTALLED)
X#
X#$(MAN_INSTALLED): $(MAN_PAGE)
X# cp $(MAN_PAGE) $(MAN_INSTALLED)
X
X#---- Misc junk ----
X
Xdist:
X rdist -Rich $(SRC) $(SUPPSRC) $(HDR) $(MAN_PAGE) $(DOC) \
X $(MISC) Makefile $(DIST)
X
Xprint:
X psgrind -2r -Plps $(HDR) $(SRC) $(SUPPSRC)
X
Xrequire:
X @echo $(REQUIRE)
X
Xclean:
X rm -f $(TARGET) $(SUPPORT) $(OBJ) $(SUPPOBJ) tags *.out foo tmp
X
Xtags: $(SRC) $(HDR) $(SUPPSRC)
X ctags -w -t $(SRC) $(HDR) $(SUPPSRC) > /dev/null 2>&1
X
Xdepend: $(SRC) $(SUPPSRC)
X cc -M $(DEFINES) $(INCLUDE) $(CFLAGS) $(SRC) $(SUPPSRC) > makedep
X echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
X echo '$$r makedep' >>eddep
X echo 'w' >>eddep
X ed - Makefile < eddep
X rm eddep makedep
X echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
X echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
X echo '# see make depend above' >> Makefile
X
X.saberinit: Makefile
X @echo load $(SRC) $(LIBS) $(LDFLAGS) > .saberinit
X
X#-----------------------------------------------------------------
X# DO NOT DELETE THIS LINE -- make depend uses it
X# DEPENDENCIES MUST END AT END OF FILE
X
END_OF_FILE
if test 4846 -ne `wc -c <'Makefile'`; then
echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'date.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'date.h'\"
else
echo shar: Extracting \"'date.h'\" \(84 characters\)
sed "s/^X//" >'date.h' <<'END_OF_FILE'
X#define DATE "Thu Apr 6 12:36:51 PDT 1989"
X#define HOST "saab"
X#define USER "billr"
END_OF_FILE
if test 84 -ne `wc -c <'date.h'`; then
echo shar: \"'date.h'\" unpacked with wrong size!
fi
# end of 'date.h'
fi
if test -f 'dict.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dict.c'\"
else
echo shar: Extracting \"'dict.c'\" \(5716 characters\)
sed "s/^X//" >'dict.c' <<'END_OF_FILE'
X
X/* RCS Info: $Revision: 1.2 $ on $Date: 89/03/15 11:16:27 $
X * $Source: /yew3/faustus/src/scrabble/RCS/dict.c,v $
X * Copyright (c) 1989 Wayne A. Christopher, U. C. Berkeley CS Dept
X * faustus@renoir.berkeley.edu, ucbvax!faustus
X * Permission is granted to modify and re-distribute this code in any manner
X * as long as this notice is preserved. All standard disclaimers apply.
X *
X */
X
X#include "scrabble.h"
X
Xstatic int dicthash(char *word, int tabsize);
Xstatic void getem(word_t **wordp, char *lbuf, int place, char *opt,
X int numopt, int len);
X
Xstatic dict_t *dictionary;
X
Xvoid
Xreaddict(char *file)
X{
X FILE *fp;
X char buf[BSIZE], *e;
X word_t *ww;
X int i, j, k, n, t;
X
X if (!(fp = fopen(file, "r"))) {
X perror(file);
X exit(0);
X }
X fprintf(stderr, "Reading \"%s\" ", file);
X fflush(stderr);
X
X dictionary = (dict_t *) util_malloc(sizeof (dict_t));
X for (i = 0; i < MAX_LENGTH; i++)
X for (j = 0; j < HASH_SIZE; j++)
X dictionary->buckets[i][j] = NULL;
X dictionary->size = 0;
X
X while (fgets(buf, BSIZE, fp)) {
X if (isupper(buf[0]) || !buf[2])
X continue;
X
X for (e = buf; *e; e++)
X ;
X *--e = '\0';
X addword(buf);
X
X#ifdef notdef
X /* Add the plural... */
X s = e - 1;
X if (index("sxz", *s)) {
X *++s = 'e';
X *++s = 's';
X *++s = '\0';
X } else {
X *++s = 's';
X *++s = '\0';
X }
X addword(buf);
X *e = '\0';
X#endif
X }
X
X fprintf(stderr, " %d words.\n", dictionary->size);
X
X if (debug) {
X fprintf(stderr, "Stats:\n");
X for (i = 0; i < MAX_LENGTH; i++) {
X fprintf(stderr, "\t%d:", i + 1);
X n = t = 0;
X for (j = 0; j < HASH_SIZE; j++) {
X for (ww = dictionary->buckets[i][j], k = 0; ww;
X ww = ww->next)
X k++;
X /* fprintf(stderr, " %d", k); */
X if (k)
X n++;
X t += k;
X }
X fprintf(stderr, " %d / %d full, %d total\n",
X n, HASH_SIZE, t);
X }
X }
X
X fclose(fp);
X
X return;
X}
X
Xvoid
Xwritedict(char *file)
X{
X int i, j, k = 0;
X word_t *word;
X FILE *fp;
X char buf[BSIZE];
X
X if (!(fp = fopen(file, "w"))) {
X perror(file);
X return;
X }
X
X for (i = 0; i < MAX_LENGTH; i++)
X for (j = 0; j < HASH_SIZE; j++)
X for (word = dictionary->buckets[i][j]; word;
X word = word->next) {
X fprintf(fp, "%s\n", word->word);
X k++;
X }
X
X fclose(fp);
X
X sprintf(buf, "Wrote %d words to %s.", k, file);
X user_message(buf);
X
X return;
X}
X
Xvoid
Xaddword(char *word)
X{
X int key = dicthash(word, HASH_SIZE);
X int len = strlen(word);
X word_t *ww;
X
X if ((key == -1) || (len > SIZE))
X return;
X
X ww = (word_t *) util_malloc(sizeof (word_t));
X
X ww->word = strsav(word);
X ww->length = len;
X ww->next = dictionary->buckets[len - 1][key];
X dictionary->buckets[len - 1][key] = ww;
X
X dictionary->size++;
X
X if (dictionary->size % 1000 == 0) {
X fprintf(stderr, ".");
X fflush(stderr);
X }
X
X return;
X}
X
Xvoid
Xremword(char *word)
X{
X int key = dicthash(word, HASH_SIZE);
X int len = strlen(word);
X word_t *ww, *lw = NULL;
X
X for (ww = dictionary->buckets[len - 1][key]; ww; ww = ww->next) {
X if (eq(ww->word, word))
X break;
X lw = ww;
X }
X
X assert(ww);
X
X if (lw)
X lw->next = ww->next;
X else
X dictionary->buckets[len - 1][key] = ww->next;
X
X dictionary->size--;
X
X return;
X}
X
Xbool
Xisaword(char *poss)
X{
X word_t *word;
X int len = strlen(poss);
X int key = dicthash(poss, HASH_SIZE);
X
X if (key == -1)
X return (false);
X
X for (word = dictionary->buckets[len - 1][key]; word; word = word->next)
X if (eq(word->word, poss))
X return (true);
X
X return (false);
X}
X
X/* Return a list of the buckets containing all the words we could make with
X * the given letters and are of the given length. Look at all the combinations
X * that include all the required ones and enough optional ones to make
X * up the length.
X */
X
Xword_t *
Xgetpossibles(char *opt, int numopt, char *req, int numreq, int len)
X{
X char lbuf[SIZE];
X int i;
X word_t *word = NULL;
X int wc1 = -1, wc2 = -1;
X
X for (i = 0; i < numreq; i++)
X lbuf[i] = req[i];
X
X if (numreq + numopt < len)
X return (NULL);
X
X for (i = 0; i < numopt; i++)
X if (opt[i] == WILD) {
X if (wc1 == -1)
X wc1 = i;
X else
X wc2 = i;
X }
X
X if (wc1 > -1) {
X for (opt[wc1] = 'a'; opt[wc1] <= 'z'; opt[wc1]++) {
X if (wc2 > -1) {
X for (opt[wc2] = 'a'; opt[wc2] <= 'z';
X opt[wc2]++)
X getem(&word, lbuf, numreq, opt, numopt,
X len);
X opt[wc2] = WILD;
X } else
X getem(&word, lbuf, numreq, opt, numopt, len);
X }
X opt[wc1] = WILD;
X } else
X getem(&word, lbuf, numreq, opt, numopt, len);
X
X return (word);
X}
X
Xstatic void
Xgetem(word_t **wordp, char *lbuf, int place, char *opt, int numopt, int len)
X{
X int key;
X word_t *set, *ww;
X
Xassert(numopt >= 0);
X
X if ((numopt == len - place) || (place == len)) {
X while (place < len)
X lbuf[place++] = *opt++;
X lbuf[len] = '\0';
X key = dicthash(lbuf, HASH_SIZE);
X set = dictionary->buckets[len - 1][key];
X if (set) {
X for (ww = *wordp; ww; ww = ww->next_set)
X if (ww == set)
X break;
X if (ww)
X return;
X
X set->next_set = *wordp;
X *wordp = set;
X#ifdef notdef
X if (debug) {
X fprintf(stderr, "\t\t");
X for (ww = set; ww; ww = ww->next)
X fprintf(stderr, " %s", ww->word);
X fprintf(stderr, "\n");
X }
X#endif
X }
X } else {
X lbuf[place] = *opt;
X getem(wordp, lbuf, place + 1, opt + 1, numopt - 1, len);
X getem(wordp, lbuf, place, opt + 1, numopt - 1, len);
X }
X
X return;
X}
X
X#define NLETTERS 28 /* So it's a multiple of 4. */
X
X/* A return value of -1 denotes that this is a bad word. */
X
Xstatic int
Xdicthash(char *word, int tabsize)
X{
X int i;
X unsigned long result = 0;
X unsigned long letters[NLETTERS];
X char *s;
X
X for (i = 0; i < NLETTERS; i++)
X letters[i] = 0;
X
X for (s = word; *s; s++) {
X if (!isalpha(*s))
X return (-1);
X letters[isupper(*s) ? (*s - 'A') : (*s - 'a')]++;
X }
X
X for (i = 0; i < NLETTERS; i++)
X result ^= letters[i] << i;
X
X return (result % tabsize);
X}
X
END_OF_FILE
if test 5716 -ne `wc -c <'dict.c'`; then
echo shar: \"'dict.c'\" unpacked with wrong size!
fi
# end of 'dict.c'
fi
if test -f 'move.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'move.c'\"
else
echo shar: Extracting \"'move.c'\" \(9358 characters\)
sed "s/^X//" >'move.c' <<'END_OF_FILE'
X
X/* RCS Info: $Revision: 1.2 $ on $Date: 89/03/15 11:16:30 $
X * $Source: /yew3/faustus/src/scrabble/RCS/move.c,v $
X * Copyright (c) 1989 Wayne A. Christopher, U. C. Berkeley CS Dept
X * faustus@renoir.berkeley.edu, ucbvax!faustus
X * Permission is granted to modify and re-distribute this code in any manner
X * as long as this notice is preserved. All standard disclaimers apply.
X *
X */
X
X#include "scrabble.h"
X
Xstatic void dopos(board_t *board, player_t *player, int x, int y,
X bool horiz, move_t *best);
Xstatic int wordpoints(board_t *board, int x, int y, bool horiz, int len,
X char *word, char subc, int wx, int wy, bool allbonuses,
X bool *wilds);
Xstatic bool validword(board_t *board, int x, int y, int len, char subc,
X bool horiz, bool machine, bool check);
Xstatic bool validlocation(board_t *board, int x, int y, bool horiz, int len);
X
Xvoid
Xbestmove(board_t *board, player_t *player, move_t *best)
X{
X int x, y;
X move_t try;
X
X best->points = -1;
X
X for (x = 0; x < SIZE; x++)
X for (y = 0; y < SIZE; y++) {
X dopos(board, player, x, y, true, &try);
X if (try.points > best->points)
X *best = try;
X dopos(board, player, x, y, false, &try);
X if (try.points > best->points)
X *best = try;
X }
X
X return;
X}
X
X#ifdef notdef
X
Xvoid
Xprintmove(int which, move_t *move, FILE *fp)
X{
X fprintf(fp, "Player %d: \"%s\", %s at (%d, %d) for %d points.\n",
X which, move->word, move->horiz ? "horiz" : "vert",
X move->x, move->y, move->points);
X
X return;
X}
X
X#endif
X
Xstatic void
Xdopos(board_t *board, player_t *player, int x, int y, bool horiz, move_t *best)
X{
X char opt[SIZE];
X char req[SIZE];
X int numopt, numreq;
X word_t *words, *set, *word;
X int i, j, len;
X char c;
X move_t try;
X
X best->points = -1;
X
X try.x = x;
X try.y = y;
X try.horiz = horiz;
X
X for (len = 1; horiz ? (x + len <= SIZE) : (y + len <= SIZE); len++) {
X try.length = len;
X
X /* First make sure this is a place we can put a word. */
X if (!validlocation(board, x, y, horiz, len))
X continue;
X
X#ifdef notdef
X if (debug)
X fprintf(stderr, "\t(%d, %d), %s, len %d ---\n",
X x, y, horiz ? "horiz" : "vert", len);
X#endif
X
X /* Make the letter set. */
X for (i = 0, numopt = 0; i < player->numworking; i++)
X opt[i] = player->working[i];
X numopt = player->numworking;
X
X for (j = 0, numreq = 0; j < len; j++) {
X c = boardletter(board, x, y, horiz, j);
X if (something(c))
X req[numreq++] = c;
X }
X if (((horiz ? x : y) + len < SIZE) && something(boardletter
X (board, x, y, horiz, len)))
X continue;
X if (((horiz ? x : y) > 0) && something(boardletter
X (board, x, y, horiz, - 1)))
X continue;
X
X if (numreq + numopt < len)
X break;
X
X#ifdef notdef
X if (debug) {
X fprintf(stderr, "\tReq:");
X for (i = 0; i < numreq; i++)
X fprintf(stderr, " %c", req[i]);
X fprintf(stderr, "\n\tOpt:");
X for (i = 0; i < numopt; i++)
X fprintf(stderr, " %c", opt[i]);
X fprintf(stderr, "\n");
X }
X#endif
X
X words = getpossibles(opt, numopt, req, numreq, len);
X
X for (set = words; set; set = set->next_set)
X for (word = set; word; word = word->next) {
X try.word = word->word;
X for (i = 0; i < SIZE; i++)
X try.wild[i] = false;
X trymove(&try, board, player, false);
X if (try.points > best->points)
X *best = try;
X }
X }
X
X return;
X}
X
Xstatic bool
Xvalidlocation(board_t *board, int x, int y, bool horiz, int len)
X{
X int i;
X
X if (board->virgin) {
X if (((y == SIZE / 2) && (x <= SIZE / 2) &&
X (x + len - 1 >= SIZE / 2)) ||
X ((x == SIZE / 2) && (y <= SIZE / 2) &&
X (y + len - 1 >= SIZE / 2)))
X return (true);
X else
X return (false);
X }
X
X for (i = 0; i < len; i++)
X if (horiz) {
X if (something(boardletter(board, x, y, horiz, i)) ||
X ((y > 0) && something(boardletter
X (board, x, y - 1, horiz, i))) ||
X ((y < SIZE - 1) && something(boardletter
X (board, x, y + 1, horiz, i))))
X return (true);
X } else {
X if (something(boardletter(board, x, y, horiz, i)) ||
X ((x > 0) && something(boardletter
X (board, x - 1, y, horiz, i))) ||
X ((x < SIZE - 1) && something(boardletter
X (board, x + 1, y, horiz, i))))
X return (true);
X }
X
X return (false);
X}
X
X/* This routine returns the value of a move, or -1 if the move would
X * be invalid.
X */
X
Xvoid
Xtrymove(move_t *move, board_t *board, player_t *player, bool check)
X{
X bool used[WORK_SIZE];
X int numused = 0;
X int i, j, x, y;
X int len;
X char c;
X char buf[BSIZE];
X
X/*printf("try %s at %d, %d, %d\n", move->word, move->x, move->y, move->horiz);*/
X
X if (check) {
X sprintf(buf, "Is \"%s\" a word?", move->word);
X if (!user_confirm(buf)) {
X remword(move->word);
X move->points = -1;
X return;
X }
X }
X
X for (i = 0; i < WORK_SIZE; i++) {
X used[i] = false;
X if (iswild(player->working[i]))
X player->working[i] = WILD;
X }
X
X /* First do the validity checks. */
X for (i = 0; i < move->length; i++) {
X c = boardletter(board, move->x, move->y, move->horiz, i);
X if (iswild(c))
X c = maketame(c);
X if (something(c)) {
X if (move->word[i] != c) {
X move->points = -1;
X return;
X }
X } else {
X for (j = 0; j < player->numworking; j++)
X if ((move->word[i] == player->working[j]) &&
X !used[j]) {
X used[j] = true;
X numused++;
X break;
X }
X if (j == player->numworking) {
X for (j = 0; j < player->numworking; j++)
X if ((player->working[j] == WILD) &&
X !used[j]) {
X move->wild[i] = true;
X used[j] = true;
X numused++;
X break;
X }
X if (j == player->numworking) {
X move->points = -1;
X return;
X }
X }
X }
X }
X
X#ifdef notdef
X if (debug)
X fprintf(stderr, "\t(%d, %d) %s: %s", move->x, move->y,
X move->horiz ? "horiz" : "vert", move->word);
X#endif
X
X if (!numused) {
X move->points = -1;
X return;
X }
X
X /* Add up the value of this word. */
X move->points = wordpoints(board, move->x, move->y, move->horiz,
X move->length, move->word, '\0', 0, 0, true,
X move->wild);
X
X if (numused == WORK_SIZE)
X move->points += ALL_BONUS;
X
X if (move->horiz)
X for (i = 0; i < move->length; i++) {
X x = move->x + i;
X if (something(board->letters[x][move->y]))
X continue;
X for (y = move->y; (y > 0) && something(board->
X letters[x][y - 1]); y--)
X ;
X for (len = 1, j = y; (j < SIZE - 1) &&
X (something(board->letters[x][j + 1]) ||
X (j + 1 == move->y)); len++, j++)
X ;
X if (len == 1)
X continue;
X if (validword(board, x, y, len, move->word[i], false,
X player->machine, check))
X move->points += wordpoints(board, x, y, false,
X len, (char *) NULL,
X move->word[i], x, y,
X false, (bool *) NULL);
X else {
X move->points = -1;
X#ifdef notdef
X if (debug)
X fprintf(stderr, "=-1\n");
X#endif
X return;
X }
X }
X else
X for (i = 0; i < move->length; i++) {
X y = move->y + i;
X if (something(board->letters[move->x][y]))
X continue;
X for (x = move->x; (x > 0) && something(board->
X letters[x - 1][y]); x--)
X ;
X for (len = 1, j = x; (j < SIZE - 1) &&
X (something(board->letters[j + 1][y]) ||
X (j + 1 == move->x)); len++, j++)
X ;
X if (len == 1)
X continue;
X if (validword(board, x, y, len, move->word[i], true,
X player->machine, check))
X move->points += wordpoints(board, x, y, true,
X len, (char *) NULL,
X move->word[i], x, y,
X false, (bool *) NULL);
X else {
X move->points = -1;
X#ifdef notdef
X if (debug)
X fprintf(stderr, "=-1\n");
X#endif
X return;
X }
X }
X
X#ifdef notdef
X if (debug)
X fprintf(stderr, "\n");
X#endif
X
X return;
X}
X
Xstatic bool
Xvalidword(board_t *board, int x, int y, int len, char subc, bool horiz,
X bool machine, bool check)
X{
X char buf[BSIZE], qbuf[BSIZE], c;
X int i;
X
X for (i = 0; i < len; i++) {
X c = boardletter(board, x, y, horiz, i);
X if (something(c))
X buf[i] = c;
X else
X buf[i] = subc;
X if (iswild(buf[i]))
X buf[i] = maketame(buf[i]);
X }
X buf[i] = '\0';
X
X#ifdef notdef
X if (debug)
X fprintf(stderr, " %s", buf);
X#endif
X
X if (check) {
X sprintf(qbuf, "Is \"%s\" a word?", buf);
X if (user_confirm(qbuf)) {
X return (true);
X } else {
X remword(buf);
X return (false);
X }
X } else if (isaword(buf)) {
X return (true);
X } else if (!machine) {
X sprintf(qbuf, "I don't think \"%s\" is a word. Do you?", buf);
X if (user_confirm(qbuf)) {
X addword(buf);
X return (true);
X } else
X return (false);
X } else {
X return (false);
X }
X}
X
Xstatic int
Xwordpoints(board_t *board, int x, int y, bool horiz, int len, char *word,
X char subc, int wx, int wy, bool allbonuses, bool *wilds)
X{
X int value = 0;
X int mult = 1;
X int i;
X bonus_t b;
X char c;
X
X if ((horiz ? x : y) + len > SIZE)
X return (-1);
X
X for (i = 0; i < len; i++) {
X if (allbonuses || (horiz && (x + i == wx)) ||
X (!horiz && (y + i == wy)))
X b = boardbonus(board, x, y, horiz, i);
X else
X b = NONE;
X
X c = boardletter(board, x, y, horiz, i);
X
X if (!something(c)) {
X if (word)
X c = word[i];
X else
X c = subc;
X assert(c);
X } else
X b = NONE;
X
X if (wilds && wilds[i])
X c = makewild(c);
X
X switch (b) {
X case NONE:
X value += letterpoints(c);
X break;
X
X case DOUBLE_LETTER:
X value += letterpoints(c) * 2;
X break;
X
X case TRIPLE_LETTER:
X value += letterpoints(c) * 3;
X break;
X
X case DOUBLE_WORD:
X value += letterpoints(c);
X mult *= 2;
X break;
X
X case TRIPLE_WORD:
X value += letterpoints(c);
X mult *= 3;
X break;
X }
X }
X
X value *= mult;
X
X#ifdef notdef
X if (debug)
X fprintf(stderr, "=%d", value);
X#endif
X
X return (value);
X}
X
END_OF_FILE
if test 9358 -ne `wc -c <'move.c'`; then
echo shar: \"'move.c'\" unpacked with wrong size!
fi
# end of 'move.c'
fi
if test -f 'refresh.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'refresh.c'\"
else
echo shar: Extracting \"'refresh.c'\" \(6569 characters\)
sed "s/^X//" >'refresh.c' <<'END_OF_FILE'
X/*
X * Copyright (c) 1981 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)refresh.c 5.2 (Berkeley) 6/8/88";
X#endif /* not lint */
X
X/*
X * make the current screen look like "win" over the area coverd by
X * win.
X */
X
X# include "curses.ext"
X
X# ifdef DEBUG
X# define STATIC
X# else
X# define STATIC static
X# endif
X
XSTATIC short ly, lx;
X
XSTATIC bool curwin;
X
XWINDOW *_win = NULL;
X
Xwrefresh(win)
Xreg WINDOW *win;
X{
X reg short wy;
X reg int retval;
X reg WINDOW *orig;
X
X /*
X * make sure were in visual state
X */
X if (_endwin) {
X _puts(VS);
X _puts(TI);
X _endwin = FALSE;
X }
X
X /*
X * initialize loop parameters
X */
X
X ly = curscr->_cury;
X lx = curscr->_curx;
X wy = 0;
X _win = win;
X curwin = (win == curscr);
X
X if (win->_clear || curscr->_clear || curwin) {
X if ((win->_flags & _FULLWIN) || curscr->_clear) {
X _puts(CL);
X ly = 0;
X lx = 0;
X if (!curwin) {
X curscr->_clear = FALSE;
X curscr->_cury = 0;
X curscr->_curx = 0;
X werase(curscr);
X }
X touchwin(win);
X }
X win->_clear = FALSE;
X }
X if (!CA) {
X if (win->_curx != 0)
X _putchar('\n');
X if (!curwin)
X werase(curscr);
X }
X# ifdef DEBUG
X fprintf(outf, "REFRESH(%0.2o): curwin = %d\n", win, curwin);
X fprintf(outf, "REFRESH:\n\tfirstch\tlastch\n");
X# endif
X for (wy = 0; wy < win->_maxy; wy++) {
X# ifdef DEBUG
X fprintf(outf, "%d\t%d\t%d\n", wy, win->_firstch[wy],
X win->_lastch[wy]);
X# endif
X if (win->_firstch[wy] != _NOCHANGE)
X if (makech(win, wy) == ERR)
X return ERR;
X else {
X if (win->_firstch[wy] >= win->_ch_off)
X win->_firstch[wy] = win->_maxx +
X win->_ch_off;
X if (win->_lastch[wy] < win->_maxx +
X win->_ch_off)
X win->_lastch[wy] = win->_ch_off;
X if (win->_lastch[wy] < win->_firstch[wy])
X win->_firstch[wy] = _NOCHANGE;
X }
X# ifdef DEBUG
X fprintf(outf, "\t%d\t%d\n", win->_firstch[wy],
X win->_lastch[wy]);
X# endif
X }
X
X if (win == curscr)
X domvcur(ly, lx, win->_cury, win->_curx);
X else {
X if (win->_leave) {
X curscr->_cury = ly;
X curscr->_curx = lx;
X ly -= win->_begy;
X lx -= win->_begx;
X if (ly >= 0 && ly < win->_maxy && lx >= 0 &&
X lx < win->_maxx) {
X win->_cury = ly;
X win->_curx = lx;
X }
X else
X win->_cury = win->_curx = 0;
X }
X else {
X domvcur(ly, lx, win->_cury + win->_begy,
X win->_curx + win->_begx);
X curscr->_cury = win->_cury + win->_begy;
X curscr->_curx = win->_curx + win->_begx;
X }
X }
X retval = OK;
Xret:
X _win = NULL;
X fflush(stdout);
X return retval;
X}
X
X/*
X * make a change on the screen
X */
XSTATIC
Xmakech(win, wy)
Xreg WINDOW *win;
Xshort wy;
X{
X reg char *nsp, *csp, *ce;
X reg short wx, lch, y;
X reg int nlsp, clsp; /* last space in lines */
X
X wx = win->_firstch[wy] - win->_ch_off;
X if (wx >= win->_maxx)
X return OK;
X else if (wx < 0)
X wx = 0;
X lch = win->_lastch[wy] - win->_ch_off;
X if (lch < 0)
X return OK;
X else if (lch >= win->_maxx)
X lch = win->_maxx - 1;;
X y = wy + win->_begy;
X
X if (curwin)
X csp = " ";
X else
X csp = &curscr->_y[wy + win->_begy][wx + win->_begx];
X
X nsp = &win->_y[wy][wx];
X if (CE && !curwin) {
X for (ce = &win->_y[wy][win->_maxx - 1]; *ce == ' '; ce--)
X if (ce <= win->_y[wy])
X break;
X nlsp = ce - win->_y[wy];
X }
X
X if (!curwin)
X ce = CE;
X else
X ce = NULL;
X
X while (wx <= lch) {
X if (*nsp != *csp) {
X domvcur(ly, lx, y, wx + win->_begx);
X# ifdef DEBUG
X fprintf(outf, "MAKECH: 1: wx = %d, lx = %d\n", wx, lx);
X# endif
X ly = y;
X lx = wx + win->_begx;
X while (*nsp != *csp && wx <= lch) {
X if (ce != NULL && wx >= nlsp && *nsp == ' ') {
X /*
X * check for clear to end-of-line
X */
X ce = &curscr->_y[ly][COLS - 1];
X while (*ce == ' ')
X if (ce-- <= csp)
X break;
X clsp = ce - curscr->_y[ly] - win->_begx;
X# ifdef DEBUG
X fprintf(outf, "MAKECH: clsp = %d, nlsp = %d\n", clsp, nlsp);
X# endif
X if (clsp - nlsp >= strlen(CE)
X && clsp < win->_maxx) {
X# ifdef DEBUG
X fprintf(outf, "MAKECH: using CE\n");
X# endif
X _puts(CE);
X lx = wx + win->_begx;
X while (wx++ <= clsp)
X *csp++ = ' ';
X return OK;
X }
X ce = NULL;
X }
X /*
X * enter/exit standout mode as appropriate
X */
X if (SO && (*nsp&_STANDOUT) != (curscr->_flags&_STANDOUT)) {
X if (*nsp & _STANDOUT) {
X _puts(SO);
X curscr->_flags |= _STANDOUT;
X }
X else {
X _puts(SE);
X curscr->_flags &= ~_STANDOUT;
X }
X }
X wx++;
X if (wx >= win->_maxx && wy == win->_maxy - 1)
X if (win->_scroll) {
X if ((curscr->_flags&_STANDOUT) &&
X (win->_flags & _ENDLINE))
X if (!MS) {
X _puts(SE);
X curscr->_flags &= ~_STANDOUT;
X }
X if (!curwin)
X _putchar((*csp = *nsp) & 0177);
X else
X _putchar(*nsp & 0177);
X if (win->_flags&_FULLWIN && !curwin)
X scroll(curscr);
X ly = win->_begy+win->_cury;
X lx = win->_begx+win->_curx;
X return OK;
X }
X else if (win->_flags&_SCROLLWIN) {
X lx = --wx;
X return ERR;
X }
X if (!curwin)
X _putchar((*csp++ = *nsp) & 0177);
X else
X _putchar(*nsp & 0177);
X# ifdef FULLDEBUG
X fprintf(outf,
X "MAKECH:putchar(%c)\n", *nsp & 0177);
X# endif
X if (UC && (*nsp & _STANDOUT)) {
X _putchar('\b');
X _puts(UC);
X }
X nsp++;
X }
X# ifdef DEBUG
X fprintf(outf, "MAKECH: 2: wx = %d, lx = %d\n", wx, lx);
X# endif
X if (lx == wx + win->_begx) /* if no change */
X break;
X lx = wx + win->_begx;
X if (lx >= COLS && AM) {
X lx = 0;
X ly++;
X /*
X * xn glitch: chomps a newline after auto-wrap.
X * we just feed it now and forget about it.
X */
X if (XN) {
X _putchar('\n');
X _putchar('\r');
X }
X }
X }
X else if (wx <= lch)
X while (*nsp == *csp && wx <= lch) {
X nsp++;
X if (!curwin)
X csp++;
X ++wx;
X }
X else
X break;
X# ifdef DEBUG
X fprintf(outf, "MAKECH: 3: wx = %d, lx = %d\n", wx, lx);
X# endif
X }
X return OK;
X}
X
X/*
X * perform a mvcur, leaving standout mode if necessary
X */
XSTATIC
Xdomvcur(oy, ox, ny, nx)
Xint oy, ox, ny, nx; {
X
X if (curscr->_flags & _STANDOUT && !MS) {
X _puts(SE);
X curscr->_flags &= ~_STANDOUT;
X }
X mvcur(oy, ox, ny, nx);
X}
END_OF_FILE
if test 6569 -ne `wc -c <'refresh.c'`; then
echo shar: \"'refresh.c'\" unpacked with wrong size!
fi
# end of 'refresh.c'
fi
if test -f 'scrabble.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'scrabble.c'\"
else
echo shar: Extracting \"'scrabble.c'\" \(6426 characters\)
sed "s/^X//" >'scrabble.c' <<'END_OF_FILE'
X
X/* RCS Info: $Revision: 1.3 $ on $Date: 89/03/15 16:33:15 $
X * $Source: /yew3/faustus/src/scrabble/RCS/scrabble.c,v $
X * Copyright (c) 1989 Wayne A. Christopher, U. C. Berkeley CS Dept
X * faustus@renoir.berkeley.edu, ucbvax!faustus
X * Permission is granted to modify and re-distribute this code in any manner
X * as long as this notice is preserved. All standard disclaimers apply.
X *
X */
X
X#include "scrabble.h"
X#include "date.h"
X#include <signal.h>
X
Xbool debug = false;
Xbool userpick = false;
Xbool confirm = false;
X
Xstatic bool domove(board_t *board, player_t **players, int which);
Xstatic void sighandler();
X
Xstatic char *dictfile = DICT_FILE;
X
Xint
Xmain(int ac, char **av)
X{
X board_t *board;
X player_t *players[MAX_PLAYERS];
X bool machine[MAX_PLAYERS];
X int numplayers = 2;
X int whosup = 0;
X int turn = 1;
X char buf[BSIZE];
X char *savedfile = NULL;
X FILE *sfp = NULL;
X int i, j, k;
X
X /*
X printf("\tScrabble 1.0, by Wayne Christopher\n");
X printf("Compiled %s by %s@%s\n\n", DATE, USER, HOST);
X */
X
X srandom(time(0));
X
X for (i = 0; i < MAX_PLAYERS; i++)
X machine[i] = false;
X
X for (ac--, av++; ac && (**av == '-'); ac--, av++) {
X if (eq(*av, "-d")) {
X debug = true;
X } else if (eq(*av, "-p")) {
X userpick = true;
X } else if (eq(*av, "-c")) {
X confirm = true;
X } else if (eq(*av, "-n")) {
X numplayers = atoi(*++av);
X ac--;
X } else if (eq(*av, "-w")) {
X dictfile = *++av;
X ac--;
X } else if (eq(*av, "-m")) {
X machine[atoi(*++av)] = true;
X ac--;
X } else {
X goto usage;
X }
X }
X if (ac > 0)
X savedfile = *av;
X
X if (savedfile) {
X if (!(sfp = fopen(savedfile, "r"))) {
X perror(savedfile);
X savedfile = NULL;
X } else {
X unlink(savedfile);
X }
X }
X
X /* Read the words. */
X readdict(dictfile);
X
X /* Create the board. */
X if (savedfile) {
X board = restoregame(sfp, &numplayers, &whosup, &turn);
X if (!board) {
X savedfile = NULL;
X board = makeboard();
X }
X } else {
X board = makeboard();
X }
X
X /* Create the players. */
X for (i = 0; i < numplayers; i++)
X if (savedfile) {
X players[i] = restoreplayer(sfp);
X } else {
X players[i] = makeplayer(board, i);
X players[i]->machine = machine[i];
X if (machine[i])
X sprintf(buf, "Mach %d", i);
X else {
X printf("Enter name of player %d: ", i);
X fgets(buf, BSIZE, stdin);
X buf[strlen(buf) - 1] = '\0';
X if (!*buf)
X sprintf(buf, "Dude %d", i);
X }
X players[i]->name = strsav(buf);
X }
X
X if (sfp)
X fclose(sfp);
X
X user_init(DEV_TTY, board, players, numplayers);
X
X signal(SIGINT, sighandler);
X
X /* Now take turns. */
X for (;;) {
X user_drawsummary(board, turn);
X while (whosup < numplayers)
X if (!domove(board, players, whosup) ||
X !players[whosup]->numworking)
X goto endgame;
X else
X whosup++;
X turn++;
X whosup = 0;
X }
X
Xendgame:
X if (players[whosup]->numworking > 0)
X whosup = -1;
X for (i = 0; i < numplayers; i++) {
X if (i == whosup)
X continue;
X for (j = 0, k = 0; j < players[i]->numworking; j++) {
Xassert(players[i]->working[j]);
X k += letterpoints(players[i]->working[j]);
X }
X sprintf(buf, "%s has %d points left.", players[i]->name,
X players[i]->score);
X user_message(buf);
X players[i]->score -= k;
X if (whosup >= 0)
X players[whosup]->score += k;
X
X user_drawplayer(players[i], i, false);
X }
X if (whosup >= 0)
X user_drawplayer(players[whosup], whosup, true);
X
X whosup = 0;
X for (i = 1; i < numplayers; i++)
X if (players[i]->score > players[whosup]->score)
X whosup = i;
X
X sprintf(buf, "%s wins with %d points. Hit return to exit...",
X players[whosup]->name, players[whosup]->score);
X (void) user_confirm(buf);
X
X if (user_confirm("Save updated dictionary?"))
X writedict(dictfile);
X
X user_cleanup();
X exit(0);
X
Xusage:
X fprintf(stderr, "Usage: scrabble [ options ] [ saved-game ]\n");
X fprintf(stderr, "\tOptions are: -d Debug mode\n");
X fprintf(stderr, "\t -p Allow user to pick tiles\n");
X fprintf(stderr, "\t -c Confirm all words used\n");
X fprintf(stderr, "\t -n num Allow nnum players\n");
X fprintf(stderr, "\t -m pnum Player pnum is the machine\n");
X fprintf(stderr, "\t -w words Use words for the dictfile\n");
X
X exit(1);
X}
X
Xstatic bool
Xdomove(board_t *board, player_t **players, int which)
X{
X move_t move;
X char buf[BSIZE];
X command_t com;
X
X#ifdef notdef
X if (debug)
X fprintf(stderr, "Moving for player %d...\n", which);
X#endif
X
X user_drawplayer(players[which], which, true);
X
X if (players[which]->numworking == 0)
X return (false);
X
X if (players[which]->machine) {
X do {
X bestmove(board, players[which], &move);
X if (confirm)
X trymove(&move, board, players[which], true);
X } while (confirm && (move.points < 0));
X
X if (move.points < 0)
X return (false);
X
X user_drawmove(board, &move, players[which]);
X playermove(board, players[which], &move);
X boardmove(board, &move);
X user_drawplayer(players[which], which, false);
X } else {
X for (;;) {
X com = user_command(board, players[which], &move);
X switch (com) {
X case NOTHING:
X continue;
X
X case MOVE:
X trymove(&move, board, players[which], false);
X
X if (!isaword(move.word)) {
X sprintf(buf,
X "I don't think \"%s\" is a word. Do you?",
X move.word);
X if (user_confirm(buf)) {
X addword(move.word);
X } else
X continue;
X }
X
X if (move.points < 0) {
X user_message("You can't do that.");
X continue;
X }
X
X user_drawmove(board, &move, players[which]);
X playermove(board, players[which], &move);
X boardmove(board, &move);
X user_drawplayer(players[which], which, false);
X break;
X
X case ADVICE:
X players[which]->machine = true;
X bestmove(board, players[which], &move);
X players[which]->machine = false;
X sprintf(buf,
X "I'd suggest \"%s\" at (%d, %d) %s for %d points.",
X move.word, move.x, move.y,
X move.horiz ? "horiz" : "vert",
X move.points);
X user_message(buf);
X continue;
X
X case TRADEIN:
X user_message("Sorry, can't do that yet.");
X continue;
X
X case SAVE:
X user_message("Sorry, can't do that yet.");
X continue;
X
X case RESTORE:
X user_message("Sorry, can't do that yet.");
X continue;
X
X case HELP:
X user_givehelp();
X continue;
X
X case QUIT:
X if (user_confirm("Save updated dictionary?"))
X writedict(dictfile);
X user_cleanup();
X exit(0);
X }
X
X break;
X }
X }
X
X return (true);
X}
X
Xstatic void
Xsighandler()
X{
X user_cleanup();
X exit(0);
X}
X
END_OF_FILE
if test 6426 -ne `wc -c <'scrabble.c'`; then
echo shar: \"'scrabble.c'\" unpacked with wrong size!
fi
# end of 'scrabble.c'
fi
if test -f 'scrabble.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'scrabble.h'\"
else
echo shar: Extracting \"'scrabble.h'\" \(5035 characters\)
sed "s/^X//" >'scrabble.h' <<'END_OF_FILE'
X
X/* RCS Info: $Revision: 1.2 $ on $Date: 89/03/15 11:16:37 $
X * $Source: /yew3/faustus/src/scrabble/RCS/scrabble.h,v $
X * Copyright (c) 1989 Wayne A. Christopher, U. C. Berkeley CS Dept
X * faustus@renoir.berkeley.edu, ucbvax!faustus
X * Permission is granted to modify and re-distribute this code in any manner
X * as long as this notice is preserved. All standard disclaimers apply.
X *
X */
X
X#include "util.h"
X
X#define AUTHOR "Wayne Christopher"
X#define ADDRESS "faustus@yew.Berkeley.EDU"
X#define VERSION "1.0"
X
X#define SIZE 15
X#define WORK_SIZE 7
X#define POOL_SIZE 100
X#define ALL_BONUS 50
X#define NUM_LETTERS 27 /* Plus wildcard. */
X#define MAX_PLAYERS 4
X
X#ifndef DICT_FILE
X#define DICT_FILE "/usr/dict/words"
X#endif
X
X#define HASH_SIZE 5003
X#define MAX_LENGTH 15
X#define WILD '*'
X#define ZIP ' '
X
Xtypedef struct board_s board_t;
Xtypedef struct player_s player_t;
Xtypedef struct move_s move_t;
Xtypedef struct dict_s dict_t;
Xtypedef struct word_s word_t;
Xtypedef enum bonus_e bonus_t;
Xtypedef enum command_e command_t;
Xtypedef enum devtype_e devtype_t;
X
Xenum bonus_e {
X NONE = 0,
X DOUBLE_LETTER = 1,
X TRIPLE_LETTER = 2,
X DOUBLE_WORD = 3,
X TRIPLE_WORD = 4
X} ;
X
Xenum command_e {
X NOTHING = 0,
X MOVE = 1,
X TRADEIN = 2,
X SAVE = 3,
X RESTORE = 4,
X HELP = 5,
X ADVICE = 6,
X QUIT = 7
X} ;
X
Xenum devtype_e {
X DEV_TTY = 0,
X DEV_X10 = 1,
X DEV_X11 = 2
X} ;
X
Xstruct board_s {
X char letters[SIZE][SIZE];
X bonus_t bonus[SIZE][SIZE];
X char pool[POOL_SIZE];
X int numleft;
X bool virgin;
X} ;
X
Xstruct player_s {
X char working[WORK_SIZE];
X int numworking;
X int score;
X bool machine;
X char *name;
X} ;
X
Xstruct move_s {
X char *word;
X bool wild[SIZE];
X int x, y;
X int length;
X bool horiz;
X int points;
X} ;
X
X/* The dictionary structure is a hash table, where the hash function is
X * calculated from the number of times each letter appears in the word.
X */
X
Xstruct dict_s {
X word_t *buckets[MAX_LENGTH][HASH_SIZE];
X int size;
X} ;
X
Xstruct word_s {
X char *word;
X int length;
X word_t *next;
X word_t *next_set;
X} ;
X
X#define boardletter(board, x, y, hf, pos) \
X ((hf) ? (board)->letters[(x) + (pos)][(y)] : \
X (board)->letters[(x)][(y) + (pos)])
X#define boardbonus(board, x, y, hf, pos) \
X ((hf) ? (board)->bonus[(x) + (pos)][(y)] : \
X (board)->bonus[(x)][(y) + (pos)])
X#define something(c) ((c) != ZIP)
X#define letterpoints(c) ((iswild(c) || ((c) == WILD)) ? 0 : \
X letterpoint_values[(c) - 'a'])
X#define iswild(c) (isupper(c))
X#define maketame(c) ((c) - 'A' + 'a')
X#define makewild(c) ((c) - 'a' + 'A')
X
X/* scrabble.c */
X
Xextern int main(int ac, char **av);
Xextern dict_t *dictionaries;
Xextern bool debug;
Xextern bool userpick;
X
X/* board.c */
X
Xextern board_t *makeboard();
Xextern void boardmove(board_t *board, move_t *move);
Xextern char pickletter(board_t *board);
Xextern int letterpoint_values[];
X
X/* extern void printboard(board_t *board, FILE *fp); */
X
X/* move.c */
X
Xextern void bestmove(board_t *board, player_t *player, move_t *best);
Xextern void trymove(move_t *move, board_t *board, player_t *player, bool check);
X
X/* extern void printmove(int which, move_t *move, FILE *fp); */
X
X/* dict.c */
X
Xextern void readdict(char *file);
Xextern word_t *getpossibles(char *req, int numreq, char *opt, int numopt,
X int len);
Xextern bool isaword(char *poss);
Xextern void addword(char *word);
Xextern void remword(char *word);
Xextern void writedict(char *file);
X
X/* player.c */
X
Xextern player_t *makeplayer(board_t *board, int num);
Xextern void playermove(board_t *board, player_t *player, move_t *move);
X
X/* extern void printplayer(player_t *player, int num, FILE *fp); */
X
X/* savegame.c */
X
Xextern board_t *restoregame(FILE *fp, int *nump, int *whosup, int *turn);
Xextern player_t *restoreplayer(FILE *fp);
Xextern void savegame(FILE *fp, int nump, int whosup, int turn);
Xextern void saveplayer(FILE *fp);
X
X/* user.c */
X
Xextern void user_init(devtype_t type, board_t *board, player_t *players[],
X int numplayers);
Xextern void user_message(char *message);
Xextern char *user_question(char *message);
Xextern bool user_confirm(char *message);
Xextern command_t user_command(board_t *board, player_t *player, move_t *move);
Xextern void user_drawplayer(player_t *player, int pos, bool up);
Xextern void user_drawsummary(board_t *board, int turn);
Xextern void user_drawmove(board_t *board, move_t *move, player_t *player);
Xextern void user_givehelp();
Xextern void user_update();
Xextern void user_cleanup();
X
X/* extern bool readmove(board_t *board, player_t *player, move_t *move); */
X
X/* tty.c */
X
Xextern void tty_init(board_t *board, player_t *players[], int numplayers);
Xextern void tty_message(char *message);
Xextern char *tty_question(char *message);
Xextern bool tty_confirm(char *message);
Xextern command_t tty_command(board_t *board, player_t *player, move_t *mv);
Xextern void tty_drawplayer(player_t *player, int pos, bool up);
Xextern void tty_drawsummary(board_t *board, int turn);
Xextern void tty_drawmove(board_t *board, move_t *mv, player_t *player);
Xextern void tty_givehelp();
Xextern void tty_update();
Xextern void tty_cleanup();
X
END_OF_FILE
if test 5035 -ne `wc -c <'scrabble.h'`; then
echo shar: \"'scrabble.h'\" unpacked with wrong size!
fi
# end of 'scrabble.h'
fi
if test -f 'tty.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'tty.c'\"
else
echo shar: Extracting \"'tty.c'\" \(8653 characters\)
sed "s/^X//" >'tty.c' <<'END_OF_FILE'
X
X/* RCS Info: $Revision: 1.2 $ on $Date: 89/03/15 16:33:18 $
X * $Source: /yew3/faustus/src/scrabble/RCS/tty.c,v $
X * Copyright (c) 1989 Wayne A. Christopher, U. C. Berkeley CS Dept
X * faustus@renoir.berkeley.edu, ucbvax!faustus
X * Permission is granted to modify and re-distribute this code in any manner
X * as long as this notice is preserved. All standard disclaimers apply.
X *
X */
X
X#include "scrabble.h"
X#include <curses.h>
X#undef bool
X
Xstatic WINDOW *boardwin, *scores, *summary, *dialog;
X#ifdef notdef
Xstatic WINDOW *title;
X#endif
X
Xstatic char lbchar[] = " `\"(<";
Xstatic char rbchar[] = " '\")>";
X
Xstatic int messline = 0;
X
X#define bpos(px, py, x, y) (px) = 3 * (x) + 4; (py) = (y) + 1;
X#define MESS_SIZE 5
X#define beep() putc('\007', stderr); fflush(stderr);
X
Xstatic char *help[] = {
X"Scrabble Version 1.0, by Wayne Christopher (faustus@renoir.Berkeley.EDU) ",
X" ",
X" The rules of the game are the same as those of the board game, and will ",
X" not be described here. The screen is divided up into a board area, ",
X" which the player can move around in, a status and score window to the ",
X" right, and a message window at the bottom. A star appears by the name ",
X" of the player whose turn it is, and if this is not a machine player the ",
X" commands below may be given. The commands H, V, Q, and T terminate the ",
X" player's turn, assuming the word is valid. ",
X" ",
X"Available commands are: ",
X" h, j, k, l : Move the cursor around the board. ",
X" H : Create a horizontal word at the cursor position. ",
X" V : Create a vertical word at the cursor position. ",
X" T : Trade in a number of tiles for new tiles. ",
X" S : Save the game into a file. ",
X" R : Restore a game from a file (loses the current game). ",
X" A : Ask for advice from the computer. ",
X" Q : Quit the game. ",
X" ^L : Redraw the screen. ",
X" ? : Print this help message. "
X} ;
X
Xvoid
Xtty_init(board_t *board, player_t *players[], int numplayers)
X{
X int i, j;
X int x, y;
X
X initscr();
X noecho();
X crmode();
X
X#ifdef notdef
X title = newwin(2, 80, 0, 0);
X#endif
X boardwin = newwin(17, 51, 0, 0);
X scores = newwin(9, 29, 3, 51);
X summary = newwin(3, 29, 14, 51);
X dialog = newwin(0, 80, 18, 0);
X
X#ifdef notdef
X /* Draw the title... */
X wmove(title, 0, 7);
X wprintw(title, "Scrabble %s, by %s (%s)", VERSION, AUTHOR, ADDRESS);
X#endif
X
X /* Draw the board... top and bottom... */
X for (i = 0; i < 15; i++) {
X wmove(boardwin, 0, 3 * i + 4);
X wprintw(boardwin, "%-2d", i);
X wmove(boardwin, 16, 3 * i + 4);
X wprintw(boardwin, "%-2d", i);
X }
X
X /* Left and right... */
X for (i = 0; i < 15; i++) {
X wmove(boardwin, 1 + i, 0);
X wprintw(boardwin, "%2d", i);
X wmove(boardwin, 1 + i, 49);
X wprintw(boardwin, "%-2d", i);
X }
X for (i = 0; i < 15; i++)
X for (j = 0; j < 15; j++) {
X bpos(x, y, i, j);
X wmove(boardwin, y, x - 1);
X waddch(boardwin, lbchar[board->bonus[j][i]]);
X wmove(boardwin, y, x);
X waddch(boardwin, '.');
X wmove(boardwin, y, x + 1);
X waddch(boardwin, rbchar[board->bonus[j][i]]);
X }
X
X /* Draw the scores display... */
X wmove(scores, 0, 0);
X wprintw(scores, " Scrabble %s", VERSION);
X wmove(scores, 1, 0);
X wprintw(scores, " by %s", AUTHOR);
X
X wmove(scores, 3, 0);
X wprintw(scores, " Name Score Letters");
X for (i = 0; i < numplayers; i++)
X tty_drawplayer(players[i], i, (i == 0) ? true : false);
X
X /* Draw the summary window. */
X tty_drawsummary(board, 0);
X
X /* The dialog window is blank. */
X
X wrefresh(boardwin);
X
X return;
X}
X
Xvoid
Xtty_message(char *message)
X{
X /* Print the message and clear the line below it. */
X messline = (messline + 1) % MESS_SIZE;
X if (messline < MESS_SIZE - 1) {
X wmove(dialog, messline + 1, 0);
X wclrtoeol(dialog);
X }
X wmove(dialog, messline, 0);
X wclrtoeol(dialog);
X wprintw(dialog, "%s", message);
X
X wrefresh(dialog);
X
X return;
X}
X
Xchar *
Xtty_question(char *message)
X{
X static char buf[BSIZE];
X
X tty_message(message);
X wmove(dialog, messline, strlen(message) + 1);
X wrefresh(dialog);
X echo();
X nocrmode();
X wgetstr(dialog, buf);
X crmode();
X noecho();
X
X return (buf);
X}
X
Xbool
Xtty_confirm(char *message)
X{
X char c;
X
X tty_message(message);
X wmove(dialog, messline, strlen(message) + 1);
X wrefresh(dialog);
X c = wgetch(dialog);
X
X if ((c == 'y') || (c == 'Y'))
X return (true);
X else
X return (false);
X}
X
X/* Let the player move to a place in the board, type 'h' or 'v', then enter
X * a word. Other commands are 'T', 'S', 'R', 'Q', and '?'.
X */
X
Xcommand_t
Xtty_command(board_t *board, player_t *player, move_t *mv)
X{
X int x = 7, y = 7;
X int px, py;
X bool horiz = false, done = false;
X char *word, buf[BSIZE];
X char c;
X int i;
X
X for (;;) {
X bpos(px, py, x, y);
X wmove(boardwin, py, px);
X wrefresh(boardwin);
X c = wgetch(boardwin);
X switch (c) {
X case '\014':
X tty_update();
X break;
X
X case 'h':
X if (x > 0)
X x--;
X else {
X beep();
X }
X break;
X
X case 'j':
X if (y < SIZE - 1)
X y++;
X else {
X beep();
X }
X break;
X
X case 'k':
X if (y > 0)
X y--;
X else {
X beep();
X }
X break;
X
X case 'l':
X if (x < SIZE - 1)
X x++;
X else {
X beep();
X }
X break;
X
X case 'H':
X horiz = true;
X done = true;
X break;
X
X case 'V':
X horiz = false;
X done = true;
X break;
X
X case 'T':
X return (TRADEIN);
X
X case 'S':
X return (SAVE);
X
X case 'R':
X return (RESTORE);
X
X case 'A':
X return (ADVICE);
X
X case 'Q':
X if (tty_confirm("Really quit?"))
X return (QUIT);
X else
X break;
X
X case '?':
X return (HELP);
X
X default:
X beep();
X break;
X }
X
X if (done)
X break;
X }
X
X if (horiz)
X sprintf(buf, "Horiz word at (%d, %d):", x, y);
X else
X sprintf(buf, "Vert word at (%d, %d):", x, y);
X
X word = tty_question(buf);
X
X if (strlen(word) > SIZE)
X word[SIZE] = '\0';
X
X mv->word = strsav(word);
X mv->x = x;
X mv->y = y;
X mv->length = strlen(word);
X mv->horiz = horiz;
X mv->points = 0;
X
X for (i = 0; i < SIZE; i++)
X mv->wild[i] = false;
X
X for (i = 0; i < mv->length; i++) {
X if (!isalpha(mv->word[i])) {
X tty_message("Invalid word.");
X return (NOTHING);
X } else if (isupper(mv->word[i])) {
X mv->word[i] = tolower(mv->word[i]);
X }
X }
X
X return (MOVE);
X}
X
Xvoid
Xtty_drawplayer(player_t *player, int pos, bool up)
X{
X int i;
X
X wmove(scores, pos + 5, 0);
X wprintw(scores, " %c %-6.6s %3d ", up ? '*' : ' ', player->name,
X player->score);
X for (i = 0; i < player->numworking; i++)
X wprintw(scores, " %c", player->working[i]);
X wclrtoeol(scores);
X wmove(scores, pos + 5, 0);
X wrefresh(scores);
X
X return;
X}
X
Xvoid
Xtty_drawsummary(board_t *board, int turn)
X{
X wmove(summary, 0, 0);
X wprintw(summary, " Game turn: %d ", turn);
X wmove(summary, 1, 0);
X wprintw(summary, " Tiles left: %d ", board->numleft);
X wrefresh(summary);
X
X return;
X}
X
Xvoid
Xtty_drawmove(board_t *board, move_t *mv, player_t *player)
X{
X int i, x, y;
X char c;
X char buf[BSIZE];
X
X for (i = 0; i < mv->length; i++) {
X c = mv->word[i];
X if (!mv->wild[i])
X c = toupper(c);
X if (mv->horiz) {
X bpos(x, y, mv->x + i, mv->y);
X } else {
X bpos(x, y, mv->x, mv->y + i);
X }
X
Xassert((x >= 0) && (x < 51) && (y >= 0) && (y < 17));
X
X wmove(boardwin, y, x);
X waddch(boardwin, c);
X }
X wrefresh(boardwin);
X sprintf(buf, "%s: \"%s\" at (%d, %d), %s, %d points.", player->name,
X mv->word, mv->x, mv->y, mv->horiz ? "horiz" : "vert",
X mv->points);
X tty_message(buf);
X
X return;
X}
X
Xvoid
Xtty_givehelp()
X{
X WINDOW *hwin = newwin(24, 80, 0, 0);
X int i;
X
X wclear(hwin);
X overwrite(hwin, stdscr);
X wrefresh(hwin);
X wrefresh(stdscr);
X
X for (i = 0; i < sizeof (help) / sizeof (help[0]); i++) {
X wmove(hwin, i, 0);
X wprintw(hwin, "%s", help[i]);
X }
X
X wmove(hwin, i + 1, 0);
X wprintw(hwin, "Hit return to continue...");
X wrefresh(hwin);
X (void) wgetch(hwin);
X
X wclear(hwin);
X wrefresh(hwin);
X
X delwin(hwin);
X
X touchwin(boardwin);
X touchwin(scores);
X touchwin(summary);
X touchwin(dialog);
X
X tty_update();
X
X return;
X}
X
Xvoid
Xtty_update()
X{
X wrefresh(boardwin);
X wrefresh(scores);
X wrefresh(summary);
X wrefresh(dialog);
X
X return;
X}
X
Xvoid
Xtty_cleanup()
X{
X move(23, 0);
X clrtoeol();
X refresh();
X endwin();
X return;
X}
X
END_OF_FILE
if test 8653 -ne `wc -c <'tty.c'`; then
echo shar: \"'tty.c'\" unpacked with wrong size!
fi
# end of 'tty.c'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked both archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0