[comp.sources.games] v06i046: scrabble - game of scrabble using curses, Part01/02

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