/uspace/trunk/tetris/scores.c |
---|
0,0 → 1,443 |
/* $OpenBSD: scores.c,v 1.11 2006/04/20 03:25:36 ray Exp $ */ |
/* $NetBSD: scores.c,v 1.2 1995/04/22 07:42:38 cgd Exp $ */ |
/*- |
* 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. 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 <err.h> |
#include <fcntl.h> |
#include <pwd.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <time.h> |
#include <term.h> |
#include <unistd.h> |
#include <sys/param.h> |
#include <sys/stat.h> |
#include <sys/types.h> |
#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(struct highscore *, int); |
static int cmpscores(const void *, const void *); |
static void getscores(FILE **); |
static void printem(int, int, struct highscore *, int, const char *); |
static char *thisuser(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(FILE **fpp) |
{ |
int sd, mint, lck, mask, i; |
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; |
} |
setegid(egid); |
mask = umask(S_IWOTH); |
sd = open(_PATH_SCOREFILE, mint, 0666); |
(void)umask(mask); |
setegid(gid); |
if (sd < 0) { |
if (fpp == NULL) { |
nscores = 0; |
return; |
} |
err(1, "cannot open %s for %s", _PATH_SCOREFILE, human); |
} |
setegid(egid); |
if ((sf = fdopen(sd, mstr)) == NULL) |
err(1, "cannot fdopen %s for %s", _PATH_SCOREFILE, human); |
setegid(gid); |
/* |
* Grab a lock. |
*/ |
if (flock(sd, lck)) |
warn("warning: score file %s cannot be locked", |
_PATH_SCOREFILE); |
nscores = fread(scores, sizeof(scores[0]), MAXHISCORES, sf); |
if (ferror(sf)) |
err(1, "error reading %s", _PATH_SCOREFILE); |
for (i = 0; i < nscores; i++) |
if (scores[i].hs_level < MINLEVEL || |
scores[i].hs_level > MAXLEVEL) |
errx(1, "scorefile %s corrupt", _PATH_SCOREFILE); |
if (fpp) |
*fpp = sf; |
else |
(void)fclose(sf); |
} |
void |
savescore(int level) |
{ |
struct highscore *sp; |
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) { |
strlcpy(sp->hs_name, me, sizeof sp->hs_name); |
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) |
warnx("error writing %s: %s\n\t-- %s", |
_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(void) |
{ |
const char *p; |
struct passwd *pw; |
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 = " ???"; |
} |
strlcpy(u, p, sizeof(u)); |
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(const void *x, const void *y) |
{ |
const struct highscore *a, *b; |
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(struct highscore *hs, int num) |
{ |
struct highscore *sp; |
int i, j, k, numnames; |
int levelfound[NLEVELS]; |
struct peruser { |
char *name; |
int times; |
} count[NUMSPOTS]; |
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(int level) |
{ |
struct highscore *sp; |
int i, n, c; |
const char *me; |
int levelfound[NLEVELS]; |
if (!gotscores) |
getscores((FILE **)NULL); |
(void)printf("\n\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 = 20; |
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"); |
} |
} |
if (nscores == 0) |
printf("\t\t\t - none to date.\n"); |
} |
static void |
printem(int level, int offset, struct highscore *hs, int n, const char *me) |
{ |
struct highscore *sp; |
int row, highlight, i; |
char buf[100]; |
#define TITLE "Rank Score Name (points/level)" |
#define TITL2 "==========================================================" |
printf("%s\n%s\n", TITLE, TITL2); |
highlight = 0; |
for (row = 0; row < n; row++) { |
sp = &hs[row]; |
(void)snprintf(buf, sizeof(buf), |
"%3d%c %6d %-31s (%6d on %d)\n", |
row + offset, sp->hs_time ? '*' : ' ', |
sp->hs_score * sp->hs_level, |
sp->hs_name, sp->hs_score, sp->hs_level); |
/* Print leaders every three lines */ |
if ((row + 1) % 3 == 0) { |
for (i = 0; i < sizeof(buf); i++) |
if (buf[i] == ' ') |
buf[i] = '_'; |
} |
/* |
* 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; |
} |
} |
} |
/uspace/trunk/tetris/input.c |
---|
0,0 → 1,166 |
/* $OpenBSD: input.c,v 1.12 2005/04/13 02:33:08 deraadt Exp $ */ |
/* $NetBSD: input.c,v 1.3 1996/02/06 22:47:33 jtc Exp $ */ |
/*- |
* 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. 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 <string.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(struct timeval *tvp) |
{ |
struct timeval starttv, endtv, *s; |
fd_set fds; |
#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 = NULL; |
again: |
FD_ZERO(&fds); |
FD_SET(STDIN_FILENO, &fds); |
switch (select(STDIN_FILENO + 1, &fds, (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(void) |
{ |
struct timeval tv; |
char c; |
tv.tv_sec = 0; |
tv.tv_usec = fallrate; |
while (TV_POS(&tv)) |
if (rwait(&tv) && read(STDIN_FILENO, &c, 1) != 1) |
break; |
} |
/* |
* getchar with timeout. |
*/ |
int |
tgetchar(void) |
{ |
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(STDIN_FILENO, &c, 1) != 1) |
stop("end of file, help"); |
return ((int)(unsigned char)c); |
} |
/uspace/trunk/tetris/screen.c |
---|
0,0 → 1,493 |
/* $OpenBSD: screen.c,v 1.13 2006/04/20 03:25:36 ray Exp $ */ |
/* $NetBSD: screen.c,v 1.4 1995/04/29 01:11:36 mycroft Exp $ */ |
/*- |
* 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. 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 <sys/ioctl.h> |
#include <err.h> |
#include <setjmp.h> |
#include <signal.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <term.h> |
#include <termios.h> |
#include <unistd.h> |
#include "screen.h" |
#include "tetris.h" |
static cell curscreen[B_SIZE]; /* 1 => standout (or otherwise marked) */ |
static int curscore; |
static int isset; /* true => terminal is in game mode */ |
static struct termios oldtt; |
static void (*tstp)(int); |
static void scr_stop(int); |
static void stopset(int); |
/* |
* Capabilities from TERMCAP. |
*/ |
char PC, *BC, *UP; /* tgoto requires globals: ugh! */ |
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}, NULL} |
}; |
/* This is where we will actually stuff the information */ |
static char combuf[1024], tbuf[1024]; |
/* |
* Routine used by tputs(). |
*/ |
int |
put(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(void) |
{ |
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}, NULL} |
}, tcnums[] = { |
{"co", &COnum}, |
{"li", &LInum}, |
{"sg", &sgnum}, |
{ {0}, NULL} |
}; |
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; |
{ |
struct tcsinfo *p; |
for (p = tcstrings; p->tcaddr; p++) |
*p->tcaddr = tgetstr(p->tcname, &fill); |
} |
if (classic) |
SOstr = SEstr = NULL; |
{ |
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; |
static void |
stopset(int sig) |
{ |
sigset_t sigset; |
(void) signal(sig, SIG_DFL); |
(void) kill(getpid(), sig); |
sigemptyset(&sigset); |
sigaddset(&sigset, sig); |
(void) sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *)0); |
longjmp(scr_onstop, 1); |
} |
static void |
scr_stop(int sig) |
{ |
sigset_t sigset; |
scr_end(); |
(void) kill(getpid(), sig); |
sigemptyset(&sigset); |
sigaddset(&sigset, sig); |
(void) sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *)0); |
scr_set(); |
scr_msg(key_msg, 1); |
} |
/* |
* Set up screen mode. |
*/ |
void |
scr_set(void) |
{ |
struct winsize ws; |
struct termios newtt; |
sigset_t sigset, osigset; |
void (*ttou)(int); |
sigemptyset(&sigset); |
sigaddset(&sigset, SIGTSTP); |
sigaddset(&sigset, SIGTTOU); |
(void) sigprocmask(SIG_BLOCK, &sigset, &osigset); |
if ((tstp = signal(SIGTSTP, stopset)) == SIG_IGN) |
(void) signal(SIGTSTP, SIG_IGN); |
if ((ttou = signal(SIGTTOU, stopset)) == SIG_IGN) |
(void) signal(SIGTTOU, 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) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); |
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) { |
char smallscr[55]; |
(void)snprintf(smallscr, sizeof(smallscr), |
"the screen is too small (must be at least %dx%d)", |
MINROWS, MINCOLS); |
stop(smallscr); |
} |
if (tcgetattr(0, &oldtt) < 0) |
stop("tcgetattr() fails"); |
newtt = oldtt; |
newtt.c_lflag &= ~(ICANON|ECHO); |
newtt.c_oflag &= ~OXTABS; |
if (tcsetattr(0, TCSADRAIN, &newtt) < 0) |
stop("tcsetattr() fails"); |
(void) sigprocmask(SIG_BLOCK, &sigset, &osigset); |
/* |
* 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); |
if (ttou != SIG_IGN) |
(void) signal(SIGTTOU, ttou); |
isset = 1; |
(void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); |
scr_clear(); |
} |
/* |
* End screen mode. |
*/ |
void |
scr_end(void) |
{ |
sigset_t sigset, osigset; |
sigemptyset(&sigset); |
sigaddset(&sigset, SIGTSTP); |
sigaddset(&sigset, SIGTTOU); |
(void) sigprocmask(SIG_BLOCK, &sigset, &osigset); |
/* 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) tcsetattr(0, TCSADRAIN, &oldtt); |
isset = 0; |
/* restore signals */ |
(void) signal(SIGTSTP, tstp); |
(void) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); |
} |
void |
stop(char *why) |
{ |
if (isset) |
scr_end(); |
errx(1, "aborting: %s", why); |
} |
/* |
* Clear the screen, forgetting the current contents in the process. |
*/ |
void |
scr_clear(void) |
{ |
putpad(CLstr); |
curscore = -1; |
memset((char *)curscreen, 0, 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(void) |
{ |
cell *bp, *sp; |
regcell so, cur_so = 0; |
int i, ccol, j; |
sigset_t sigset, osigset; |
static const struct shape *lastshape; |
sigemptyset(&sigset); |
sigaddset(&sigset, SIGTSTP); |
(void) sigprocmask(SIG_BLOCK, &sigset, &osigset); |
/* 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("Score: %d", score); |
curscore = score; |
} |
/* draw preview of next pattern */ |
if (showpreview && (nextshape != lastshape)) { |
int i; |
static int r=5, c=2; |
int tr, tc, t; |
lastshape = nextshape; |
/* clean */ |
putpad(SEstr); |
moveto(r-1, c-1); putstr(" "); |
moveto(r, c-1); putstr(" "); |
moveto(r+1, c-1); putstr(" "); |
moveto(r+2, c-1); putstr(" "); |
moveto(r-3, c-2); |
putstr("Next shape:"); |
/* draw */ |
if (SOstr) |
putpad(SOstr); |
moveto(r, 2 * c); |
putstr(SOstr ? " " : "[]"); |
for (i = 0; i < 3; i++) { |
t = c + r * B_COLS; |
t += nextshape->off[i]; |
tr = t / B_COLS; |
tc = t % B_COLS; |
moveto(tr, 2*tc); |
putstr(SOstr ? " " : "[]"); |
} |
putpad(SEstr); |
} |
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 ? "[]" : " "); |
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) sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0); |
} |
/* |
* 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(char *s, int set) |
{ |
if (set || CEstr == NULL) { |
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); |
} |
} |
/uspace/trunk/tetris/tetris.h |
---|
0,0 → 1,178 |
/* $OpenBSD: tetris.h,v 1.9 2003/06/03 03:01:41 millert Exp $ */ |
/* $NetBSD: tetris.h,v 1.2 1995/04/22 07:42:48 cgd Exp $ */ |
/*- |
* 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. 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; |
extern 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 |
extern 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 rotc; /* -- " -- in classic version */ |
int off[3]; /* offsets to other blots if center is at (0,0) */ |
}; |
extern const struct shape shapes[]; |
extern const struct shape *curshape; |
extern const struct shape *nextshape; |
/* |
* 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. |
*/ |
extern 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). |
* |
* If previewing has been turned on, the score is multiplied by PRE_PENALTY. |
*/ |
#define PRE_PENALTY 0.75 |
extern int score; /* the obvious thing */ |
extern gid_t gid, egid; |
extern char key_msg[100]; |
extern int showpreview; |
extern int classic; |
int fits_in(const struct shape *, int); |
void place(const struct shape *, int, int); |
void stop(char *); |
/uspace/trunk/tetris/scores.h |
---|
0,0 → 1,53 |
/* $OpenBSD: scores.h,v 1.5 2003/06/03 03:01:41 millert Exp $ */ |
/* $NetBSD: scores.h,v 1.2 1995/04/22 07:42:40 cgd Exp $ */ |
/*- |
* 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. 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[MAXLOGNAME]; /* 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(int); |
void showscores(int); |
/uspace/trunk/tetris/shapes.c |
---|
0,0 → 1,106 |
/* $OpenBSD: shapes.c,v 1.8 2004/07/10 07:26:24 deraadt Exp $ */ |
/* $NetBSD: shapes.c,v 1.2 1995/04/22 07:42:44 cgd Exp $ */ |
/*- |
* 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. 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 <unistd.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 */ |
const struct shape shapes[] = { |
/* 0*/ { 7, 7, { TL, TC, MR } }, |
/* 1*/ { 8, 8, { TC, TR, ML } }, |
/* 2*/ { 9, 11, { ML, MR, BC } }, |
/* 3*/ { 3, 3, { TL, TC, ML } }, |
/* 4*/ { 12, 14, { ML, BL, MR } }, |
/* 5*/ { 15, 17, { ML, BR, MR } }, |
/* 6*/ { 18, 18, { ML, MR, 2 } }, /* sticks out */ |
/* 7*/ { 0, 0, { TC, ML, BL } }, |
/* 8*/ { 1, 1, { TC, MR, BR } }, |
/* 9*/ { 10, 2, { TC, MR, BC } }, |
/*10*/ { 11, 9, { TC, ML, MR } }, |
/*11*/ { 2, 10, { TC, ML, BC } }, |
/*12*/ { 13, 4, { TC, BC, BR } }, |
/*13*/ { 14, 12, { TR, ML, MR } }, |
/*14*/ { 4, 13, { TL, TC, BC } }, |
/*15*/ { 16, 5, { TR, TC, BC } }, |
/*16*/ { 17, 15, { TL, MR, ML } }, |
/*17*/ { 5, 16, { TC, BC, BL } }, |
/*18*/ { 6, 6, { TC, BC, 2*B_COLS } }/* sticks out */ |
}; |
/* |
* Return true iff the given shape fits in the given position, |
* taking the current board into account. |
*/ |
int |
fits_in(const struct shape *shape, int pos) |
{ |
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(const struct shape *shape, int pos, int onoff) |
{ |
int *o = shape->off; |
board[pos] = onoff; |
board[pos + *o++] = onoff; |
board[pos + *o++] = onoff; |
board[pos + *o] = onoff; |
} |
/uspace/trunk/tetris/input.h |
---|
0,0 → 1,40 |
/* $OpenBSD: input.h,v 1.5 2003/06/03 03:01:41 millert Exp $ */ |
/* $NetBSD: input.h,v 1.2 1995/04/22 07:42:36 cgd Exp $ */ |
/*- |
* 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. 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 |
*/ |
int rwait(struct timeval *); |
int tgetchar(void); |
void tsleep(void); |
/uspace/trunk/tetris/screen.h |
---|
0,0 → 1,55 |
/* $OpenBSD: screen.h,v 1.5 2003/06/03 03:01:41 millert Exp $ */ |
/* $NetBSD: screen.h,v 1.2 1995/04/22 07:42:42 cgd Exp $ */ |
/*- |
* 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. 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). |
*/ |
extern char *SEstr; /* end standout mode */ |
extern char *SOstr; /* begin standout mode */ |
/* |
* putpad() is for padded strings with count=1. |
*/ |
#define putpad(s) tputs(s, 1, put) |
int put(int); /* just calls putchar; for tputs */ |
void scr_clear(void); |
void scr_end(void); |
void scr_init(void); |
void scr_msg(char *, int); |
void scr_set(void); |
void scr_update(void); |
/uspace/trunk/tetris/pathnames.h |
---|
0,0 → 1,38 |
/* $OpenBSD: pathnames.h,v 1.3 2003/06/03 03:01:41 millert Exp $ */ |
/* $NetBSD: pathnames.h,v 1.2 1995/04/22 07:42:37 cgd Exp $ */ |
/*- |
* 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. 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" |
/uspace/trunk/tetris/tetris.c |
---|
0,0 → 1,373 |
/* $OpenBSD: tetris.c,v 1.21 2006/04/20 03:24:12 ray Exp $ */ |
/* $NetBSD: tetris.c,v 1.2 1995/04/22 07:42:47 cgd Exp $ */ |
/*- |
* 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. 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 const 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/param.h> |
#include <sys/time.h> |
#include <sys/types.h> |
#include <err.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" |
cell board[B_SIZE]; |
int Rows, Cols; |
const struct shape *curshape; |
const struct shape *nextshape; |
long fallrate; |
int score; |
gid_t gid, egid; |
char key_msg[100]; |
int showpreview, classic; |
static void elide(void); |
static void setup_board(void); |
const struct shape *randshape(void); |
void onintr(int); |
void usage(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(void) |
{ |
int i; |
cell *p; |
p = board; |
for (i = B_SIZE; i; i--) |
*p++ = i <= (2 * B_COLS) || (i % B_COLS) < 2; |
} |
/* |
* Elide any full active rows. |
*/ |
static void |
elide(void) |
{ |
int rows = 0; |
int i, j, base; |
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 */ |
rows++; |
memset(&board[base], 0, B_COLS - 2); |
scr_update(); |
tsleep(); |
while (--base != 0) |
board[base + B_COLS] = board[base]; |
scr_update(); |
tsleep(); |
break; |
} |
} |
} |
switch (rows) { |
case 1: |
score += 10; |
break; |
case 2: |
score += 30; |
break; |
case 3: |
score += 70; |
break; |
case 4: |
score += 150; |
break; |
default: |
break; |
} |
} |
const struct shape * |
randshape(void) |
{ |
const struct shape *tmp; |
int i, j; |
tmp = &shapes[random() % 7]; |
j = random() % 4; |
for (i = 0; i < j; i++) |
tmp = &shapes[classic? tmp->rotc : tmp->rot]; |
return (tmp); |
} |
int |
main(int argc, char *argv[]) |
{ |
int pos, c; |
char *keys; |
int level = 2; |
char key_write[6][10]; |
const char *errstr; |
int ch, i, j; |
keys = "jkl pq"; |
gid = getgid(); |
egid = getegid(); |
setegid(gid); |
classic = showpreview = 0; |
while ((ch = getopt(argc, argv, "ck:l:ps")) != -1) |
switch(ch) { |
case 'c': |
/* |
* this means: |
* - rotate the other way; |
* - no reverse video. |
*/ |
classic = 1; |
break; |
case 'k': |
if (strlen(keys = optarg) != 6) |
usage(); |
break; |
case 'l': |
level = (int)strtonum(optarg, MINLEVEL, MAXLEVEL, |
&errstr); |
if (errstr) |
errx(1, "level must be from %d to %d", |
MINLEVEL, MAXLEVEL); |
break; |
case 'p': |
showpreview = 1; |
break; |
case 's': |
showscores(0); |
exit(0); |
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]) |
errx(1, "duplicate command keys specified."); |
} |
if (keys[i] == ' ') |
strlcpy(key_write[i], "<space>", sizeof key_write[i]); |
else { |
key_write[i][0] = keys[i]; |
key_write[i][1] = '\0'; |
} |
} |
snprintf(key_msg, sizeof 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(); |
srandomdev(); |
scr_set(); |
pos = A_FIRST*B_COLS + (B_COLS/2)-1; |
nextshape = randshape(); |
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 = nextshape; |
nextshape = 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 */ |
const struct shape *new = &shapes[ |
classic? curshape->rotc : 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_msg(key_msg, 1); |
} |
} |
scr_clear(); |
scr_end(); |
if (showpreview == 0) |
(void)printf("Your score: %d point%s x level %d = %d\n", |
score, score == 1 ? "" : "s", level, score * level); |
else { |
(void)printf("Your score: %d point%s x level %d x preview penalty %0.3f = %d\n", |
score, score == 1 ? "" : "s", level, (double)PRE_PENALTY, |
(int)(score * level * PRE_PENALTY)); |
score = score * PRE_PENALTY; |
} |
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(int signo) |
{ |
scr_clear(); /* XXX signal race */ |
scr_end(); /* XXX signal race */ |
_exit(0); |
} |
void |
usage(void) |
{ |
(void)fprintf(stderr, "usage: tetris [-ps] [-k keys] [-l level]\n"); |
exit(1); |
} |
/uspace/trunk/tetris/Makefile |
---|
0,0 → 1,18 |
# $OpenBSD: Makefile,v 1.7 2002/05/31 03:46:35 pjanzen Exp $ |
PROG= tetris |
SRCS= input.c screen.c shapes.c scores.c tetris.c |
MAN= tetris.6 |
DPADD= ${LIBCURSES} |
LDADD= -lcurses |
BINMODE=2555 |
beforeinstall: |
@if [ ! -f ${DESTDIR}/var/games/tetris.scores ]; then \ |
${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m 664 \ |
/dev/null ${DESTDIR}/var/games/tetris.scores ; \ |
else \ |
true ; \ |
fi |
.include <bsd.prog.mk> |