diff options
Diffstat (limited to 'games')
36 files changed, 4701 insertions, 7 deletions
diff --git a/games/Makefile b/games/Makefile index f342283519fcb..68b52249eb465 100644 --- a/games/Makefile +++ b/games/Makefile @@ -1,5 +1,5 @@ # @(#)Makefile 8.2 (Berkeley) 3/31/94 -# $Id$ +# $Id: Makefile,v 1.10 1995/12/22 19:21:09 markm Exp $ # XXX missing: chess ching monop [copyright] SUBDIR= adventure arithmetic atc backgammon battlestar bcd boggle bs caesar \ diff --git a/games/boggle/Makefile b/games/boggle/Makefile new file mode 100644 index 0000000000000..eb4452910d333 --- /dev/null +++ b/games/boggle/Makefile @@ -0,0 +1,26 @@ +# @(#)Makefile 8.1 (Berkeley) 6/11/93 + +SUBDIR= boggle mkdict mkindex + +.if exists(${.OBJDIR}/mkdict) +MKDICT= ${.OBJDIR}/mkdict/mkdict +.else +MKDICT= ${.CURDIR}/mkdict/mkdict +.endif +.if exists(${.OBJDIR}/mkindex) +MKINDX= ${.OBJDIR}/mkindex/mkindex +.else +MKINDX= ${.CURDIR}/mkindex/mkindex +.endif + +afterdistribute afterinstall: + ${MKDICT} < ${.CURDIR}/../../share/dict/web2 > \ + ${DESTDIR}/usr/share/games/boggle/dictionary + ${MKINDX} < ${DESTDIR}/usr/share/games/boggle/dictionary > \ + ${DESTDIR}/usr/share/games/boggle/dictindex + chown ${BINOWN}.${BINGRP} ${DESTDIR}/usr/share/games/boggle/dictionary + chmod 444 ${DESTDIR}/usr/share/games/boggle/dictionary + chown ${BINOWN}.${BINGRP} ${DESTDIR}/usr/share/games/boggle/dictindex + chmod 444 ${DESTDIR}/usr/share/games/boggle/dictindex + +.include <bsd.subdir.mk> diff --git a/games/boggle/README b/games/boggle/README new file mode 100644 index 0000000000000..ac87da00bd003 --- /dev/null +++ b/games/boggle/README @@ -0,0 +1,65 @@ + +Bog is a fairly portable simulation of Parker Brother's game of Boggle and +is similar to the 4.[23] BSD "boggle" and Sun's "boggletool". +Bog has not been derived from any proprietary code. +It has been tested on the Sun 3 under SunOS 3.2 and on the Atari 1040ST (MWC). + +What You Need + +You will need curses/termcap and a large word list. +The minix word list or /usr/dict/words will do nicely. +The word list must already be sorted (you can use "sort -c" to check). + +Contents + + README - this file + Makefile + bog.man - half-hearted man page (use the game's help command) + bog.h - configuration and header info + bog.c - machine independent game code + word.c - machine independent word list routines + help.c - (curses) help routine + mach.c - (curses) display code + prtable.c - ditto + timer.c - machine dependent (os) input polling + mkdict.c - convert a word list to a bog dictionary + mkindex.c - create an index file for the bog dictionary + showdict.c - print a bog dictionary to stdout + +Portability + +- I've tried to make bog.c (the program logic) independent of the I/O. + My plan was to make it straightforward to adapt the game to run under a + windowing system (eg., Suntools, GEM). I have no plan to actually do this. + I've stuck to a small subset of the curses routines. +- The program runs with the input in raw mode. +- If you want the running timer you must #define TIMER in bog.h + and insert the input polling code in timer.c for your system. There is + already code there for BSD, SYSV, and ATARI. + +Setup + +1. Check bog.h and Makefile and edit to fit your environment +2. "make all" + This will make all the binaries and create the dictionary and index files +3. Move "dict", "dict.ind", and "helpfile" to where you specified in bog.h +4. Play away + +Distribution + +You may use this software for your enjoyment and you may share it with others. +You may not sell this software or use it for any commercial purposes +whatsoever. All modified versions of the software that you redistribute must +clearly indicate your changes. + +If you come across any bugs or make any changes you'd like to share please +send mail to me rather than posting to the net. + +Enjoy. [But beware: boggle can be addictive!] + +----- +Barry Brachman | UUCP: {alberta,uw-beaver,uunet}! +Dept. of Computer Science| ubc-vision!ubc-csgrads!brachman +Univ. of British Columbia| Internet: brachman@cs.ubc.ca +Vancouver, B.C. V6T 1W5 | brachman%ubc.csnet@csnet-relay.arpa +(604) 228-5010 | brachman@ubc.csnet diff --git a/games/boggle/boggle/Makefile b/games/boggle/boggle/Makefile new file mode 100644 index 0000000000000..0c26112646b26 --- /dev/null +++ b/games/boggle/boggle/Makefile @@ -0,0 +1,15 @@ +# @(#)Makefile 8.1 (Berkeley) 6/11/93 + +PROG= boggle +SRCS= bog.c help.c mach.c prtable.c timer.c word.c +DPADD= ${LIBCURSES} ${LIBTERMCAP} +LDADD= -lcurses -ltermcap +HIDEGAME=hidegame +MAN6= boggle.6 + +beforeinstall: + ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/helpfile \ + ${DESTDIR}/usr/share/games/boggle/helpfile + +.include "../../Makefile.inc" +.include <bsd.prog.mk> diff --git a/games/boggle/boggle/bog.c b/games/boggle/boggle/bog.c new file mode 100644 index 0000000000000..8b1cd50ba1afd --- /dev/null +++ b/games/boggle/boggle/bog.c @@ -0,0 +1,672 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)bog.c 8.1 (Berkeley) 6/11/93"; +#endif /* not lint */ + +#include <ctype.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +#include "bog.h" +#include "extern.h" + +static int compar __P((const void *, const void *)); + +struct dictindex dictindex[26]; + +/* + * Cube position numbering: + * + * 0 1 2 3 + * 4 5 6 7 + * 8 9 A B + * C D E F + */ +static int adjacency[16][16] = { +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + { 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 0 */ + { 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1 */ + { 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 2 */ + { 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 3 */ + { 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, /* 4 */ + { 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, /* 5 */ + { 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 }, /* 6 */ + { 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0 }, /* 7 */ + { 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0 }, /* 8 */ + { 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0 }, /* 9 */ + { 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1 }, /* A */ + { 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1 }, /* B */ + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 }, /* C */ + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0 }, /* D */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1 }, /* E */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 } /* F */ +}; + +static int letter_map[26][16]; + +char board[17]; +int wordpath[MAXWORDLEN + 1]; +int wordlen; /* Length of last word returned by nextword() */ +int usedbits; + +char *pword[MAXPWORDS], pwords[MAXPSPACE], *pwordsp; +int npwords; + +char *mword[MAXMWORDS], mwords[MAXMSPACE], *mwordsp; +int nmwords; + +int ngames = 0; +int tnmwords = 0, tnpwords = 0; + +#include <setjmp.h> +jmp_buf env; + +long start_t; + +static FILE *dictfp; + +int batch; +int debug; +int minlength; +int reuse; +int tlimit; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + long seed = 0; + int ch, done, i, selfuse, sflag; + char *bspec, *p; + + batch = debug = reuse = selfuse = sflag = 0; + bspec = NULL; + minlength = 3; + tlimit = 180; /* 3 minutes is standard */ + + while ((ch = getopt(argc, argv, "bds:t:w:")) != EOF) + switch(ch) { + case 'b': + batch = 1; + break; + case 'd': + debug = 1; + break; + case 's': + sflag = 1; + seed = atol(optarg); + break; + case 't': + if ((tlimit = atoi(optarg)) < 1) + errx(1, "bad time limit"); + break; + case 'w': + if ((minlength = atoi(optarg)) < 3) + errx(1, "min word length must be > 2"); + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argv[0]) { /* any args left? */ + if (strcmp(argv[0], "+") == 0) + reuse = 1; + else if (strcmp(argv[0], "++") == 0) + selfuse = 1; + else if (islower(argv[0][0])) { + if (strlen(argv[0]) != 16) { + usage(); + + } else + /* This board is assumed to be valid... */ + bspec = argv[0]; + } + } + + if (batch && bspec == NULL) + errx(1, "must give both -b and a board setup"); + + if (selfuse) + for (i = 0; i < 16; i++) + adjacency[i][i] = 1; + + if (batch) { + newgame(bspec); + while ((p = batchword(stdin)) != NULL) + (void) printf("%s\n", p); + exit (0); + } + setup(sflag, seed); + prompt("Loading the dictionary..."); + if ((dictfp = opendict(DICT)) == NULL) { + warn("%s", DICT); + cleanup(); + exit(1); + } +#ifdef LOADDICT + if (loaddict(dictfp) < 0) { + warnx("can't load %s", DICT); + cleanup(); + exit(1); + } + (void)fclose(dictfp); + dictfp = NULL; +#endif + if (loadindex(DICTINDEX) < 0) { + warnx("can't load %s", DICTINDEX); + cleanup(); + exit(1); + } + + prompt("Type <space> to begin..."); + while (inputch() != ' '); + + for (done = 0; !done;) { + newgame(bspec); + bspec = NULL; /* reset for subsequent games */ + playgame(); + prompt("Type <space> to continue, any cap to quit..."); + delay(50); /* wait for user to quit typing */ + flushin(stdin); + for (;;) { + ch = inputch(); + if (ch == '\033') + findword(); + else if (ch == '\014' || ch == '\022') /* ^l or ^r */ + redraw(); + else { + if (isupper(ch)) { + done = 1; + break; + } + if (ch == ' ') + break; + } + } + } + cleanup(); + exit (0); +} + +/* + * Read a line from the given stream and check if it is legal + * Return a pointer to a legal word or a null pointer when EOF is reached + */ +char * +batchword(fp) + FILE *fp; +{ + register int *p, *q; + register char *w; + + q = &wordpath[MAXWORDLEN + 1]; + p = wordpath; + while (p < q) + *p++ = -1; + while ((w = nextword(fp)) != NULL) { + if (wordlen < minlength) + continue; + p = wordpath; + while (p < q && *p != -1) + *p++ = -1; + usedbits = 0; + if (checkword(w, -1, wordpath) != -1) + return (w); + } + return (NULL); +} + +/* + * Play a single game + * Reset the word lists from last game + * Keep track of the running stats + */ +void +playgame() +{ + /* Can't use register variables if setjmp() is used! */ + int i, *p, *q; + long t; + char buf[MAXWORDLEN + 1]; + + ngames++; + npwords = 0; + pwordsp = pwords; + nmwords = 0; + mwordsp = mwords; + + time(&start_t); + + q = &wordpath[MAXWORDLEN + 1]; + p = wordpath; + while (p < q) + *p++ = -1; + showboard(board); + startwords(); + if (setjmp(env)) { + badword(); + goto timesup; + } + + while (1) { + if (getline(buf) == NULL) { + if (feof(stdin)) + clearerr(stdin); + break; + } + time(&t); + if (t - start_t >= tlimit) { + badword(); + break; + } + if (buf[0] == '\0') { + int remaining; + + remaining = tlimit - (int) (t - start_t); + (void)snprintf(buf, sizeof(buf), + "%d:%02d", remaining / 60, remaining % 60); + showstr(buf, 1); + continue; + } + if (strlen(buf) < minlength) { + badword(); + continue; + } + + p = wordpath; + while (p < q && *p != -1) + *p++ = -1; + usedbits = 0; + + if (checkword(buf, -1, wordpath) < 0) + badword(); + else { + if (debug) { + (void) printf("["); + for (i = 0; wordpath[i] != -1; i++) + (void) printf(" %d", wordpath[i]); + (void) printf(" ]\n"); + } + for (i = 0; i < npwords; i++) { + if (strcmp(pword[i], buf) == 0) + break; + } + if (i != npwords) { /* already used the word */ + badword(); + showword(i); + } + else if (!validword(buf)) + badword(); + else { + int len; + + len = strlen(buf) + 1; + if (npwords == MAXPWORDS - 1 || + pwordsp + len >= &pwords[MAXPSPACE]) { + warnx("Too many words!"); + cleanup(); + exit(1); + } + pword[npwords++] = pwordsp; + (void) strcpy(pwordsp, buf); + pwordsp += len; + addword(buf); + } + } + } + +timesup: ; + + /* + * Sort the player's words and terminate the list with a null + * entry to help out checkdict() + */ + qsort(pword, npwords, sizeof(pword[0]), compar); + pword[npwords] = NULL; + + /* + * These words don't need to be sorted since the dictionary is sorted + */ + checkdict(); + + tnmwords += nmwords; + tnpwords += npwords; + + results(); +} + +/* + * Check if the given word is present on the board, with the constraint + * that the first letter of the word is adjacent to square 'prev' + * Keep track of the current path of squares for the word + * A 'q' must be followed by a 'u' + * Words must end with a null + * Return 1 on success, -1 on failure + */ +int +checkword(word, prev, path) + char *word; + int prev, *path; +{ + register char *p, *q; + register int i, *lm; + + if (debug) { + (void) printf("checkword(%s, %d, [", word, prev); + for (i = 0; wordpath[i] != -1; i++) + (void) printf(" %d", wordpath[i]); + (void) printf(" ]\n"); + } + + if (*word == '\0') + return (1); + + lm = letter_map[*word - 'a']; + + if (prev == -1) { + char subword[MAXWORDLEN + 1]; + + /* + * Check for letters not appearing in the cube to eliminate some + * recursive calls + * Fold 'qu' into 'q' + */ + p = word; + q = subword; + while (*p != '\0') { + if (*letter_map[*p - 'a'] == -1) + return (-1); + *q++ = *p; + if (*p++ == 'q') { + if (*p++ != 'u') + return (-1); + } + } + *q = '\0'; + while (*lm != -1) { + *path = *lm; + usedbits |= (1 << *lm); + if (checkword(subword + 1, *lm, path + 1) > 0) + return (1); + usedbits &= ~(1 << *lm); + lm++; + } + return (-1); + } + + /* + * A cube is only adjacent to itself in the adjacency matrix if selfuse + * was set, so a cube can't be used twice in succession if only the + * reuse flag is set + */ + for (i = 0; lm[i] != -1; i++) { + if (adjacency[prev][lm[i]]) { + int used; + + used = 1 << lm[i]; + /* + * If necessary, check if the square has already + * been used. + */ + if (!reuse && (usedbits & used)) + continue; + *path = lm[i]; + usedbits |= used; + if (checkword(word + 1, lm[i], path + 1) > 0) + return (1); + usedbits &= ~used; + } + } + *path = -1; /* in case of a backtrack */ + return (-1); +} + +/* + * A word is invalid if it is not in the dictionary + * At this point it is already known that the word can be formed from + * the current board + */ +int +validword(word) + char *word; +{ + register int j; + register char *q, *w; + + j = word[0] - 'a'; + if (dictseek(dictfp, dictindex[j].start, 0) < 0) { + (void) fprintf(stderr, "Seek error\n"); + cleanup(); + exit(1); + } + + while ((w = nextword(dictfp)) != NULL) { + int ch; + + if (*w != word[0]) /* end of words starting with word[0] */ + break; + q = word; + while ((ch = *w++) == *q++ && ch != '\0') + ; + if (*(w - 1) == '\0' && *(q - 1) == '\0') + return (1); + } + if (dictfp != NULL && feof(dictfp)) /* Special case for z's */ + clearerr(dictfp); + return (0); +} + +/* + * Check each word in the dictionary against the board + * Delete words from the machine list that the player has found + * Assume both the dictionary and the player's words are already sorted + */ +void +checkdict() +{ + register char *p, **pw, *w; + register int i; + int prevch, previndex, *pi, *qi, st; + + mwordsp = mwords; + nmwords = 0; + pw = pword; + prevch ='a'; + qi = &wordpath[MAXWORDLEN + 1]; + + (void) dictseek(dictfp, 0L, 0); + while ((w = nextword(dictfp)) != NULL) { + if (wordlen < minlength) + continue; + if (*w != prevch) { + /* + * If we've moved on to a word with a different first + * letter then we can speed things up by skipping all + * words starting with a letter that doesn't appear in + * the cube. + */ + i = (int) (*w - 'a'); + while (i < 26 && letter_map[i][0] == -1) + i++; + if (i == 26) + break; + previndex = prevch - 'a'; + prevch = i + 'a'; + /* + * Fall through if the word's first letter appears in + * the cube (i.e., if we can't skip ahead), otherwise + * seek to the beginning of words in the dictionary + * starting with the next letter (alphabetically) + * appearing in the cube and then read the first word. + */ + if (i != previndex + 1) { + if (dictseek(dictfp, + dictindex[i].start, 0) < 0) { + warnx("seek error in checkdict()"); + cleanup(); + exit(1); + } + continue; + } + } + + pi = wordpath; + while (pi < qi && *pi != -1) + *pi++ = -1; + usedbits = 0; + if (checkword(w, -1, wordpath) == -1) + continue; + + st = 1; + while (*pw != NULL && (st = strcmp(*pw, w)) < 0) + pw++; + if (st == 0) /* found it */ + continue; + if (nmwords == MAXMWORDS || + mwordsp + wordlen + 1 >= &mwords[MAXMSPACE]) { + warnx("too many words!"); + cleanup(); + exit(1); + } + mword[nmwords++] = mwordsp; + p = w; + while (*mwordsp++ = *p++); + } +} + +/* + * Crank up a new game + * If the argument is non-null then it is assumed to be a legal board spec + * in ascending cube order, oth. make a random board + */ +void +newgame(b) + char *b; +{ + register int i, p, q; + char *tmp; + int *lm[26]; + static char *cubes[16] = { + "ednosw", "aaciot", "acelrs", "ehinps", + "eefhiy", "elpstu", "acdemp", "gilruw", + "egkluy", "ahmors", "abilty", "adenvz", + "bfiorx", "dknotu", "abjmoq", "egintv" + }; + + if (b == NULL) { + /* + * Shake the cubes and make the board + */ + i = 0; + while (i < 100) { + p = (int) (random() % 16); + q = (int) (random() % 16); + if (p != q) { + tmp = cubes[p]; + cubes[p] = cubes[q]; + cubes[q] = tmp; + i++; + } + /* else try again */ + } + + for (i = 0; i < 16; i++) + board[i] = cubes[i][random() % 6]; + } + else { + for (i = 0; i < 16; i++) + board[i] = b[i]; + } + board[16] = '\0'; + + /* + * Set up the map from letter to location(s) + * Each list is terminated by a -1 entry + */ + for (i = 0; i < 26; i++) { + lm[i] = letter_map[i]; + *lm[i] = -1; + } + + for (i = 0; i < 16; i++) { + register int j; + + j = (int) (board[i] - 'a'); + *lm[j] = i; + *(++lm[j]) = -1; + } + + if (debug) { + for (i = 0; i < 26; i++) { + int ch, j; + + (void) printf("%c:", 'a' + i); + for (j = 0; (ch = letter_map[i][j]) != -1; j++) + (void) printf(" %d", ch); + (void) printf("\n"); + } + } + +} + +int +compar(p, q) + const void *p, *q; +{ + return (strcmp(*(char **)p, *(char **)q)); +} + +void +usage() +{ + (void) fprintf(stderr, + "usage: bog [-bd] [-s#] [-t#] [-w#] [+[+]] [boardspec]\n"); + exit(1); +} diff --git a/games/boggle/boggle/bog.h b/games/boggle/boggle/bog.h new file mode 100644 index 0000000000000..a25f1d751f40b --- /dev/null +++ b/games/boggle/boggle/bog.h @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bog.h 8.1 (Berkeley) 6/11/93 + */ + +#define LOADDICT 1 /* Load the dictionary for speed */ + +/* + * Locations for the dictionary (generated by mkdict), + * index (generated by mkindex), and helpfile + */ +#define DICT "/usr/share/games/boggle/dictionary" +#define DICTINDEX "/usr/share/games/boggle/dictindex" +#define HELPFILE "/usr/share/games/boggle/helpfile" + +/* + * The theoretical maximum for MAXWORDLEN is ('a' - 1) == 96 + */ +#define MAXWORDLEN 40 /* Maximum word length */ +#define MAXPWORDS 200 /* Maximum number of player's words */ +#define MAXMWORDS 200 /* Maximum number of machine's words */ +#define MAXPSPACE 2000 /* Space for player's words */ +#define MAXMSPACE 4000 /* Space for machines's words */ + +#define MAXCOLS 20 + +/* + * The following determine the screen layout + */ +#define PROMPT_COL 20 +#define PROMPT_LINE 2 + +#define BOARD_COL 0 +#define BOARD_LINE 0 + +#define SCORE_COL 20 +#define SCORE_LINE 0 + +#define LIST_COL 0 +#define LIST_LINE 10 + +#define TIMER_COL 20 +#define TIMER_LINE 2 + +/* + * Internal dictionary index + * Initialized from the file created by mkindex + */ +struct dictindex { + long start; + long length; +}; diff --git a/games/boggle/boggle/boggle.6 b/games/boggle/boggle/boggle.6 new file mode 100644 index 0000000000000..2b9f3053775d8 --- /dev/null +++ b/games/boggle/boggle/boggle.6 @@ -0,0 +1,114 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Barry Brachman. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)boggle.6 8.1 (Berkeley) 6/11/93 +.\" +.TH BOGGLE 6 "June 11, 1993" +.UC +.SH NAME +boggle \- word search game +.SH SYNOPSIS +boggle [-bd] [-s seed] [-t time] [-w length] [+[+]] [boardspec] +.SH DESCRIPTION +The object of +.I boggle +is to find as many words as possible on the Boggle board within the three +minute time limit. +A Boggle board is a four by four arrangement of Boggle cubes, each side of +each cube displaying a letter of the alphabet or `qu'. +Words are formed by finding a sequence of cubes (letters) that are in the +game's dictionary. +The (N+1)th cube in the word must be horizontally, +vertically, or diagonally adjacent to the Nth cube. +Cubes cannot be reused. +Words consist solely of lower case letters and must be at least 3 letters long. +.PP +Command line flags can be given to change the rules of the game. +The +.B + +flag allows a cube to be used multiple times, but not in succession. +The +.B ++ +flag allows the same cubes to be considered adjacent to itself. +.B +A seed other than the time of day is specified by +.B -s#, +where +.B # +is the seed. +The time limit can be changed from the default 3 minutes by using the flag +.B -t#, +where +.B # +is the duration (in seconds) of each game. +The minimum word length can be changed from 3 letters by specifying +.B -w#, +where +.B # +is the minimum number of letters to use. +.PP +A starting board position can be specified on the command line by +listing the board left to right and top to bottom. +.PP +The +.B -b +flag puts +.I boggle +in batch mode. +A +.B boardspec +must also be given. +The dictionary is read from stdin and a list of words appearing in +.B boardspec +is printed to stdout. +.PP +Help is available during play by typing `?'. +More detailed information on the game is given there. +.SH BUGS +If there are a great many words in the cube the final display of the words +may scroll off of the screen. (On a 25 line screen about 130 words can be +displayed.) +.sp 2 +No word can contain a 'q' that is not immediately followed by a 'u'. +.sp 2 +When using the '+' or '++' options the display of words found in the board +doesn't indicate reused cubes. +.SH AUTHOR +Boggle is a trademark of Parker Brothers. +.br +Barry Brachman +.br +Dept. of Computer Science +.br +University of British Columbia diff --git a/games/boggle/boggle/extern.h b/games/boggle/boggle/extern.h new file mode 100644 index 0000000000000..9761c4f66d7c5 --- /dev/null +++ b/games/boggle/boggle/extern.h @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.1 (Berkeley) 6/11/93 + */ + +void addword __P((char *)); +void badword __P((void)); +char *batchword __P((FILE *)); +void checkdict __P((void)); +int checkword __P((char *, int, int *)); +void cleanup __P((void)); +void delay __P((int)); +long dictseek __P((FILE *, long, int)); +void findword __P((void)); +void flushin __P((FILE *)); +char *getline __P((char *)); +void getword __P((char *)); +int help __P((void)); +int inputch __P((void)); +int loaddict __P((FILE *)); +int loadindex __P((char *)); +void newgame __P((char *)); +char *nextword __P((FILE *)); +FILE *opendict __P((char *)); +void playgame __P((void)); +void prompt __P((char *)); +void prtable __P((char *[], + int, int, int, void (*)(char *[], int), int (*)(char *[], int))); +void putstr __P((char *)); +void redraw __P((void)); +void results __P((void)); +int setup __P((int, long)); +void showboard __P((char *)); +void showstr __P((char *, int)); +void showword __P((int)); +void starttime __P((void)); +void startwords __P((void)); +void stoptime __P((void)); +int timerch __P((void)); +void usage __P((void)); +int validword __P((char *)); diff --git a/games/boggle/boggle/help.c b/games/boggle/boggle/help.c new file mode 100644 index 0000000000000..684c0ff60bd9c --- /dev/null +++ b/games/boggle/boggle/help.c @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)help.c 8.1 (Berkeley) 6/11/93"; +#endif /* not lint */ + +#include <curses.h> +#include <stdio.h> + +#include "bog.h" +#include "extern.h" + +int +help() +{ + extern int nlines; + int eof, i; + FILE *fp; + WINDOW *win; + char buf[BUFSIZ]; + + if ((fp = fopen(HELPFILE, "r")) == NULL) + return(-1); + win = newwin(0, 0, 0, 0); + clearok(win, 1); + + eof = 0; + if (ungetc(getc(fp), fp) == EOF) { + wprintw(win, "There doesn't seem to be any help."); + eof = 1; /* Nothing there... */ + } + + while (!eof) { + for (i = 0; i < nlines - 3; i++) { + if (fgets(buf, sizeof(buf), fp) == (char *) NULL) { + eof = 1; + break; + } + if (buf[0] == '.' && buf[1] == '\n') + break; + wprintw(win, "%s", buf); + } + if (eof || ungetc(getc(fp), fp) == EOF) { + eof = 1; + break; + } + wmove(win, nlines - 1, 0); + wprintw(win, + "Type <space> to continue, anything else to quit..."); + wrefresh(win); + if ((inputch() & 0177) != ' ') + break; + wclear(win); + } + + fclose(fp); + if (eof) { + wmove(win, nlines - 1, 0); + wprintw(win, "Hit any key to continue..."); + wrefresh(win); + inputch(); + } + delwin(win); + clearok(stdscr, 1); + refresh(); + return(0); +} diff --git a/games/boggle/boggle/helpfile b/games/boggle/boggle/helpfile new file mode 100644 index 0000000000000..c511efe7e1ad9 --- /dev/null +++ b/games/boggle/boggle/helpfile @@ -0,0 +1,92 @@ + +Commands: + +Enter word: <return> or <linefeed> or <space> +Delete previous character: <delete> or <backspace> +Delete line: <^u> or <^w> +Redraw screen: <^l> or <^r> +Pause game: <^s> +Resume game: <^q> or <^s> +Suspend game (BSD only): <^z> +Give up on current cube: <^d> +Show remaining time: <space> first thing on a line +Show help: ? (Suspends timer until done) +Exit game: <^c> + +(^u means "control u", etc.) + +[Note for users of versions of this program that do not display a timer: +The first word entered after the timer has run out causes a list of all the +words you found, the words you missed, and your running statistics to be +displayed.] + +Any time you are prompted while the board is displayed you can type: + <esc>word +to see where "word" is on the board. + +Usage: + bog [-b] [-d] [-s#] [-t#] [-w#] [+[+]] [boardspec] + + -b: batch mode (boardspec must be present); dictionary read from stdin + -d: debug mode + -s#: use # as the random number seed + -t#: time limit is # seconds instead of default 180 + -w#: minimum word length is # letters instead of default 3 + +: can reuse a cube, but not twice in succession + ++: can reuse cubes arbitrarily + boardspec: the first board to use (use 'q' for 'qu'); e.g.: + bog nolezeebnqieegei +. + Default Rules + +A Boggle board is a four by four arrangement of Boggle cubes. +You have 3 minutes to find as many words as possible in the Boggle board. +Words are formed by finding a sequence of cubes (letters) that are in the +game's dictionary. The (N+1)th cube in the word must be horizontally, +vertically, or diagonally adjacent to the Nth cube. Cubes cannot be reused. +Words consist solely of lower case letters and must be at least 3 letters long. +. + Options + +Command line flags can be given to change the rules of the game. +The '+' flag allows a cube to be used multiple times, but not in succession. +The '++' flag makes each cube adjacent to itself. +The time limit can be changed from the default 3 minutes by using the flag +'-t#', where # is the duration (in seconds) of each game. +The minimum word length can be changed from 3 letters by specifying 'w#', +where # is the minimum number of letters to use. +. + Bugs and Limitations + +The following bugs and problems are known to exist: + +- If there are a great many words in the cube the final display of the words + may scroll off of the screen. (On a 25 line screen about 130 words can be + displayed.) + +- Computing the complete word list can be too slow on small machines. + +- No word can contain a 'q' that is not immediately followed by a 'u'. + +- When using the '+' or '++' options the display of words found in the board + doesn't indicate reused cubes. +. + About This Program + +Permission is given to freely copy and distribute this software providing: + +1) You do not sell it, +2) You do not use it for commercial advantage, +3) If you pass the program on you must make the source code available, and +4) This notice must accompany the distribution + +Please notify the author of any bugs or if you have any suggestions. + +Copyright (c) 1988 +Barry Brachman | UUCP: {alberta,uw-beaver,uunet}! +Dept. of Computer Science| ubc-vision!ubc-csgrads!brachman +Univ. of British Columbia| Internet: brachman@cs.ubc.ca +Vancouver, B.C. V6T 1W5 | brachman%ubc.csnet@csnet-relay.arpa +(604) 228-5010 | brachman@ubc.csnet + +Boggle is a trademark of Parker Brothers. diff --git a/games/boggle/boggle/mach.c b/games/boggle/boggle/mach.c new file mode 100644 index 0000000000000..ea6071145dbd2 --- /dev/null +++ b/games/boggle/boggle/mach.c @@ -0,0 +1,676 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)mach.c 8.1 (Berkeley) 6/11/93"; +#endif /* not lint */ + +/* + * Terminal interface + * + * Input is raw and unechoed + */ +#include <ctype.h> +#include <curses.h> +#include <fcntl.h> +#include <sgtty.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +#include "bog.h" +#include "extern.h" + +static int ccol, crow, maxw; +static int colstarts[MAXCOLS], ncolstarts; +static int lastline; +int ncols, nlines; + +extern char *pword[], *mword[]; +extern int ngames, nmwords, npwords, tnmwords, tnpwords; + +static void cont_catcher __P((int)); +static int prwidth __P((char *[], int)); +static void prword __P((char *[], int)); +static void stop_catcher __P((int)); +static void tty_cleanup __P((void)); +static int tty_setup __P((void)); +static void tty_showboard __P((char *)); +static void winch_catcher __P((int)); + +/* + * Do system dependent initialization + * This is called once, when the program starts + */ +int +setup(sflag, seed) + int sflag; + long seed; +{ + extern int debug; + + if (tty_setup() < 0) + return(-1); + + if (!sflag) + time(&seed); + srandom(seed); + if (debug) + (void) printf("seed = %ld\n", seed); + return(0); +} + +/* + * Do system dependent clean up + * This is called once, just before the program terminates + */ +void +cleanup() +{ + tty_cleanup(); +} + +/* + * Display the player's word list, the list of words not found, and the running + * stats + */ +void +results() +{ + int col, row; + int denom1, denom2; + + move(LIST_LINE, LIST_COL); + clrtobot(); + printw("Words you found (%d):", npwords); + refresh(); + move(LIST_LINE + 1, LIST_COL); + prtable(pword, npwords, 0, ncols, prword, prwidth); + + getyx(stdscr, row, col); + move(row + 1, col); + printw("Words you missed (%d):", nmwords); + refresh(); + move(row + 2, col); + prtable(mword, nmwords, 0, ncols, prword, prwidth); + + denom1 = npwords + nmwords; + denom2 = tnpwords + tnmwords; + + move(SCORE_LINE, SCORE_COL); + printw("Percentage: %0.2f%% (%0.2f%% over %d game%s)\n", + denom1 ? (100.0 * npwords) / (double) (npwords + nmwords) : 0.0, + denom2 ? (100.0 * tnpwords) / (double) (tnpwords + tnmwords) : 0.0, + ngames, ngames > 1 ? "s" : ""); +} + +static void +prword(base, indx) + char *base[]; + int indx; +{ + printw("%s", base[indx]); +} + +static int +prwidth(base, indx) + char *base[]; + int indx; +{ + return (strlen(base[indx])); +} + +/* + * Main input routine + * + * - doesn't accept words longer than MAXWORDLEN or containing caps + */ +char * +getline(q) + char *q; +{ + register int ch, done; + register char *p; + int row, col; + + p = q; + done = 0; + while (!done) { + ch = timerch(); + switch (ch) { + case '\n': + case '\r': + case ' ': + done = 1; + break; + case '\033': + findword(); + break; + case '\177': /* <del> */ + case '\010': /* <bs> */ + if (p == q) + break; + p--; + getyx(stdscr, row, col); + move(row, col - 1); + clrtoeol(); + refresh(); + break; + case '\025': /* <^u> */ + case '\027': /* <^w> */ + if (p == q) + break; + getyx(stdscr, row, col); + move(row, col - (int) (p - q)); + p = q; + clrtoeol(); + refresh(); + break; +#ifdef SIGTSTP + case '\032': /* <^z> */ + stop_catcher(0); + break; +#endif + case '\023': /* <^s> */ + stoptime(); + printw("<PAUSE>"); + refresh(); + while ((ch = inputch()) != '\021' && ch != '\023') + ; + move(crow, ccol); + clrtoeol(); + refresh(); + starttime(); + break; + case '\003': /* <^c> */ + cleanup(); + exit(0); + /*NOTREACHED*/ + case '\004': /* <^d> */ + done = 1; + ch = EOF; + break; + case '\014': /* <^l> */ + case '\022': /* <^r> */ + redraw(); + break; + case '?': + stoptime(); + if (help() < 0) + showstr("Can't open help file", 1); + starttime(); + break; + default: + if (!islower(ch)) + break; + if ((int) (p - q) == MAXWORDLEN) { + p = q; + badword(); + break; + } + *p++ = ch; + addch(ch); + refresh(); + break; + } + } + *p = '\0'; + if (ch == EOF) + return((char *) NULL); + return(q); +} + +int +inputch() +{ + return (getch() & 0177); +} + +void +redraw() +{ + clearok(stdscr, 1); + refresh(); +} + +void +flushin(fp) + FILE *fp; +{ + int arg; + + arg = FREAD; + (void)ioctl(fileno(fp), TIOCFLUSH, &arg); +} + +static int gone; + +/* + * Stop the game timer + */ +void +stoptime() +{ + extern long start_t; + long t; + + (void)time(&t); + gone = (int) (t - start_t); +} + +/* + * Restart the game timer + */ +void +starttime() +{ + extern long start_t; + long t; + + (void)time(&t); + start_t = t - (long) gone; +} + +/* + * Initialize for the display of the player's words as they are typed + * This display starts at (LIST_LINE, LIST_COL) and goes "down" until the last + * line. After the last line a new column is started at LIST_LINE + * Keep track of each column position for showword() + * There is no check for exceeding COLS + */ +void +startwords() +{ + crow = LIST_LINE; + ccol = LIST_COL; + maxw = 0; + ncolstarts = 1; + colstarts[0] = LIST_COL; + move(LIST_LINE, LIST_COL); + refresh(); +} + +/* + * Add a word to the list and start a new column if necessary + * The maximum width of the current column is maintained so we know where + * to start the next column + */ +void +addword(w) + char *w; +{ + int n; + + if (crow == lastline) { + crow = LIST_LINE; + ccol += (maxw + 5); + colstarts[ncolstarts++] = ccol; + maxw = 0; + move(crow, ccol); + } + else { + move(++crow, ccol); + if ((n = strlen(w)) > maxw) + maxw = n; + } + refresh(); +} + +/* + * The current word is unacceptable so erase it + */ +void +badword() +{ + + move(crow, ccol); + clrtoeol(); + refresh(); +} + +/* + * Highlight the nth word in the list (starting with word 0) + * No check for wild arg + */ +void +showword(n) + int n; +{ + int col, row; + + row = LIST_LINE + n % (lastline - LIST_LINE + 1); + col = colstarts[n / (lastline - LIST_LINE + 1)]; + move(row, col); + standout(); + printw("%s", pword[n]); + standend(); + move(crow, ccol); + refresh(); + delay(15); + move(row, col); + printw("%s", pword[n]); + move(crow, ccol); + refresh(); +} + +/* + * Get a word from the user and check if it is in either of the two + * word lists + * If it's found, show the word on the board for a short time and then + * erase the word + * + * Note: this function knows about the format of the board + */ +void +findword() +{ + int c, col, found, i, r, row; + char buf[MAXWORDLEN + 1]; + extern char board[]; + extern int usedbits, wordpath[]; + extern char *mword[], *pword[]; + extern int nmwords, npwords; + + getyx(stdscr, r, c); + getword(buf); + found = 0; + for (i = 0; i < npwords; i++) { + if (strcmp(buf, pword[i]) == 0) { + found = 1; + break; + } + } + if (!found) { + for (i = 0; i < nmwords; i++) { + if (strcmp(buf, mword[i]) == 0) { + found = 1; + break; + } + } + } + for (i = 0; i < MAXWORDLEN; i++) + wordpath[i] = -1; + usedbits = 0; + if (!found || checkword(buf, -1, wordpath) == -1) { + move(r, c); + clrtoeol(); + addstr("[???]"); + refresh(); + delay(10); + move(r, c); + clrtoeol(); + refresh(); + return; + } + + standout(); + for (i = 0; wordpath[i] != -1; i++) { + row = BOARD_LINE + (wordpath[i] / 4) * 2 + 1; + col = BOARD_COL + (wordpath[i] % 4) * 4 + 2; + move(row, col); + if (board[wordpath[i]] == 'q') + printw("Qu"); + else + printw("%c", toupper(board[wordpath[i]])); + move(r, c); + refresh(); + delay(5); + } + + standend(); + + for (i = 0; wordpath[i] != -1; i++) { + row = BOARD_LINE + (wordpath[i] / 4) * 2 + 1; + col = BOARD_COL + (wordpath[i] % 4) * 4 + 2; + move(row, col); + if (board[wordpath[i]] == 'q') + printw("Qu"); + else + printw("%c", toupper(board[wordpath[i]])); + } + move(r, c); + clrtoeol(); + refresh(); +} + +/* + * Display a string at the current cursor position for the given number of secs + */ +void +showstr(str, delaysecs) + char *str; + int delaysecs; +{ + addstr(str); + refresh(); + delay(delaysecs * 10); + move(crow, ccol); + clrtoeol(); + refresh(); +} + +void +putstr(s) + char *s; +{ + addstr(s); +} + +/* + * Get a valid word and put it in the buffer + */ +void +getword(q) + char *q; +{ + int ch, col, done, i, row; + char *p; + + done = 0; + i = 0; + p = q; + addch('['); + refresh(); + while (!done && i < MAXWORDLEN - 1) { + ch = getch() & 0177; + switch (ch) { + case '\177': /* <del> */ + case '\010': /* <bs> */ + if (p == q) + break; + p--; + getyx(stdscr, row, col); + move(row, col - 1); + clrtoeol(); + break; + case '\025': /* <^u> */ + case '\027': /* <^w> */ + if (p == q) + break; + getyx(stdscr, row, col); + move(row, col - (int) (p - q)); + p = q; + clrtoeol(); + break; + case ' ': + case '\n': + case '\r': + done = 1; + break; + case '\014': /* <^l> */ + case '\022': /* <^r> */ + clearok(stdscr, 1); + refresh(); + break; + default: + if (islower(ch)) { + *p++ = ch; + addch(ch); + i++; + } + break; + } + refresh(); + } + *p = '\0'; + addch(']'); + refresh(); +} + +void +showboard(b) + char *b; +{ + tty_showboard(b); +} + +void +prompt(mesg) + char *mesg; +{ + move(PROMPT_LINE, PROMPT_COL); + printw("%s", mesg); + move(PROMPT_LINE + 1, PROMPT_COL); + refresh(); +} + +static int +tty_setup() +{ + initscr(); + raw(); + noecho(); + + /* + * Does curses look at the winsize structure? + * Should handle SIGWINCH ... + */ + nlines = LINES; + lastline = nlines - 1; + ncols = COLS; + + (void) signal(SIGTSTP, stop_catcher); + (void) signal(SIGCONT, cont_catcher); + (void) signal(SIGWINCH, winch_catcher); + return(0); +} + +static void +stop_catcher(signo) + int signo; +{ + stoptime(); + noraw(); + echo(); + move(nlines - 1, 0); + refresh(); + + (void) signal(SIGTSTP, SIG_DFL); + (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP-1))); + (void) kill(0, SIGTSTP); + (void) signal(SIGTSTP, stop_catcher); +} + +static void +cont_catcher(signo) + int signo; +{ + (void) signal(SIGCONT, cont_catcher); + noecho(); + raw(); + clearok(stdscr, 1); + move(crow, ccol); + refresh(); + starttime(); +} + +/* + * The signal is caught but nothing is done about it... + * It would mean reformatting the entire display + */ +static void +winch_catcher(signo) + int signo; +{ + struct winsize win; + + (void) signal(SIGWINCH, winch_catcher); + (void) ioctl(fileno(stdout), TIOCGWINSZ, &win); + /* + LINES = win.ws_row; + COLS = win.ws_col; + */ +} + +static void +tty_cleanup() +{ + move(nlines - 1, 0); + refresh(); + noraw(); + echo(); + endwin(); +} + +static void +tty_showboard(b) + char *b; +{ + register int i; + int line; + + clear(); + move(BOARD_LINE, BOARD_COL); + line = BOARD_LINE; + printw("+---+---+---+---+"); + move(++line, BOARD_COL); + for (i = 0; i < 16; i++) { + if (b[i] == 'q') + printw("| Qu"); + else + printw("| %c ", toupper(b[i])); + if ((i + 1) % 4 == 0) { + printw("|"); + move(++line, BOARD_COL); + printw("+---+---+---+---+"); + move(++line, BOARD_COL); + } + } + move(SCORE_LINE, SCORE_COL); + printw("Type '?' for help"); + refresh(); +} diff --git a/games/boggle/boggle/prtable.c b/games/boggle/boggle/prtable.c new file mode 100644 index 0000000000000..f62e00d8c6f7d --- /dev/null +++ b/games/boggle/boggle/prtable.c @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)prtable.c 8.1 (Berkeley) 6/11/93 + */ + +#include <curses.h> + +#include "extern.h" + +#define NCOLS 5 + +static int get_maxlen __P((char *[], int, int (*)(char **, int))); + +/* + * Routine to print a table + * Modified from 'ls.c' mods (BJB/83) + * Arguments: + * base - address of first entry + * num - number of entries + * d_cols - number of columns to use if > 0, "best" size if == 0 + * width - max line width if not zero + * prentry - address of the routine to call to print the string + * length - address of the routine to call to determine the length + * of string to be printed + * + * prtable and length are called with the the address of the base and + * an index + */ +void +prtable(base, num, d_cols, width, prentry, length) + char *base[]; + int num, d_cols, width; + void (*prentry) __P((char *[], int)); + int (*length) __P((char *[], int)); +{ + register int c, j; + register int a, b, cols, loc, maxlen, nrows, z; + int col, row; + + if (num == 0) + return; + maxlen = get_maxlen(base, num, length) + 1; + if (d_cols > 0) + cols = d_cols; + else + cols = width / maxlen; + if (cols == 0) + cols = NCOLS; + nrows = (num - 1) / cols + 1; + for (a = 1; a <= nrows; a++) { + b = c = z = loc = 0; + for (j = 0; j < num; j++) { + c++; + if (c >= a + b) + break; + } + while (j < num) { + (*prentry)(base, j); + loc += (*length)(base, j); + z++; + b += nrows; + for (j++; j < num; j++) { + c++; + if (c >= a + b) + break; + } + if (j < num) { + while (loc < z * maxlen) { + addch(' '); + loc++; + } + } + } + getyx(stdscr, row, col); + move(row + 1, 0); + } + refresh(); +} + +static int +get_maxlen(base, num, length) + char *base[]; + int num; + int (*length) __P((char **, int)); +{ + register int i, len, max; + + max = (*length)(base, 0); + for (i = 0; i < num; i++) { + if ((len = (*length)(base, i)) > max) + max = len; + } + return(max); +} diff --git a/games/boggle/boggle/timer.c b/games/boggle/boggle/timer.c new file mode 100644 index 0000000000000..f4ed6b8c334ad --- /dev/null +++ b/games/boggle/boggle/timer.c @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)timer.c 8.2 (Berkeley) 2/22/94"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/time.h> + +#include <curses.h> +#include <setjmp.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> + +#include "bog.h" +#include "extern.h" + +static int waitch __P((long)); + +/* + * Update the display of the remaining time while waiting for a character + * If time runs out do a longjmp() to the game controlling routine, returning + * non-zero; oth. return the character + * Leave the cursor where it was initially + */ +int +timerch() +{ + extern int tlimit; + extern long start_t; + extern jmp_buf env; + long prevt, t; + int col, remaining, row; + + getyx(stdscr, row, col); + prevt = 0L; + for (;;) { + if (waitch(1000L) == 1) + break; + time(&t); + if (t == prevt) + continue; + prevt = t; + remaining = tlimit - (int) (t - start_t); + if (remaining < 0) { + longjmp(env, 1); + /*NOTREACHED*/ + } + move(TIMER_LINE, TIMER_COL); + printw("%d:%02d", remaining / 60, remaining % 60); + move(row, col); + refresh(); + } + return (getch() & 0177); +} + +/* + * Wait up to 'delay' microseconds for input to appear + * Returns 1 if input is ready, 0 oth. + */ +static int +waitch(delay) + long delay; +{ + fd_set fdbits; + struct timeval duration; + + duration.tv_sec = 0; + duration.tv_usec = delay; + FD_ZERO(&fdbits); + FD_SET(STDIN_FILENO, &fdbits); + return (select(32, &fdbits, NULL, NULL, &duration)); +} + +void +delay(tenths) + int tenths; +{ + struct timeval duration; + + duration.tv_usec = (tenths % 10 ) * 100000L; + duration.tv_sec = (long) (tenths / 10); + select(32, 0, 0, 0, &duration); +} diff --git a/games/boggle/boggle/word.c b/games/boggle/boggle/word.c new file mode 100644 index 0000000000000..ed4cf28cfaca4 --- /dev/null +++ b/games/boggle/boggle/word.c @@ -0,0 +1,216 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)word.c 8.1 (Berkeley) 6/11/93"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "bog.h" +#include "extern.h" + +static char *dictspace, *dictend; +static char *sp; + +static int first = 1, lastch = 0; + +/* + * Return the next word in the compressed dictionary in 'buffer' or + * NULL on end-of-file + */ +char * +nextword(fp) + FILE *fp; +{ + extern int wordlen; + register int ch, pcount; + register char *p; + static char buf[MAXWORDLEN + 1]; + + if (fp == NULL) { + if (sp == dictend) + return (NULL); + + p = buf + (int) *sp++; + + /* + * The dictionary ends with a null byte + */ + while (*sp >= 'a') + if ((*p++ = *sp++) == 'q') + *p++ = 'u'; + } else { + if (first) { + if ((pcount = getc(fp)) == EOF) + return (NULL); + first = 0; + } else if ((pcount = lastch) == EOF) + return (NULL); + + p = buf + pcount; + + while ((ch = getc(fp)) != EOF && ch >= 'a') + if ((*p++ = ch) == 'q') + *p++ = 'u'; + lastch = ch; + } + wordlen = (int) (p - buf); + *p = '\0'; + return (buf); +} + +/* + * Reset the state of nextword() and do the fseek() + */ +long +dictseek(fp, offset, ptrname) + FILE *fp; + long offset; + int ptrname; +{ + if (fp == NULL) { + if ((sp = dictspace + offset) >= dictend) + return (-1); + return (0); + } + + first = 1; + return (fseek(fp, offset, ptrname)); +} + +FILE * +opendict(dict) + char *dict; +{ + FILE *fp; + + if ((fp = fopen(dict, "r")) == NULL) + return (NULL); + return (fp); +} + +/* + * Load the given dictionary and initialize the pointers + */ +int +loaddict(fp) + FILE *fp; +{ + struct stat statb; + long n; + int st; + char *p; + + if (fstat(fileno(fp), &statb) < 0) { + (void)fclose(fp); + return (-1); + } + + /* + * An extra character (a sentinel) is allocated and set to null + * to improve the expansion loop in nextword(). + */ + if ((dictspace = malloc(statb.st_size + 1)) == NULL) { + (void)fclose(fp); + return (-1); + } + n = (long)statb.st_size; + sp = dictspace; + dictend = dictspace + n; + + p = dictspace; + st = -1; + while (n > 0 && (st = fread(p, 1, BUFSIZ, fp)) > 0) { + p += st; + n -= st; + } + if (st < 0) { + (void)fclose(fp); + (void)fprintf(stderr, "Error reading dictionary\n"); + return (-1); + } + *p = '\0'; + return (0); +} + +/* + * Dependent on the exact format of the index file: + * Starting offset field begins in column 1 and length field in column 9 + * Taking the easy way out, the input buffer is made "large" and a check + * is made for lines that are too long + */ +int +loadindex(indexfile) + char *indexfile; +{ + register int i, j; + char buf[BUFSIZ]; + FILE *fp; + extern struct dictindex dictindex[]; + + if ((fp = fopen(indexfile, "r")) == NULL) { + (void) fprintf(stderr, "Can't open '%s'\n", indexfile); + return (-1); + } + i = 0; + while (fgets(buf, sizeof(buf), fp) != NULL) { + if (strchr(buf, '\n') == NULL) { + (void)fprintf(stderr, + "A line in the index file is too long\n"); + return(-1); + } + j = *buf - 'a'; + if (i != j) { + (void) fprintf(stderr, "Bad index order\n"); + return(-1); + } + dictindex[j].start = atol(buf + 1); + dictindex[j].length = atol(buf + 9) - dictindex[j].start; + i++; + } + if (i != 26) { + (void) fprintf(stderr, "Bad index length\n"); + return(-1); + } + (void) fclose(fp); + return(0); +} diff --git a/games/boggle/mkdict/Makefile b/games/boggle/mkdict/Makefile new file mode 100644 index 0000000000000..83a323a1952b9 --- /dev/null +++ b/games/boggle/mkdict/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 8.1 (Berkeley) 6/11/93 + +PROG= mkdict +CFLAGS+=-I${.CURDIR}/../boggle +NOMAN=noman + +install: + +.include <bsd.prog.mk> diff --git a/games/boggle/mkdict/mkdict.c b/games/boggle/mkdict/mkdict.c new file mode 100644 index 0000000000000..2bec6a88973f7 --- /dev/null +++ b/games/boggle/mkdict/mkdict.c @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mkdict.c 8.1 (Berkeley) 6/11/93"; +#endif /* not lint */ + +/* + * Filter out words that: + * 1) Are not completely made up of lower case letters + * 2) Contain a 'q' not immediately followed by a 'u' + * 3) Are less that 3 characters long + * 4) Are greater than MAXWORDLEN characters long + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "bog.h" + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register char *p, *q; + register int ch, common, n, nwords; + int current, len, prev, qcount; + char buf[2][MAXWORDLEN + 1]; + + prev = 0; + current = 1; + buf[prev][0] = '\0'; + if (argc == 2) + n = atoi(argv[1]); + + for (nwords = 1; + fgets(buf[current], MAXWORDLEN + 1, stdin) != NULL; ++nwords) { + if ((p = index(buf[current], '\n')) == NULL) { + fprintf(stderr, + "mkdict: word too long: %s\n", buf[current]); + while ((ch = getc(stdin)) != EOF && ch != '\n') + ; + if (ch == EOF) + break; + continue; + } + len = 0; + for (p = buf[current]; *p != '\n'; p++) { + if (!islower(*p)) + break; + if (*p == 'q') { + q = p + 1; + if (*q != 'u') + break; + else { + while (*q = *(q + 1)) + q++; + } + len++; + } + len++; + } + if (*p != '\n' || len < 3 || len > MAXWORDLEN) + continue; + if (argc == 2 && nwords % n) + continue; + + *p = '\0'; + p = buf[current]; + q = buf[prev]; + qcount = 0; + while ((ch = *p++) == *q++ && ch != '\0') + if (ch == 'q') + qcount++; + common = p - buf[current] - 1; + printf("%c%s", common + qcount, p - 1); + prev = !prev; + current = !current; + } + fprintf(stderr, "%d words\n", nwords); + exit(0); +} diff --git a/games/boggle/mkindex/Makefile b/games/boggle/mkindex/Makefile new file mode 100644 index 0000000000000..0b8a02f427409 --- /dev/null +++ b/games/boggle/mkindex/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 8.1 (Berkeley) 6/11/93 + +PROG= mkindex +CFLAGS+=-I${.CURDIR}/../boggle +NOMAN=noman + +install: + +.include <bsd.prog.mk> diff --git a/games/boggle/mkindex/mkindex.c b/games/boggle/mkindex/mkindex.c new file mode 100644 index 0000000000000..d9f97fa52c3c7 --- /dev/null +++ b/games/boggle/mkindex/mkindex.c @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Barry Brachman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mkindex.c 8.1 (Berkeley) 6/11/93"; +#endif /* not lint */ + +#include <stdio.h> + +#include "bog.h" + +char *nextword __P((FILE *, char *, int *, int *)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int clen, rlen, prev; + long off, start; + char buf[MAXWORDLEN + 1]; + + prev = '\0'; + off = start = 0L; + while (nextword(stdin, buf, &clen, &rlen) != NULL) { + if (*buf != prev) { + if (prev != '\0') + printf("%c %6ld %6ld\n", prev, start, off - 1); + prev = *buf; + start = off; + } + off += clen + 1; + } + printf("%c %6ld %6ld\n", prev, start, off - 1); + exit(0); +} + +/* + * Return the next word in the compressed dictionary in 'buffer' or + * NULL on end-of-file + * Also set clen to the length of the compressed word (for mkindex) and + * rlen to the strlen() of the real word + */ +char * +nextword(fp, buffer, clen, rlen) + FILE *fp; + char *buffer; + int *clen, *rlen; +{ + register int ch, pcount; + register char *p, *q; + static char buf[MAXWORDLEN + 1]; + static int first = 1; + static int lastch = 0; + + if (first) { + if ((pcount = getc(fp)) == EOF) + return (NULL); + first = 0; + } + else if ((pcount = lastch) == EOF) + return (NULL); + + p = buf + (*clen = pcount); + + while ((ch = getc(fp)) != EOF && ch >= 'a') + *p++ = ch; + lastch = ch; + *p = '\0'; + + *rlen = (int) (p - buf); + *clen = *rlen - *clen; + + p = buf; + q = buffer; + while ((*q++ = *p) != '\0') { + if (*p++ == 'q') + *q++ = 'u'; + } + return (buffer); +} diff --git a/games/bs/Makefile b/games/bs/Makefile index 31498f4b9c88f..6eef432a96482 100644 --- a/games/bs/Makefile +++ b/games/bs/Makefile @@ -1,4 +1,4 @@ -# $Id$ +# $Id: Makefile,v 1.1.1.1 1994/12/03 04:33:28 ache Exp $ PROG= bs MAN6= bs.6 diff --git a/games/grdc/Makefile b/games/grdc/Makefile index 543f4be377db8..d509e67abeb21 100644 --- a/games/grdc/Makefile +++ b/games/grdc/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1.1.1 1994/12/03 04:34:46 ache Exp $ +# $Id: Makefile,v 1.1.1.1 1994/12/04 21:51:19 ache Exp $ PROG= grdc MAN6= grdc.6 diff --git a/games/hack/hack.version.c b/games/hack/hack.version.c index 3ac6868c151a3..0c2febc9864e2 100644 --- a/games/hack/hack.version.c +++ b/games/hack/hack.version.c @@ -1,6 +1,6 @@ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* hack.version.c - version 1.0.3 */ -/* $Header: hack.version.c,v 1.5 85/05/09 00:40:41 aeb Exp $ */ +/* $Header: /home/ncvs/src/games/hack/hack.version.c,v 1.1.1.1 1994/09/04 04:02:54 jkh Exp $ */ #include "date.h" diff --git a/games/phantasia/phantasia.6 b/games/phantasia/phantasia.6 index 5fc64a3e2efcf..128ef8c335df6 100644 --- a/games/phantasia/phantasia.6 +++ b/games/phantasia/phantasia.6 @@ -1,4 +1,4 @@ -.\" $Id$ +.\" $Id: phantasia.6,v 1.2 1996/10/05 22:26:14 wosch Exp $ .\" .de sh .br diff --git a/games/piano/piano.c b/games/piano/piano.c index 69b3476976b0f..a1564e196ff72 100644 --- a/games/piano/piano.c +++ b/games/piano/piano.c @@ -1,7 +1,7 @@ /* * piano.c - a piano emulator */ -static char rcsid[] = "$Id: piano.c,v 1.1.1.1 1995/04/28 17:38:07 jkh Exp $"; +static char rcsid[] = "$Id: piano.c,v 1.2 1995/05/30 03:37:05 rgrimes Exp $"; #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/games/sail/sail.6 b/games/sail/sail.6 index 6fb647be459ca..bf6e4f56659c5 100644 --- a/games/sail/sail.6 +++ b/games/sail/sail.6 @@ -30,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)sail.6 8.2 (Berkeley) 12/30/93 -.\" $Id$ +.\" $Id: sail.6,v 1.2 1996/10/05 22:26:16 wosch Exp $ .\" .TH SAIL 6 "December 30, 1993" .UC 4 diff --git a/games/tetris/Makefile b/games/tetris/Makefile new file mode 100644 index 0000000000000..d545f8383da7b --- /dev/null +++ b/games/tetris/Makefile @@ -0,0 +1,10 @@ +# @(#)Makefile 8.1 (Berkeley) 5/31/93 + +PROG= tetris +SRCS= input.c screen.c shapes.c scores.c tetris.c +MAN6= tetris.6 +DPADD= ${LIBTERMCAP} +LDADD= -ltermcap +HIDEGAME=hidegame + +.include <bsd.prog.mk> diff --git a/games/tetris/input.c b/games/tetris/input.c new file mode 100644 index 0000000000000..48da0884cd76b --- /dev/null +++ b/games/tetris/input.c @@ -0,0 +1,180 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek and Darren F. Provine. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)input.c 8.1 (Berkeley) 5/31/93 + */ + +/* + * Tetris input. + */ + +#include <sys/types.h> +#include <sys/time.h> + +#include <errno.h> +#include <unistd.h> + +#include "input.h" +#include "tetris.h" + +/* return true iff the given timeval is positive */ +#define TV_POS(tv) \ + ((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0)) + +/* subtract timeval `sub' from `res' */ +#define TV_SUB(res, sub) \ + (res)->tv_sec -= (sub)->tv_sec; \ + (res)->tv_usec -= (sub)->tv_usec; \ + if ((res)->tv_usec < 0) { \ + (res)->tv_usec += 1000000; \ + (res)->tv_sec--; \ + } + +/* + * Do a `read wait': select for reading from stdin, with timeout *tvp. + * On return, modify *tvp to reflect the amount of time spent waiting. + * It will be positive only if input appeared before the time ran out; + * otherwise it will be zero or perhaps negative. + * + * If tvp is nil, wait forever, but return if select is interrupted. + * + * Return 0 => no input, 1 => can read() from stdin + */ +int +rwait(tvp) + register struct timeval *tvp; +{ + int i; + struct timeval starttv, endtv, *s; + extern int errno; +#define NILTZ ((struct timezone *)0) + + /* + * Someday, select() will do this for us. + * Just in case that day is now, and no one has + * changed this, we use a temporary. + */ + if (tvp) { + (void) gettimeofday(&starttv, NILTZ); + endtv = *tvp; + s = &endtv; + } else + s = 0; +again: + i = 1; + switch (select(1, (fd_set *)&i, (fd_set *)0, (fd_set *)0, s)) { + + case -1: + if (tvp == 0) + return (-1); + if (errno == EINTR) + goto again; + stop("select failed, help"); + /* NOTREACHED */ + + case 0: /* timed out */ + tvp->tv_sec = 0; + tvp->tv_usec = 0; + return (0); + } + if (tvp) { + /* since there is input, we may not have timed out */ + (void) gettimeofday(&endtv, NILTZ); + TV_SUB(&endtv, &starttv); + TV_SUB(tvp, &endtv); /* adjust *tvp by elapsed time */ + } + return (1); +} + +/* + * `sleep' for the current turn time (using select). + * Eat any input that might be available. + */ +void +tsleep() +{ + struct timeval tv; + char c; + + tv.tv_sec = 0; + tv.tv_usec = fallrate; + while (TV_POS(&tv)) + if (rwait(&tv) && read(0, &c, 1) != 1) + break; +} + +/* + * Eat up any input (used at end of game). + */ +void +eat_input() +{ + struct timeval tv; + char c; + + do { + tv.tv_sec = tv.tv_usec = 0; + } while (rwait(&tv) && read(0, &c, 1) == 1); +} + +/* + * getchar with timeout. + */ +int +tgetchar() +{ + static struct timeval timeleft; + char c; + + /* + * Reset timeleft to fallrate whenever it is not positive. + * In any case, wait to see if there is any input. If so, + * take it, and update timeleft so that the next call to + * tgetchar() will not wait as long. If there is no input, + * make timeleft zero or negative, and return -1. + * + * Most of the hard work is done by rwait(). + */ + if (!TV_POS(&timeleft)) { + faster(); /* go faster */ + timeleft.tv_sec = 0; + timeleft.tv_usec = fallrate; + } + if (!rwait(&timeleft)) + return (-1); + if (read(0, &c, 1) != 1) + stop("end of file, help"); + return ((int)(unsigned char)c); +} diff --git a/games/tetris/input.h b/games/tetris/input.h new file mode 100644 index 0000000000000..733182d73357e --- /dev/null +++ b/games/tetris/input.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek and Darren F. Provine. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)input.h 8.1 (Berkeley) 5/31/93 + */ + +void eat_input __P((void)); +int rwait __P((struct timeval *)); +int tgetchar __P((void)); +void tsleep __P((void)); diff --git a/games/tetris/pathnames.h b/games/tetris/pathnames.h new file mode 100644 index 0000000000000..ba08dd116125e --- /dev/null +++ b/games/tetris/pathnames.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek and Darren F. Provine. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)pathnames.h 8.1 (Berkeley) 5/31/93 + */ + +#define _PATH_SCOREFILE "/var/games/tetris.scores" diff --git a/games/tetris/scores.c b/games/tetris/scores.c new file mode 100644 index 0000000000000..e7e6bb590ad88 --- /dev/null +++ b/games/tetris/scores.c @@ -0,0 +1,472 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek and Darren F. Provine. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)scores.c 8.1 (Berkeley) 5/31/93 + */ + +/* + * Score code for Tetris, by Darren Provine (kilroy@gboro.glassboro.edu) + * modified 22 January 1992, to limit the number of entries any one + * person has. + * + * Major whacks since then. + */ +#include <errno.h> +#include <fcntl.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +/* + * XXX - need a <termcap.h> + */ +int tputs __P((const char *, int, int (*)(int))); + +#include "pathnames.h" +#include "screen.h" +#include "scores.h" +#include "tetris.h" + +/* + * Within this code, we can hang onto one extra "high score", leaving + * room for our current score (whether or not it is high). + * + * We also sometimes keep tabs on the "highest" score on each level. + * As long as the scores are kept sorted, this is simply the first one at + * that level. + */ +#define NUMSPOTS (MAXHISCORES + 1) +#define NLEVELS (MAXLEVEL + 1) + +static time_t now; +static int nscores; +static int gotscores; +static struct highscore scores[NUMSPOTS]; + +static int checkscores __P((struct highscore *, int)); +static int cmpscores __P((const void *, const void *)); +static void getscores __P((FILE **)); +static void printem __P((int, int, struct highscore *, int, const char *)); +static char *thisuser __P((void)); + +/* + * Read the score file. Can be called from savescore (before showscores) + * or showscores (if savescore will not be called). If the given pointer + * is not NULL, sets *fpp to an open file pointer that corresponds to a + * read/write score file that is locked with LOCK_EX. Otherwise, the + * file is locked with LOCK_SH for the read and closed before return. + * + * Note, we assume closing the stdio file releases the lock. + */ +static void +getscores(fpp) + FILE **fpp; +{ + int sd, mint, lck; + char *mstr, *human; + FILE *sf; + + if (fpp != NULL) { + mint = O_RDWR | O_CREAT; + mstr = "r+"; + human = "read/write"; + lck = LOCK_EX; + } else { + mint = O_RDONLY; + mstr = "r"; + human = "reading"; + lck = LOCK_SH; + } + sd = open(_PATH_SCOREFILE, mint, 0666); + if (sd < 0) { + if (fpp == NULL) { + nscores = 0; + return; + } + (void)fprintf(stderr, "tetris: cannot open %s for %s: %s\n", + _PATH_SCOREFILE, human, strerror(errno)); + exit(1); + } + if ((sf = fdopen(sd, mstr)) == NULL) { + (void)fprintf(stderr, "tetris: cannot fdopen %s for %s: %s\n", + _PATH_SCOREFILE, human, strerror(errno)); + exit(1); + } + + /* + * Grab a lock. + */ + if (flock(sd, lck)) + (void)fprintf(stderr, + "tetris: warning: score file %s cannot be locked: %s\n", + _PATH_SCOREFILE, strerror(errno)); + + nscores = fread(scores, sizeof(scores[0]), MAXHISCORES, sf); + if (ferror(sf)) { + (void)fprintf(stderr, "tetris: error reading %s: %s\n", + _PATH_SCOREFILE, strerror(errno)); + exit(1); + } + + if (fpp) + *fpp = sf; + else + (void)fclose(sf); +} + +void +savescore(level) + int level; +{ + register struct highscore *sp; + register int i; + int change; + FILE *sf; + const char *me; + + getscores(&sf); + gotscores = 1; + (void)time(&now); + + /* + * Allow at most one score per person per level -- see if we + * can replace an existing score, or (easiest) do nothing. + * Otherwise add new score at end (there is always room). + */ + change = 0; + me = thisuser(); + for (i = 0, sp = &scores[0]; i < nscores; i++, sp++) { + if (sp->hs_level != level || strcmp(sp->hs_name, me) != 0) + continue; + if (score > sp->hs_score) { + (void)printf("%s bettered %s %d score of %d!\n", + "\nYou", "your old level", level, + sp->hs_score * sp->hs_level); + sp->hs_score = score; /* new score */ + sp->hs_time = now; /* and time */ + change = 1; + } else if (score == sp->hs_score) { + (void)printf("%s tied %s %d high score.\n", + "\nYou", "your old level", level); + sp->hs_time = now; /* renew it */ + change = 1; /* gotta rewrite, sigh */ + } /* else new score < old score: do nothing */ + break; + } + if (i >= nscores) { + strcpy(sp->hs_name, me); + sp->hs_level = level; + sp->hs_score = score; + sp->hs_time = now; + nscores++; + change = 1; + } + + if (change) { + /* + * Sort & clean the scores, then rewrite. + */ + nscores = checkscores(scores, nscores); + rewind(sf); + if (fwrite(scores, sizeof(*sp), nscores, sf) != nscores || + fflush(sf) == EOF) + (void)fprintf(stderr, + "tetris: error writing %s: %s -- %s\n", + _PATH_SCOREFILE, strerror(errno), + "high scores may be damaged"); + } + (void)fclose(sf); /* releases lock */ +} + +/* + * Get login name, or if that fails, get something suitable. + * The result is always trimmed to fit in a score. + */ +static char * +thisuser() +{ + register const char *p; + register struct passwd *pw; + register size_t l; + static char u[sizeof(scores[0].hs_name)]; + + if (u[0]) + return (u); + p = getlogin(); + if (p == NULL || *p == '\0') { + pw = getpwuid(getuid()); + if (pw != NULL) + p = pw->pw_name; + else + p = " ???"; + } + l = strlen(p); + if (l >= sizeof(u)) + l = sizeof(u) - 1; + bcopy(p, u, l); + u[l] = '\0'; + return (u); +} + +/* + * Score comparison function for qsort. + * + * If two scores are equal, the person who had the score first is + * listed first in the highscore file. + */ +static int +cmpscores(x, y) + const void *x, *y; +{ + register const struct highscore *a, *b; + register long l; + + a = x; + b = y; + l = (long)b->hs_level * b->hs_score - (long)a->hs_level * a->hs_score; + if (l < 0) + return (-1); + if (l > 0) + return (1); + if (a->hs_time < b->hs_time) + return (-1); + if (a->hs_time > b->hs_time) + return (1); + return (0); +} + +/* + * If we've added a score to the file, we need to check the file and ensure + * that this player has only a few entries. The number of entries is + * controlled by MAXSCORES, and is to ensure that the highscore file is not + * monopolised by just a few people. People who no longer have accounts are + * only allowed the highest score. Scores older than EXPIRATION seconds are + * removed, unless they are someone's personal best. + * Caveat: the highest score on each level is always kept. + */ +static int +checkscores(hs, num) + register struct highscore *hs; + int num; +{ + register struct highscore *sp; + register int i, j, k, numnames; + int levelfound[NLEVELS]; + struct peruser { + char *name; + int times; + } count[NUMSPOTS]; + register struct peruser *pu; + + /* + * Sort so that highest totals come first. + * + * levelfound[i] becomes set when the first high score for that + * level is encountered. By definition this is the highest score. + */ + qsort((void *)hs, nscores, sizeof(*hs), cmpscores); + for (i = MINLEVEL; i < NLEVELS; i++) + levelfound[i] = 0; + numnames = 0; + for (i = 0, sp = hs; i < num;) { + /* + * This is O(n^2), but do you think we care? + */ + for (j = 0, pu = count; j < numnames; j++, pu++) + if (strcmp(sp->hs_name, pu->name) == 0) + break; + if (j == numnames) { + /* + * Add new user, set per-user count to 1. + */ + pu->name = sp->hs_name; + pu->times = 1; + numnames++; + } else { + /* + * Two ways to keep this score: + * - Not too many (per user), still has acct, & + * score not dated; or + * - High score on this level. + */ + if ((pu->times < MAXSCORES && + getpwnam(sp->hs_name) != NULL && + sp->hs_time + EXPIRATION >= now) || + levelfound[sp->hs_level] == 0) + pu->times++; + else { + /* + * Delete this score, do not count it, + * do not pass go, do not collect $200. + */ + num--; + for (k = i; k < num; k++) + hs[k] = hs[k + 1]; + continue; + } + } + levelfound[sp->hs_level] = 1; + i++, sp++; + } + return (num > MAXHISCORES ? MAXHISCORES : num); +} + +/* + * Show current scores. This must be called after savescore, if + * savescore is called at all, for two reasons: + * - Showscores munches the time field. + * - Even if that were not the case, a new score must be recorded + * before it can be shown anyway. + */ +void +showscores(level) + int level; +{ + register struct highscore *sp; + register int i, n, c; + const char *me; + int levelfound[NLEVELS]; + + if (!gotscores) + getscores((FILE **)NULL); + (void)printf("\n\t\t\t Tetris High Scores\n"); + + /* + * If level == 0, the person has not played a game but just asked for + * the high scores; we do not need to check for printing in highlight + * mode. If SOstr is null, we can't do highlighting anyway. + */ + me = level && SOstr ? thisuser() : NULL; + + /* + * Set times to 0 except for high score on each level. + */ + for (i = MINLEVEL; i < NLEVELS; i++) + levelfound[i] = 0; + for (i = 0, sp = scores; i < nscores; i++, sp++) { + if (levelfound[sp->hs_level]) + sp->hs_time = 0; + else { + sp->hs_time = 1; + levelfound[sp->hs_level] = 1; + } + } + + /* + * Page each screenful of scores. + */ + for (i = 0, sp = scores; i < nscores; sp += n) { + n = 40; + if (i + n > nscores) + n = nscores - i; + printem(level, i + 1, sp, n, me); + if ((i += n) < nscores) { + (void)printf("\nHit RETURN to continue."); + (void)fflush(stdout); + while ((c = getchar()) != '\n') + if (c == EOF) + break; + (void)printf("\n"); + } + } +} + +static void +printem(level, offset, hs, n, me) + int level, offset; + register struct highscore *hs; + register int n; + const char *me; +{ + register struct highscore *sp; + int nrows, row, col, item, i, highlight; + char buf[100]; +#define TITLE "Rank Score Name (points/level)" + + /* + * This makes a nice two-column sort with headers, but it's a bit + * convoluted... + */ + printf("%s %s\n", TITLE, n > 1 ? TITLE : ""); + + highlight = 0; + nrows = (n + 1) / 2; + + for (row = 0; row < nrows; row++) { + for (col = 0; col < 2; col++) { + item = col * nrows + row; + if (item >= n) { + /* + * Can only occur on trailing columns. + */ + (void)putchar('\n'); + continue; + } + (void)printf(item + offset < 10 ? " " : " "); + sp = &hs[item]; + (void)sprintf(buf, + "%d%c %6d %-11s (%d on %d)", + item + offset, sp->hs_time ? '*' : ' ', + sp->hs_score * sp->hs_level, + sp->hs_name, sp->hs_score, sp->hs_level); + /* + * Highlight if appropriate. This works because + * we only get one score per level. + */ + if (me != NULL && + sp->hs_level == level && + sp->hs_score == score && + strcmp(sp->hs_name, me) == 0) { + putpad(SOstr); + highlight = 1; + } + (void)printf("%s", buf); + if (highlight) { + putpad(SEstr); + highlight = 0; + } + + /* fill in spaces so column 1 lines up */ + if (col == 0) + for (i = 40 - strlen(buf); --i >= 0;) + (void)putchar(' '); + else /* col == 1 */ + (void)putchar('\n'); + } + } +} diff --git a/games/tetris/scores.h b/games/tetris/scores.h new file mode 100644 index 0000000000000..7a4865adb4ac3 --- /dev/null +++ b/games/tetris/scores.h @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek and Darren F. Provine. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)scores.h 8.1 (Berkeley) 5/31/93 + */ + +/* + * Tetris scores. + */ +struct highscore { + char hs_name[20]; /* login name */ + int hs_score; /* raw score */ + int hs_level; /* play level */ + time_t hs_time; /* time at game end */ +}; + +#define MAXHISCORES 80 +#define MAXSCORES 9 /* maximum high score entries per person */ +#define EXPIRATION (5L * 365 * 24 * 60 * 60) + +void savescore __P((int)); +void showscores __P((int)); diff --git a/games/tetris/screen.c b/games/tetris/screen.c new file mode 100644 index 0000000000000..9662ed0155706 --- /dev/null +++ b/games/tetris/screen.c @@ -0,0 +1,454 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek and Darren F. Provine. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)screen.c 8.1 (Berkeley) 5/31/93 + */ + +/* + * Tetris screen control. + */ + +#include <sgtty.h> +#include <sys/ioctl.h> + +#include <setjmp.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifndef sigmask +#define sigmask(s) (1 << ((s) - 1)) +#endif + +#include "screen.h" +#include "tetris.h" + +/* + * XXX - need a <termcap.h> + */ +int tgetent __P((char *, const char *)); +int tgetflag __P((const char *)); +int tgetnum __P((const char *)); +int tputs __P((const char *, int, int (*)(int))); + +static cell curscreen[B_SIZE]; /* 1 => standout (or otherwise marked) */ +static int curscore; +static int isset; /* true => terminal is in game mode */ +static struct sgttyb oldtt; +static void (*tstp)(); + +char *tgetstr(), *tgoto(); + + +/* + * Capabilities from TERMCAP. + */ +char PC, *BC, *UP; /* tgoto requires globals: ugh! */ +short ospeed; + +static char + *bcstr, /* backspace char */ + *CEstr, /* clear to end of line */ + *CLstr, /* clear screen */ + *CMstr, /* cursor motion string */ +#ifdef unneeded + *CRstr, /* "\r" equivalent */ +#endif + *HOstr, /* cursor home */ + *LLstr, /* last line, first column */ + *pcstr, /* pad character */ + *TEstr, /* end cursor motion mode */ + *TIstr; /* begin cursor motion mode */ +char + *SEstr, /* end standout mode */ + *SOstr; /* begin standout mode */ +static int + COnum, /* co# value */ + LInum, /* li# value */ + MSflag; /* can move in standout mode */ + + +struct tcsinfo { /* termcap string info; some abbrevs above */ + char tcname[3]; + char **tcaddr; +} tcstrings[] = { + "bc", &bcstr, + "ce", &CEstr, + "cl", &CLstr, + "cm", &CMstr, +#ifdef unneeded + "cr", &CRstr, +#endif + "le", &BC, /* move cursor left one space */ + "pc", &pcstr, + "se", &SEstr, + "so", &SOstr, + "te", &TEstr, + "ti", &TIstr, + "up", &UP, /* cursor up */ + 0 +}; + +/* This is where we will actually stuff the information */ + +static char combuf[1024], tbuf[1024]; + + +/* + * Routine used by tputs(). + */ +int +put(c) + int c; +{ + + return (putchar(c)); +} + +/* + * putstr() is for unpadded strings (either as in termcap(5) or + * simply literal strings); putpad() is for padded strings with + * count=1. (See screen.h for putpad().) + */ +#define putstr(s) (void)fputs(s, stdout) +#define moveto(r, c) putpad(tgoto(CMstr, c, r)) + +/* + * Set up from termcap. + */ +void +scr_init() +{ + static int bsflag, xsflag, sgnum; +#ifdef unneeded + static int ncflag; +#endif + char *term, *fill; + static struct tcninfo { /* termcap numeric and flag info */ + char tcname[3]; + int *tcaddr; + } tcflags[] = { + "bs", &bsflag, + "ms", &MSflag, +#ifdef unneeded + "nc", &ncflag, +#endif + "xs", &xsflag, + 0 + }, tcnums[] = { + "co", &COnum, + "li", &LInum, + "sg", &sgnum, + 0 + }; + + if ((term = getenv("TERM")) == NULL) + stop("you must set the TERM environment variable"); + if (tgetent(tbuf, term) <= 0) + stop("cannot find your termcap"); + fill = combuf; + { + register struct tcsinfo *p; + + for (p = tcstrings; p->tcaddr; p++) + *p->tcaddr = tgetstr(p->tcname, &fill); + } + { + register struct tcninfo *p; + + for (p = tcflags; p->tcaddr; p++) + *p->tcaddr = tgetflag(p->tcname); + for (p = tcnums; p->tcaddr; p++) + *p->tcaddr = tgetnum(p->tcname); + } + if (bsflag) + BC = "\b"; + else if (BC == NULL && bcstr != NULL) + BC = bcstr; + if (CLstr == NULL) + stop("cannot clear screen"); + if (CMstr == NULL || UP == NULL || BC == NULL) + stop("cannot do random cursor positioning via tgoto()"); + PC = pcstr ? *pcstr : 0; + if (sgnum >= 0 || xsflag) + SOstr = SEstr = NULL; +#ifdef unneeded + if (ncflag) + CRstr = NULL; + else if (CRstr == NULL) + CRstr = "\r"; +#endif +} + +/* this foolery is needed to modify tty state `atomically' */ +static jmp_buf scr_onstop; + +#define sigunblock(mask) sigsetmask(sigblock(0) & ~(mask)) + +static void +stopset(sig) + int sig; +{ + (void) signal(sig, SIG_DFL); + (void) kill(getpid(), sig); + (void) sigunblock(sigmask(sig)); + longjmp(scr_onstop, 1); +} + +static void +scr_stop() +{ + scr_end(); + (void) kill(getpid(), SIGTSTP); + (void) sigunblock(sigmask(SIGTSTP)); + scr_set(); + scr_msg(key_msg, 1); +} + +/* + * Set up screen mode. + */ +void +scr_set() +{ + struct winsize ws; + struct sgttyb newtt; + volatile int omask; + void (*ttou)(); + + omask = sigblock(sigmask(SIGTSTP) | sigmask(SIGTTOU)); + if ((tstp = signal(SIGTSTP, stopset)) == SIG_IGN) + (void) signal(SIGTSTP, SIG_IGN); + if ((ttou = signal(SIGTSTP, stopset)) == SIG_IGN) + (void) signal(SIGTSTP, SIG_IGN); + /* + * At last, we are ready to modify the tty state. If + * we stop while at it, stopset() above will longjmp back + * to the setjmp here and we will start over. + */ + (void) setjmp(scr_onstop); + (void) sigsetmask(omask); + Rows = 0, Cols = 0; + if (ioctl(0, TIOCGWINSZ, &ws) == 0) { + Rows = ws.ws_row; + Cols = ws.ws_col; + } + if (Rows == 0) + Rows = LInum; + if (Cols == 0) + Cols = COnum; + if (Rows < MINROWS || Cols < MINCOLS) { + (void) fprintf(stderr, + "the screen is too small: must be at least %d x %d", + MINROWS, MINCOLS); + stop(""); /* stop() supplies \n */ + } + if (ioctl(0, TIOCGETP, &oldtt)) + stop("ioctl(TIOCGETP) fails"); + newtt = oldtt; + newtt.sg_flags = (newtt.sg_flags | CBREAK) & ~(CRMOD | ECHO); + if ((newtt.sg_flags & TBDELAY) == XTABS) + newtt.sg_flags &= ~TBDELAY; + if (ioctl(0, TIOCSETN, &newtt)) + stop("ioctl(TIOCSETN) fails"); + ospeed = newtt.sg_ospeed; + omask = sigblock(sigmask(SIGTSTP) | sigmask(SIGTTOU)); + + /* + * We made it. We are now in screen mode, modulo TIstr + * (which we will fix immediately). + */ + if (TIstr) + putstr(TIstr); /* termcap(5) says this is not padded */ + if (tstp != SIG_IGN) + (void) signal(SIGTSTP, scr_stop); + (void) signal(SIGTTOU, ttou); + + isset = 1; + (void) sigsetmask(omask); + scr_clear(); +} + +/* + * End screen mode. + */ +void +scr_end() +{ + int omask = sigblock(sigmask(SIGTSTP) | sigmask(SIGTTOU)); + + /* move cursor to last line */ + if (LLstr) + putstr(LLstr); /* termcap(5) says this is not padded */ + else + moveto(Rows - 1, 0); + /* exit screen mode */ + if (TEstr) + putstr(TEstr); /* termcap(5) says this is not padded */ + (void) fflush(stdout); + (void) ioctl(0, TIOCSETN, &oldtt); + isset = 0; + /* restore signals */ + (void) signal(SIGTSTP, tstp); + (void) sigsetmask(omask); +} + +void +stop(why) + char *why; +{ + + if (isset) + scr_end(); + (void) fprintf(stderr, "aborting: %s\n", why); + exit(1); +} + +/* + * Clear the screen, forgetting the current contents in the process. + */ +void +scr_clear() +{ + + putpad(CLstr); + curscore = -1; + bzero((char *)curscreen, sizeof(curscreen)); +} + +#if vax && !__GNUC__ +typedef int regcell; /* pcc is bad at `register char', etc */ +#else +typedef cell regcell; +#endif + +/* + * Update the screen. + */ +void +scr_update() +{ + register cell *bp, *sp; + register regcell so, cur_so = 0; + register int i, ccol, j; + int omask = sigblock(sigmask(SIGTSTP)); + + /* always leave cursor after last displayed point */ + curscreen[D_LAST * B_COLS - 1] = -1; + + if (score != curscore) { + if (HOstr) + putpad(HOstr); + else + moveto(0, 0); + (void) printf("%d", score); + curscore = score; + } + + bp = &board[D_FIRST * B_COLS]; + sp = &curscreen[D_FIRST * B_COLS]; + for (j = D_FIRST; j < D_LAST; j++) { + ccol = -1; + for (i = 0; i < B_COLS; bp++, sp++, i++) { + if (*sp == (so = *bp)) + continue; + *sp = so; + if (i != ccol) { + if (cur_so && MSflag) { + putpad(SEstr); + cur_so = 0; + } + moveto(RTOD(j), CTOD(i)); + } + if (SOstr) { + if (so != cur_so) { + putpad(so ? SOstr : SEstr); + cur_so = so; + } + putstr(" "); + } else + putstr(so ? "XX" : " "); + ccol = i + 1; + /* + * Look ahead a bit, to avoid extra motion if + * we will be redrawing the cell after the next. + * Motion probably takes four or more characters, + * so we save even if we rewrite two cells + * `unnecessarily'. Skip it all, though, if + * the next cell is a different color. + */ +#define STOP (B_COLS - 3) + if (i > STOP || sp[1] != bp[1] || so != bp[1]) + continue; + if (sp[2] != bp[2]) + sp[1] = -1; + else if (i < STOP && so == bp[2] && sp[3] != bp[3]) { + sp[2] = -1; + sp[1] = -1; + } + } + } + if (cur_so) + putpad(SEstr); + (void) fflush(stdout); + (void) sigsetmask(omask); +} + +/* + * Write a message (set!=0), or clear the same message (set==0). + * (We need its length in case we have to overwrite with blanks.) + */ +void +scr_msg(s, set) + register char *s; + int set; +{ + + if (set || CEstr == NULL) { + register int l = strlen(s); + + moveto(Rows - 2, ((Cols - l) >> 1) - 1); + if (set) + putstr(s); + else + while (--l >= 0) + (void) putchar(' '); + } else { + moveto(Rows - 2, 0); + putpad(CEstr); + } +} diff --git a/games/tetris/screen.h b/games/tetris/screen.h new file mode 100644 index 0000000000000..fd6793d17a147 --- /dev/null +++ b/games/tetris/screen.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek and Darren F. Provine. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)screen.h 8.1 (Berkeley) 5/31/93 + */ + +/* + * Capabilities from TERMCAP (used in the score code). + */ +char *SEstr; /* end standout mode */ +char *SOstr; /* begin standout mode */ + +/* + * putpad() is for padded strings with count=1. + */ +#define putpad(s) tputs(s, 1, put) + +int put __P((int)); /* just calls putchar; for tputs */ +void scr_clear __P((void)); +void scr_end __P((void)); +void scr_init __P((void)); +void scr_msg __P((char *, int)); +void scr_set __P((void)); +void scr_update __P((void)); diff --git a/games/tetris/shapes.c b/games/tetris/shapes.c new file mode 100644 index 0000000000000..39ba3788871ff --- /dev/null +++ b/games/tetris/shapes.c @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek and Darren F. Provine. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)shapes.c 8.1 (Berkeley) 5/31/93 + */ + +/* + * Tetris shapes and related routines. + * + * Note that the first 7 are `well known'. + */ + +#include <sys/cdefs.h> +#include "tetris.h" + +#define TL -B_COLS-1 /* top left */ +#define TC -B_COLS /* top center */ +#define TR -B_COLS+1 /* top right */ +#define ML -1 /* middle left */ +#define MR 1 /* middle right */ +#define BL B_COLS-1 /* bottom left */ +#define BC B_COLS /* bottom center */ +#define BR B_COLS+1 /* bottom right */ + +struct shape shapes[] = { + /* 0*/ 7, TL, TC, MR, + /* 1*/ 8, TC, TR, ML, + /* 2*/ 9, ML, MR, BC, + /* 3*/ 3, TL, TC, ML, + /* 4*/ 12, ML, BL, MR, + /* 5*/ 15, ML, BR, MR, + /* 6*/ 18, ML, MR, /* sticks out */ 2, + /* 7*/ 0, TC, ML, BL, + /* 8*/ 1, TC, MR, BR, + /* 9*/ 10, TC, MR, BC, + /*10*/ 11, TC, ML, MR, + /*11*/ 2, TC, ML, BC, + /*12*/ 13, TC, BC, BR, + /*13*/ 14, TR, ML, MR, + /*14*/ 4, TL, TC, BC, + /*15*/ 16, TR, TC, BC, + /*16*/ 17, TL, MR, ML, + /*17*/ 5, TC, BC, BL, + /*18*/ 6, TC, BC, /* sticks out */ 2*B_COLS, +}; + +/* + * Return true iff the given shape fits in the given position, + * taking the current board into account. + */ +int +fits_in(shape, pos) + struct shape *shape; + register int pos; +{ + register int *o = shape->off; + + if (board[pos] || board[pos + *o++] || board[pos + *o++] || + board[pos + *o]) + return 0; + return 1; +} + +/* + * Write the given shape into the current board, turning it on + * if `onoff' is 1, and off if `onoff' is 0. + */ +void +place(shape, pos, onoff) + struct shape *shape; + register int pos, onoff; +{ + register int *o = shape->off; + + board[pos] = onoff; + board[pos + *o++] = onoff; + board[pos + *o++] = onoff; + board[pos + *o] = onoff; +} diff --git a/games/tetris/tetris.6 b/games/tetris/tetris.6 new file mode 100644 index 0000000000000..9513ca057d9e5 --- /dev/null +++ b/games/tetris/tetris.6 @@ -0,0 +1,154 @@ +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Nancy L. Tinkham and Darren F. Provine. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)tetris.6 8.1 (Berkeley) 5/31/93 +.\" +.Dd "May 31, 1993" +.Dt TETRIS 6 +.Os +.Sh NAME +.Nm tetris +.Nd the game of tetris +.Sh SYNOPSIS +.Nm +.Op Fl s +.Op Fl k Ar keys +.Op Fl l Ar level +.Sh DESCRIPTION +The +.Nm +command runs display-based game which must be played on a CRT terminal. +The object is to fit the shapes together forming complete rows, +which then vanish. +When the shapes fill up to the top, the game ends. +You can optionally select a level of play, or custom-select control keys. +.Pp +The default level of play is 2. +.Pp +The default control keys are as follows: +.Pp +.Bl -tag -width "<space>" -compact -offset indent +.It j +move left +.It k +rotate 1/4 turn counterclockwise +.It l +move right +.It <space> +drop +.It p +pause +.It q +quit +.El +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl k +The default control keys can be changed using the +.Fl k option. +The +.Ar keys +argument must have the six keys in order, and, remember to quote any +space or tab characters from the shell. +For example: +.sp +.Dl "tetris -l 2 -k 'jkl pq'" +.sp +will play the default games, i.e. level 2 and with the default +control keys. +The current key settings are displayed at the bottom of the screen +during play. +.It Fl l +Select a level of play. +.It Fl s +Display the top scores. +.El +.Pp +.Sh PLAY +At the start of the game, a shape will appear at the top of the screen, +falling one square at a time. +The speed at which it falls is determined directly by the level: +if you select level 2, the blocks will fall twice per second; +at level 9, they fall 9 times per second. +(As the game goes on, things speed up, +no matter what your initial selection.) +When this shape +.Dq "touches down" +on the bottom of the field, another will appear at the top. +.Pp +You can move shapes to the left or right, rotate them counterclockwise, +or drop them to the bottom by pressing the appropriate keys. +As you fit them together, completed horizontal rows vanish, +and any blocks above fall down to fill in. +When the blocks stack up to the top of the screen, the game is over. +.Sh SCORING +You get one point for every block you fit into the stack, +and one point for every space a block falls when you hit the drop key. +(Dropping the blocks is therefore a good way to increase your score.) +Your total score is the product of the level of play +and your accumulated +.ie t points\(em200 +.el points -- 200 +points on level 3 gives you a score of 600. +Each player gets at most one entry on any level, +for a total of nine scores in the high scores file. +Players who no longer have accounts are limited to one score. +Also, scores over 5 years old are expired. +The exception to these conditions is that the highest score on a given +level is +.Em always +kept, +so that following generations can pay homage to those who have +wasted serious amounts of time. +.Pp +The score list is produced at the end of the game. +The printout includes each player's overall ranking, +name, score, and how many points were scored on what level. +Scores which are the highest on a given level +are marked with asterisks +.Dq * . +.Sh FILES +.Bl -tag -width /var/games/tetris.scoresxx +.It /var/games/tetris.scores +high score file +.El +.Sh BUGS +The higher levels are unplayable without a fast terminal connection. +.Sh AUTHORS +Adapted from a 1989 International Obfuscated C Code Contest winner by +Chris Torek and Darren F. Provine. +.Pp +Manual adapted from the original entry written by Nancy L. Tinkham and +Darren F. Provine. diff --git a/games/tetris/tetris.c b/games/tetris/tetris.c new file mode 100644 index 0000000000000..63265bc6b7541 --- /dev/null +++ b/games/tetris/tetris.c @@ -0,0 +1,312 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek and Darren F. Provine. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tetris.c 8.1 (Berkeley) 5/31/93 + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1992, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +/* + * Tetris (or however it is spelled). + */ + +#include <sys/time.h> + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "input.h" +#include "scores.h" +#include "screen.h" +#include "tetris.h" + +void onintr __P((int)); +void usage __P((void)); + +/* + * Set up the initial board. The bottom display row is completely set, + * along with another (hidden) row underneath that. Also, the left and + * right edges are set. + */ +static void +setup_board() +{ + register int i; + register cell *p; + + p = board; + for (i = B_SIZE; i; i--) +#ifndef mips + *p++ = i <= (2 * B_COLS) || (i % B_COLS) < 2; +#else /* work around compiler bug */ + *p++ = i <= (2 * B_COLS) || (i % B_COLS) < 2 ? 1 : 0; +#endif +} + +/* + * Elide any full active rows. + */ +static void +elide() +{ + register int i, j, base; + register cell *p; + + for (i = A_FIRST; i < A_LAST; i++) { + base = i * B_COLS + 1; + p = &board[base]; + for (j = B_COLS - 2; *p++ != 0;) { + if (--j <= 0) { + /* this row is to be elided */ + bzero(&board[base], B_COLS - 2); + scr_update(); + tsleep(); + while (--base != 0) + board[base + B_COLS] = board[base]; + scr_update(); + tsleep(); + break; + } + } + } +} + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register int pos, c; + register struct shape *curshape; + register char *keys; + register int level = 2; + char key_write[6][10]; + int ch, i, j; + + keys = "jkl pq"; + + while ((ch = getopt(argc, argv, "k:l:s")) != EOF) + switch(ch) { + case 'k': + if (strlen(keys = optarg) != 6) + usage(); + break; + case 'l': + level = atoi(optarg); + if (level < MINLEVEL || level > MAXLEVEL) { + (void)fprintf(stderr, + "tetris: level must be from %d to %d", + MINLEVEL, MAXLEVEL); + exit(1); + } + break; + case 's': + showscores(0); + exit(0); + case '?': + default: + usage(); + } + + argc -= optind; + argv += optind; + + if (argc) + usage(); + + fallrate = 1000000 / level; + + for (i = 0; i <= 5; i++) { + for (j = i+1; j <= 5; j++) { + if (keys[i] == keys[j]) { + (void)fprintf(stderr, + "%s: Duplicate command keys specified.\n", + argv[0]); + exit (1); + } + } + if (keys[i] == ' ') + strcpy(key_write[i], "<space>"); + else { + key_write[i][0] = keys[i]; + key_write[i][1] = '\0'; + } + } + + sprintf(key_msg, +"%s - left %s - rotate %s - right %s - drop %s - pause %s - quit", + key_write[0], key_write[1], key_write[2], key_write[3], + key_write[4], key_write[5]); + + (void)signal(SIGINT, onintr); + scr_init(); + setup_board(); + + srandom(getpid()); + scr_set(); + + pos = A_FIRST*B_COLS + (B_COLS/2)-1; + curshape = randshape(); + + scr_msg(key_msg, 1); + + for (;;) { + place(curshape, pos, 1); + scr_update(); + place(curshape, pos, 0); + c = tgetchar(); + if (c < 0) { + /* + * Timeout. Move down if possible. + */ + if (fits_in(curshape, pos + B_COLS)) { + pos += B_COLS; + continue; + } + + /* + * Put up the current shape `permanently', + * bump score, and elide any full rows. + */ + place(curshape, pos, 1); + score++; + elide(); + + /* + * Choose a new shape. If it does not fit, + * the game is over. + */ + curshape = randshape(); + pos = A_FIRST*B_COLS + (B_COLS/2)-1; + if (!fits_in(curshape, pos)) + break; + continue; + } + + /* + * Handle command keys. + */ + if (c == keys[5]) { + /* quit */ + break; + } + if (c == keys[4]) { + static char msg[] = + "paused - press RETURN to continue"; + + place(curshape, pos, 1); + do { + scr_update(); + scr_msg(key_msg, 0); + scr_msg(msg, 1); + (void) fflush(stdout); + } while (rwait((struct timeval *)NULL) == -1); + scr_msg(msg, 0); + scr_msg(key_msg, 1); + place(curshape, pos, 0); + continue; + } + if (c == keys[0]) { + /* move left */ + if (fits_in(curshape, pos - 1)) + pos--; + continue; + } + if (c == keys[1]) { + /* turn */ + struct shape *new = &shapes[curshape->rot]; + + if (fits_in(new, pos)) + curshape = new; + continue; + } + if (c == keys[2]) { + /* move right */ + if (fits_in(curshape, pos + 1)) + pos++; + continue; + } + if (c == keys[3]) { + /* move to bottom */ + while (fits_in(curshape, pos + B_COLS)) { + pos += B_COLS; + score++; + } + continue; + } + if (c == '\f') + scr_clear(); + } + + scr_clear(); + scr_end(); + + (void)printf("Your score: %d point%s x level %d = %d\n", + score, score == 1 ? "" : "s", level, score * level); + savescore(level); + + printf("\nHit RETURN to see high scores, ^C to skip.\n"); + + while ((i = getchar()) != '\n') + if (i == EOF) + break; + + showscores(level); + + exit(0); +} + +void +onintr(signo) + int signo; +{ + scr_clear(); + scr_end(); + exit(0); +} + +void +usage() +{ + (void)fprintf(stderr, "usage: tetris [-s] [-l level] [-keys]\n"); + exit(1); +} diff --git a/games/tetris/tetris.h b/games/tetris/tetris.h new file mode 100644 index 0000000000000..b95627bb9b678 --- /dev/null +++ b/games/tetris/tetris.h @@ -0,0 +1,169 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek and Darren F. Provine. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tetris.h 8.1 (Berkeley) 5/31/93 + */ + +/* + * Definitions for Tetris. + */ + +/* + * The display (`board') is composed of 23 rows of 12 columns of characters + * (numbered 0..22 and 0..11), stored in a single array for convenience. + * Columns 1 to 10 of rows 1 to 20 are the actual playing area, where + * shapes appear. Columns 0 and 11 are always occupied, as are all + * columns of rows 21 and 22. Rows 0 and 22 exist as boundary areas + * so that regions `outside' the visible area can be examined without + * worrying about addressing problems. + */ + + /* the board */ +#define B_COLS 12 +#define B_ROWS 23 +#define B_SIZE (B_ROWS * B_COLS) + +typedef unsigned char cell; +cell board[B_SIZE]; /* 1 => occupied, 0 => empty */ + + /* the displayed area (rows) */ +#define D_FIRST 1 +#define D_LAST 22 + + /* the active area (rows) */ +#define A_FIRST 1 +#define A_LAST 21 + +/* + * Minimum display size. + */ +#define MINROWS 23 +#define MINCOLS 40 + +int Rows, Cols; /* current screen size */ + +/* + * Translations from board coordinates to display coordinates. + * As with board coordinates, display coordiates are zero origin. + */ +#define RTOD(x) ((x) - 1) +#define CTOD(x) ((x) * 2 + (((Cols - 2 * B_COLS) >> 1) - 1)) + +/* + * A `shape' is the fundamental thing that makes up the game. There + * are 7 basic shapes, each consisting of four `blots': + * + * X.X X.X X.X + * X.X X.X X.X.X X.X X.X.X X.X.X X.X.X.X + * X X X + * + * 0 1 2 3 4 5 6 + * + * Except for 3 and 6, the center of each shape is one of the blots. + * This blot is designated (0,0). The other three blots can then be + * described as offsets from the center. Shape 3 is the same under + * rotation, so its center is effectively irrelevant; it has been chosen + * so that it `sticks out' upward and leftward. Except for shape 6, + * all the blots are contained in a box going from (-1,-1) to (+1,+1); + * shape 6's center `wobbles' as it rotates, so that while it `sticks out' + * rightward, its rotation---a vertical line---`sticks out' downward. + * The containment box has to include the offset (2,0), making the overall + * containment box range from offset (-1,-1) to (+2,+1). (This is why + * there is only one row above, but two rows below, the display area.) + * + * The game works by choosing one of these shapes at random and putting + * its center at the middle of the first display row (row 1, column 5). + * The shape is moved steadily downward until it collides with something: + * either another shape, or the bottom of the board. When the shape can + * no longer be moved downwards, it is merged into the current board. + * At this time, any completely filled rows are elided, and blots above + * these rows move down to make more room. A new random shape is again + * introduced at the top of the board, and the whole process repeats. + * The game ends when the new shape will not fit at (1,5). + * + * While the shapes are falling, the user can rotate them counterclockwise + * 90 degrees (in addition to moving them left or right), provided that the + * rotation puts the blots in empty spaces. The table of shapes is set up + * so that each shape contains the index of the new shape obtained by + * rotating the current shape. Due to symmetry, each shape has exactly + * 1, 2, or 4 rotations total; the first 7 entries in the table represent + * the primary shapes, and the remaining 12 represent their various + * rotated forms. + */ +struct shape { + int rot; /* index of rotated version of this shape */ + int off[3]; /* offsets to other blots if center is at (0,0) */ +}; + +extern struct shape shapes[]; +#define randshape() (&shapes[random() % 7]) + +/* + * Shapes fall at a rate faster than once per second. + * + * The initial rate is determined by dividing 1 million microseconds + * by the game `level'. (This is at most 1 million, or one second.) + * Each time the fall-rate is used, it is decreased a little bit, + * depending on its current value, via the `faster' macro below. + * The value eventually reaches a limit, and things stop going faster, + * but by then the game is utterly impossible. + */ +long fallrate; /* less than 1 million; smaller => faster */ +#define faster() (fallrate -= fallrate / 3000) + +/* + * Game level must be between 1 and 9. This controls the initial fall rate + * and affects scoring. + */ +#define MINLEVEL 1 +#define MAXLEVEL 9 + +/* + * Scoring is as follows: + * + * When the shape comes to rest, and is integrated into the board, + * we score one point. If the shape is high up (at a low-numbered row), + * and the user hits the space bar, the shape plummets all the way down, + * and we score a point for each row it falls (plus one more as soon as + * we find that it is at rest and integrate it---until then, it can + * still be moved or rotated). + */ +int score; /* the obvious thing */ + +char key_msg[100]; + +int fits_in __P((struct shape *, int)); +void place __P((struct shape *, int, int)); +void stop __P((char *)); |