ascii tetris!
This commit is contained in:
parent
dd267b8c9d
commit
fece8b5011
|
@ -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.0
|
||||
DPADD= ${LIBTERM}
|
||||
LDADD= -ltermcap
|
||||
HIDEGAME=hidegame
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
|
@ -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"
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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));
|
|
@ -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;
|
||||
}
|
|
@ -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.
|
|
@ -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);
|
||||
}
|
|
@ -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 *));
|
Loading…
Reference in New Issue