Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 1418 → Rev 1419

/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>