Import NetBSD games/snake command.

Change-Id: Ie46c0acc09e5e8079f80301ae3a40172fcfb51dd
This commit is contained in:
Alexandre Beletti 2014-09-23 04:16:10 -03:00 committed by Ben Gras
parent 3a40bab785
commit 831337191b
9 changed files with 1326 additions and 1 deletions

View file

@ -602,6 +602,8 @@
./usr/games/ppt minix-sys
./usr/games/primes minix-sys
./usr/games/random minix-sys
./usr/games/snake minix-sys
./usr/games/snscore minix-sys
./usr/games/strfile minix-sys
./usr/games/tetris minix-sys
./usr/games/unstr minix-sys
@ -5033,6 +5035,7 @@
./usr/man/man6/ppt.6 minix-sys
./usr/man/man6/primes.6 minix-sys
./usr/man/man6/random.6 minix-sys
./usr/man/man6/snake.6 minix-sys
./usr/man/man6/tetris.6 minix-sys
./usr/man/man6/wargames.6 minix-sys
./usr/man/man7 minix-sys

View file

@ -13,7 +13,7 @@ SUBDIR= adventure arithmetic \
factor fortune \
monop morse number \
pig ppt primes \
random tetris \
random snake tetris \
wargames
.if !defined(__MINIX)

6
games/snake/Makefile Normal file
View file

@ -0,0 +1,6 @@
# $NetBSD: Makefile,v 1.3 1995/04/22 08:34:18 cgd Exp $
# @(#)Makefile 8.1 (Berkeley) 5/31/93
SUBDIR= snake snscore
.include <bsd.subdir.mk>

View file

@ -0,0 +1,13 @@
# $NetBSD: Makefile,v 1.10 2010/02/06 23:45:26 he Exp $
# @(#)Makefile 8.1 (Berkeley) 5/31/93
PROG= snake
SRCS= snake.c
MAN= snake.6
DPADD= ${LIBM} ${LIBCURSES} ${LIBTERMINFO}
LDADD= -lm -lcurses -lterminfo
HIDEGAME=hidegame
SETGIDGAME=yes
.include "../../Makefile.inc"
.include <bsd.prog.mk>

View file

@ -0,0 +1,35 @@
/* $NetBSD: pathnames.h,v 1.4 2003/08/07 09:37:45 agc Exp $ */
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. 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_RAWSCORES "/var/games/snakerawscores"
#define _PATH_LOGFILE "/var/games/snake.log"

126
games/snake/snake/snake.6 Normal file
View file

@ -0,0 +1,126 @@
.\" $NetBSD: snake.6,v 1.12 2009/03/11 13:05:59 joerg Exp $
.\"
.\" Copyright (c) 1980, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. 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.
.\"
.\" @(#)snake.6 8.1 (Berkeley) 5/31/93
.\"
.Dd May 31, 1993
.Dt SNAKE 6
.Os
.Sh NAME
.Nm snake ,
.Nm snscore
.Nd display chase game
.Sh SYNOPSIS
.Nm
.Op Fl w Ar width
.Op Fl l Ar length
.Op Fl t
.Nm snscore
.Sh DESCRIPTION
.Nm
is a display-based game which must be played on a CRT terminal.
The object of the game is to make as much money as possible without
getting eaten by the snake.
The
.Fl l
and
.Fl w
options allow you to specify the length and width of the field.
By default the entire screen is used.
The
.Fl t
option makes the game assume you are on a slow terminal.
.Pp
You are represented on the screen by an I.
The snake is 6 squares long and is represented by s's with an S at its head.
The money is $, and an exit is #.
Your score is posted in the upper left hand corner.
.Pp
You can move around using the same conventions as
.Xr vi 1 ,
the
.Ic h ,
.Ic j ,
.Ic k ,
and
.Ic l
keys work, as do the arrow keys.
Other possibilities include:
.Bl -tag -width indent
.It Ic sefc
These keys are like hjkl but form a directed pad around the d key.
.It Ic HJKL
These keys move you all the way in the indicated direction to the
same row or column as the money.
This does
.Em not
let you jump away from the snake, but rather saves you from having
to type a key repeatedly.
The snake still gets all his turns.
.It Ic SEFC
Likewise for the upper case versions on the left.
.It Ic ATPB
These keys move you to the four edges of the screen.
Their position on the keyboard is the mnemonic, e.g.
P is at the far right of the keyboard.
.It Ic x
This lets you quit the game at any time.
.It Ic p
Points in a direction you might want to go.
.It Ic w
Space warp to get out of tight squeezes, at a price.
.El
.Pp
To earn money, move to the same square the money is on.
A new $ will appear when you earn the current one.
As you get richer, the snake gets hungrier.
To leave the game, move to the exit (#).
.Pp
A record is kept of the personal best score of each player.
Scores are only counted if you leave at the exit,
getting eaten by the snake is worth nothing.
.Pp
As in pinball, matching the last digit of your score to the number
which appears after the game is worth a bonus.
.Pp
To see who wastes time playing snake, run
.Nm snscore .
.Sh FILES
.Bl -tag -width /var/games/snakerawscores -compact
.It Pa /var/games/snakerawscores
database of personal bests
.It Pa /var/games/snake.log
log of games played
.El
.Sh BUGS
When playing on a small screen,
it's hard to tell when you hit the edge of the screen.
.Pp
The scoring function takes into account the size of the screen.
A perfect function to do this equitably has not been devised.

999
games/snake/snake/snake.c Normal file
View file

@ -0,0 +1,999 @@
/* $NetBSD: snake.c,v 1.28 2012/06/19 05:46:09 dholland Exp $ */
/*
* Copyright (c) 1980, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1980, 1993\
The Regents of the University of California. All rights reserved.");
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)snake.c 8.2 (Berkeley) 1/7/94";
#else
__RCSID("$NetBSD: snake.c,v 1.28 2012/06/19 05:46:09 dholland Exp $");
#endif
#endif /* not lint */
/*
* snake - crt hack game.
*
* You move around the screen with arrow keys trying to pick up money
* without getting eaten by the snake. hjkl work as in vi in place of
* arrow keys. You can leave at the exit any time.
*
* compile as follows:
* cc -O snake.c move.c -o snake -lm -ltermlib
*/
#include <sys/param.h>
#include <curses.h>
#include <fcntl.h>
#include <pwd.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <err.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include "pathnames.h"
#define cashvalue chunk*(loot-penalty)/25
struct point {
int col, line;
};
#define same(s1, s2) ((s1)->line == (s2)->line && (s1)->col == (s2)->col)
#define PENALTY 10 /* % penalty for invoking spacewarp */
#define EOT '\004'
#define LF '\n'
#define DEL '\177'
#define ME 'I'
#define SNAKEHEAD 'S'
#define SNAKETAIL 's'
#define TREASURE '$'
#define GOAL '#'
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#define pchar(point, c) mvaddch((point)->line + 1, (point)->col + 1, (c))
#define delay(t) usleep(t * 50000);
static struct point you;
static struct point money;
static struct point finish;
static struct point snake[6];
static int loot, penalty;
static int moves;
static int fast = 1;
static int rawscores;
static FILE *logfile;
static int lcnt, ccnt; /* user's idea of screen size */
static int chunk; /* amount of money given at a time */
static void chase(struct point *, struct point *);
static int chk(const struct point *);
static void drawbox(void);
static void flushi(void);
static void length(int);
static void logit(const char *);
static void mainloop(void) __dead;
static struct point *point(struct point *, int, int);
static int post(int, int);
static int pushsnake(void);
static void setup(void);
static void snap(void);
static void snrand(struct point *);
static void spacewarp(int);
static void stop(int) __dead;
static int stretch(const struct point *);
static void surround(struct point *);
static void suspend(void);
static void win(const struct point *);
static void winnings(int);
int
main(int argc, char **argv)
{
int ch, i;
time_t tv;
/* Open score files then revoke setgid privileges */
rawscores = open(_PATH_RAWSCORES, O_RDWR|O_CREAT, 0664);
if (rawscores < 0) {
warn("open %s", _PATH_RAWSCORES);
sleep(2);
} else if (rawscores < 3)
exit(1);
logfile = fopen(_PATH_LOGFILE, "a");
if (logfile == NULL) {
warn("fopen %s", _PATH_LOGFILE);
sleep(2);
}
setgid(getgid());
(void) time(&tv);
while ((ch = getopt(argc, argv, "l:w:t")) != -1)
switch ((char) ch) {
#ifdef DEBUG
case 'd':
tv = atol(optarg);
break;
#endif
case 'w': /* width */
ccnt = atoi(optarg);
break;
case 'l': /* length */
lcnt = atoi(optarg);
break;
case 't':
fast = 0;
break;
case '?':
default:
#ifdef DEBUG
fprintf(stderr,
"usage: %s [-d seed] [-w width] [-l length] [-t]\n",
getprogname());
#else
fprintf(stderr,
"usage: %s [-w width] [-l length] [-t]\n",
getprogname());
#endif
exit(1);
}
srandom((int) tv);
penalty = loot = 0;
if (!initscr())
errx(0, "couldn't initialize screen");;
cbreak();
noecho();
#ifdef KEY_LEFT
keypad(stdscr, TRUE);
#endif
if (!lcnt || lcnt > LINES - 2)
lcnt = LINES - 2;
if (!ccnt || ccnt > COLS - 2)
ccnt = COLS - 2;
i = MIN(lcnt, ccnt);
if (i < 4) {
endwin();
errx(1, "screen too small for a fair game.");
}
/*
* chunk is the amount of money the user gets for each $.
* The formula below tries to be fair for various screen sizes.
* We only pay attention to the smaller of the 2 edges, since
* that seems to be the bottleneck.
* This formula is a hyperbola which includes the following points:
* (24, $25) (original scoring algorithm)
* (12, $40) (experimentally derived by the "feel")
* (48, $15) (a guess)
* This will give a 4x4 screen $99/shot. We don't allow anything
* smaller than 4x4 because there is a 3x3 game where you can win
* an infinite amount of money.
*/
if (i < 12)
i = 12; /* otherwise it isn't fair */
/*
* Compensate for border. This really changes the game since
* the screen is two squares smaller but we want the default
* to be $25, and the high scores on small screens were a bit
* much anyway.
*/
i += 2;
chunk = (675.0 / (i + 6)) + 2.5; /* min screen edge */
signal(SIGINT, stop);
snrand(&finish);
snrand(&you);
snrand(&money);
snrand(&snake[0]);
for (i = 1; i < 6; i++)
chase(&snake[i], &snake[i - 1]);
setup();
mainloop();
/* NOTREACHED */
return (0);
}
static struct point *
point(struct point *ps, int x, int y)
{
ps->col = x;
ps->line = y;
return (ps);
}
/* Main command loop */
static void
mainloop(void)
{
int k;
int repeat = 1;
int lastc = 0;
for (;;) {
int c;
/* Highlight you, not left & above */
move(you.line + 1, you.col + 1);
refresh();
if (((c = getch()) <= '9') && (c >= '0')) {
repeat = c - '0';
while (((c = getch()) <= '9') && (c >= '0'))
repeat = 10 * repeat + (c - '0');
} else {
if (c != '.')
repeat = 1;
}
if (c == '.') {
c = lastc;
}
if (!fast)
flushi();
lastc = c;
switch (c) {
case CTRL('z'):
suspend();
continue;
case EOT:
case 'x':
case 0177: /* del or end of file */
endwin();
length(moves);
logit("quit");
exit(0);
case CTRL('l'):
setup();
winnings(cashvalue);
continue;
case 'p':
case 'd':
snap();
continue;
case 'w':
spacewarp(0);
continue;
case 'A':
repeat = you.col;
c = 'h';
break;
case 'H':
case 'S':
repeat = you.col - money.col;
c = 'h';
break;
case 'T':
repeat = you.line;
c = 'k';
break;
case 'K':
case 'E':
repeat = you.line - money.line;
c = 'k';
break;
case 'P':
repeat = ccnt - 1 - you.col;
c = 'l';
break;
case 'L':
case 'F':
repeat = money.col - you.col;
c = 'l';
break;
case 'B':
repeat = lcnt - 1 - you.line;
c = 'j';
break;
case 'J':
case 'C':
repeat = money.line - you.line;
c = 'j';
break;
}
for (k = 1; k <= repeat; k++) {
moves++;
switch (c) {
case 's':
case 'h':
#ifdef KEY_LEFT
case KEY_LEFT:
#endif
case '\b':
if (you.col > 0) {
if ((fast) || (k == 1))
pchar(&you, ' ');
you.col--;
if ((fast) || (k == repeat) ||
(you.col == 0))
pchar(&you, ME);
}
break;
case 'f':
case 'l':
#ifdef KEY_RIGHT
case KEY_RIGHT:
#endif
case ' ':
if (you.col < ccnt - 1) {
if ((fast) || (k == 1))
pchar(&you, ' ');
you.col++;
if ((fast) || (k == repeat) ||
(you.col == ccnt - 1))
pchar(&you, ME);
}
break;
case CTRL('p'):
case 'e':
case 'k':
#ifdef KEY_UP
case KEY_UP:
#endif
case 'i':
if (you.line > 0) {
if ((fast) || (k == 1))
pchar(&you, ' ');
you.line--;
if ((fast) || (k == repeat) ||
(you.line == 0))
pchar(&you, ME);
}
break;
case CTRL('n'):
case 'c':
case 'j':
#ifdef KEY_DOWN
case KEY_DOWN:
#endif
case LF:
case 'm':
if (you.line + 1 < lcnt) {
if ((fast) || (k == 1))
pchar(&you, ' ');
you.line++;
if ((fast) || (k == repeat) ||
(you.line == lcnt - 1))
pchar(&you, ME);
}
break;
}
if (same(&you, &money)) {
loot += 25;
if (k < repeat)
pchar(&you, ' ');
do {
snrand(&money);
} while ((money.col == finish.col &&
money.line == finish.line) ||
(money.col < 5 && money.line == 0) ||
(money.col == you.col &&
money.line == you.line));
pchar(&money, TREASURE);
winnings(cashvalue);
continue;
}
if (same(&you, &finish)) {
win(&finish);
flushi();
endwin();
printf("You have won with $%d.\n", cashvalue);
fflush(stdout);
logit("won");
post(cashvalue, 1);
length(moves);
exit(0);
}
if (pushsnake())
break;
}
}
}
/*
* setup the board
*/
static void
setup(void)
{
int i;
erase();
pchar(&you, ME);
pchar(&finish, GOAL);
pchar(&money, TREASURE);
for (i = 1; i < 6; i++) {
pchar(&snake[i], SNAKETAIL);
}
pchar(&snake[0], SNAKEHEAD);
drawbox();
refresh();
}
static void
drawbox(void)
{
int i;
for (i = 1; i <= ccnt; i++) {
mvaddch(0, i, '-');
mvaddch(lcnt + 1, i, '-');
}
for (i = 0; i <= lcnt + 1; i++) {
mvaddch(i, 0, '|');
mvaddch(i, ccnt + 1, '|');
}
}
static void
snrand(struct point *sp)
{
struct point p;
int i;
for (;;) {
p.col = random() % ccnt;
p.line = random() % lcnt;
/* make sure it's not on top of something else */
if (p.line == 0 && p.col < 5)
continue;
if (same(&p, &you))
continue;
if (same(&p, &money))
continue;
if (same(&p, &finish))
continue;
for (i = 0; i < 6; i++)
if (same(&p, &snake[i]))
break;
if (i < 6)
continue;
break;
}
*sp = p;
}
static int
post(int iscore, int flag)
{
short score = iscore;
short uid;
short oldbest = 0;
short allbwho = 0, allbscore = 0;
struct passwd *p;
/* I want to printf() the scores for terms that clear on cook(),
* but this routine also gets called with flag == 0 to see if
* the snake should wink. If (flag) then we're at game end and
* can printf.
*/
/*
* Neg uid, 0, and 1 cannot have scores recorded.
*/
if ((uid = getuid()) <= 1) {
if (flag)
printf("No saved scores for uid %d.\n", uid);
return (1);
}
if (rawscores < 0) {
/* Error reported earlier */
return (1);
}
/* Figure out what happened in the past */
read(rawscores, &allbscore, sizeof(short));
read(rawscores, &allbwho, sizeof(short));
lseek(rawscores, uid * sizeof(short), SEEK_SET);
read(rawscores, &oldbest, sizeof(short));
if (!flag) {
lseek(rawscores, 0, SEEK_SET);
return (score > oldbest ? 1 : 0);
}
/* Update this jokers best */
if (score > oldbest) {
lseek(rawscores, uid * sizeof(short), SEEK_SET);
write(rawscores, &score, sizeof(short));
printf("You bettered your previous best of $%d\n", oldbest);
} else
printf("Your best to date is $%d\n", oldbest);
/* See if we have a new champ */
p = getpwuid(allbwho);
if (score > allbscore) {
lseek(rawscores, 0, SEEK_SET);
write(rawscores, &score, sizeof(short));
write(rawscores, &uid, sizeof(short));
if (allbwho) {
if (p)
printf("You beat %s's old record of $%d!\n",
p->pw_name, allbscore);
else
printf("You beat (%d)'s old record of $%d!\n",
(int)allbwho, allbscore);
}
else
printf("You set a new record!\n");
} else if (p)
printf("The highest is %s with $%d\n", p->pw_name, allbscore);
else
printf("The highest is (%d) with $%d\n", (int)allbwho,
allbscore);
lseek(rawscores, 0, SEEK_SET);
return (1);
}
/*
* Flush typeahead to keep from buffering a bunch of chars and then
* overshooting. This loses horribly at 9600 baud, but works nicely
* if the terminal gets behind.
*/
static void
flushi(void)
{
tcflush(0, TCIFLUSH);
}
static const int mx[8] = {
0, 1, 1, 1, 0, -1, -1, -1
};
static const int my[8] = {
-1, -1, 0, 1, 1, 1, 0, -1
};
static const float absv[8] = {
1, 1.4, 1, 1.4, 1, 1.4, 1, 1.4
};
static int oldw = 0;
static void
chase(struct point *np, struct point *sp)
{
/* this algorithm has bugs; otherwise the snake would get too good */
struct point d;
int w, i, wt[8];
double v1, v2, vp, max;
point(&d, you.col - sp->col, you.line - sp->line);
v1 = sqrt((double) (d.col * d.col + d.line * d.line));
w = 0;
max = 0;
for (i = 0; i < 8; i++) {
vp = d.col * mx[i] + d.line * my[i];
v2 = absv[i];
if (v1 > 0)
vp = ((double) vp) / (v1 * v2);
else
vp = 1.0;
if (vp > max) {
max = vp;
w = i;
}
}
for (i = 0; i < 8; i++) {
point(&d, sp->col + mx[i], sp->line + my[i]);
wt[i] = 0;
if (d.col < 0 || d.col >= ccnt || d.line < 0 || d.line >= lcnt)
continue;
/*
* Change to allow snake to eat you if you're on the money,
* otherwise, you can just crouch there until the snake goes
* away. Not positive it's right.
*
* if (d.line == 0 && d.col < 5) continue;
*/
if (same(&d, &money))
continue;
if (same(&d, &finish))
continue;
wt[i] = i == w ? loot / 10 : 1;
if (i == oldw)
wt[i] += loot / 20;
}
for (w = i = 0; i < 8; i++)
w += wt[i];
vp = ((random() >> 6) & 01777) % w;
for (i = 0; i < 8; i++)
if (vp < wt[i])
break;
else
vp -= wt[i];
if (i == 8) {
printw("failure\n");
i = 0;
while (wt[i] == 0)
i++;
}
oldw = w = i;
point(np, sp->col + mx[w], sp->line + my[w]);
}
static void
spacewarp(int w)
{
struct point p;
int j;
const char *str;
snrand(&you);
point(&p, COLS / 2 - 8, LINES / 2 - 1);
if (p.col < 0)
p.col = 0;
if (p.line < 0)
p.line = 0;
if (w) {
str = "BONUS!!!";
loot = loot - penalty;
penalty = 0;
} else {
str = "SPACE WARP!!!";
penalty += loot / PENALTY;
}
for (j = 0; j < 3; j++) {
erase();
refresh();
delay(5);
mvaddstr(p.line + 1, p.col + 1, str);
refresh();
delay(10);
}
setup();
winnings(cashvalue);
}
static void
snap(void)
{
#if 0 /* This code doesn't really make sense. */
struct point p;
if (you.line < 3) {
mvaddch(1, you.col + 1, '-');
}
if (you.line > lcnt - 4) {
mvaddch(lcnt, you.col + 1, '_');
}
if (you.col < 10) {
mvaddch(you.line + 1, 1, '(');
}
if (you.col > ccnt - 10) {
mvaddch(you.line + 1, ccnt, ')');
}
#endif
if (!stretch(&money))
if (!stretch(&finish)) {
pchar(&you, '?');
refresh();
delay(10);
pchar(&you, ME);
}
#if 0
if (you.line < 3) {
point(&p, you.col, 0);
chk(&p);
}
if (you.line > lcnt - 4) {
point(&p, you.col, lcnt - 1);
chk(&p);
}
if (you.col < 10) {
point(&p, 0, you.line);
chk(&p);
}
if (you.col > ccnt - 10) {
point(&p, ccnt - 1, you.line);
chk(&p);
}
#endif
refresh();
}
static int
stretch(const struct point *ps)
{
struct point p;
point(&p, you.col, you.line);
if ((abs(ps->col - you.col) < (ccnt / 12)) && (you.line != ps->line)) {
if (you.line < ps->line) {
for (p.line = you.line + 1; p.line <= ps->line; p.line++)
pchar(&p, 'v');
refresh();
delay(10);
for (; p.line > you.line; p.line--)
chk(&p);
} else {
for (p.line = you.line - 1; p.line >= ps->line; p.line--)
pchar(&p, '^');
refresh();
delay(10);
for (; p.line < you.line; p.line++)
chk(&p);
}
return (1);
} else
if ((abs(ps->line - you.line) < (lcnt/7))
&& (you.col != ps->col)) {
p.line = you.line;
if (you.col < ps->col) {
for (p.col = you.col + 1; p.col <= ps->col; p.col++)
pchar(&p, '>');
refresh();
delay(10);
for (; p.col > you.col; p.col--)
chk(&p);
} else {
for (p.col = you.col - 1; p.col >= ps->col; p.col--)
pchar(&p, '<');
refresh();
delay(10);
for (; p.col < you.col; p.col++)
chk(&p);
}
return (1);
}
return (0);
}
static void
surround(struct point *ps)
{
int j;
if (ps->col == 0)
ps->col++;
if (ps->line == 0)
ps->line++;
if (ps->line == LINES - 1)
ps->line--;
if (ps->col == COLS - 1)
ps->col--;
mvaddstr(ps->line, ps->col, "/*\\");
mvaddstr(ps->line + 1, ps->col, "* *");
mvaddstr(ps->line + 2, ps->col, "\\*/");
for (j = 0; j < 20; j++) {
pchar(ps, '@');
refresh();
delay(1);
pchar(ps, ' ');
refresh();
delay(1);
}
if (post(cashvalue, 0)) {
mvaddstr(ps->line, ps->col, " ");
mvaddstr(ps->line + 1, ps->col, "o.o");
mvaddstr(ps->line + 2, ps->col, "\\_/");
refresh();
delay(6);
mvaddstr(ps->line, ps->col, " ");
mvaddstr(ps->line + 1, ps->col, "o.-");
mvaddstr(ps->line + 2, ps->col, "\\_/");
refresh();
delay(6);
}
mvaddstr(ps->line, ps->col, " ");
mvaddstr(ps->line + 1, ps->col, "o.o");
mvaddstr(ps->line + 2, ps->col, "\\_/");
refresh();
delay(6);
}
static void
win(const struct point *ps)
{
struct point x;
int j, k;
int boxsize; /* actually diameter of box, not radius */
boxsize = fast ? 10 : 4;
point(&x, ps->col, ps->line);
for (j = 1; j < boxsize; j++) {
for (k = 0; k < j; k++) {
pchar(&x, '#');
x.line--;
}
for (k = 0; k < j; k++) {
pchar(&x, '#');
x.col++;
}
j++;
for (k = 0; k < j; k++) {
pchar(&x, '#');
x.line++;
}
for (k = 0; k < j; k++) {
pchar(&x, '#');
x.col--;
}
refresh();
delay(1);
}
}
static int
pushsnake(void)
{
int i, bonus;
int issame = 0;
struct point tmp;
/*
* My manual says times doesn't return a value. Furthermore, the
* snake should get his turn every time no matter if the user is
* on a fast terminal with typematic keys or not.
* So I have taken the call to times out.
*/
for (i = 4; i >= 0; i--)
if (same(&snake[i], &snake[5]))
issame++;
if (!issame)
pchar(&snake[5], ' ');
/* Need the following to catch you if you step on the snake's tail */
tmp.col = snake[5].col;
tmp.line = snake[5].line;
for (i = 4; i >= 0; i--)
snake[i + 1] = snake[i];
chase(&snake[0], &snake[1]);
pchar(&snake[1], SNAKETAIL);
pchar(&snake[0], SNAKEHEAD);
for (i = 0; i < 6; i++) {
if (same(&snake[i], &you) || same(&tmp, &you)) {
surround(&you);
i = (cashvalue) % 10;
bonus = ((random() >> 8) & 0377) % 10;
mvprintw(lcnt + 1, 0, "%d\n", bonus);
refresh();
delay(30);
if (bonus == i) {
spacewarp(1);
logit("bonus");
flushi();
return (1);
}
flushi();
endwin();
if (loot >= penalty) {
printf("\nYou and your $%d have been eaten\n",
cashvalue);
} else {
printf("\nThe snake ate you. You owe $%d.\n",
-cashvalue);
}
logit("eaten");
length(moves);
exit(0);
}
}
return (0);
}
static int
chk(const struct point *sp)
{
int j;
if (same(sp, &money)) {
pchar(sp, TREASURE);
return (2);
}
if (same(sp, &finish)) {
pchar(sp, GOAL);
return (3);
}
if (same(sp, &snake[0])) {
pchar(sp, SNAKEHEAD);
return (4);
}
for (j = 1; j < 6; j++) {
if (same(sp, &snake[j])) {
pchar(sp, SNAKETAIL);
return (4);
}
}
if ((sp->col < 4) && (sp->line == 0)) {
winnings(cashvalue);
if ((you.line == 0) && (you.col < 4))
pchar(&you, ME);
return (5);
}
if (same(sp, &you)) {
pchar(sp, ME);
return (1);
}
pchar(sp, ' ');
return (0);
}
static void
winnings(int won)
{
if (won > 0) {
mvprintw(1, 1, "$%d", won);
}
}
static void
stop(int dummy __unused)
{
signal(SIGINT, SIG_IGN);
endwin();
length(moves);
exit(0);
}
static void
suspend(void)
{
endwin();
kill(getpid(), SIGTSTP);
refresh();
winnings(cashvalue);
}
static void
length(int num)
{
printf("You made %d moves.\n", num);
}
static void
logit(const char *msg)
{
time_t t;
if (logfile != NULL) {
time(&t);
fprintf(logfile, "%s $%d %dx%d %s %s",
getlogin(), cashvalue, lcnt, ccnt, msg, ctime(&t));
fflush(logfile);
}
}

View file

@ -0,0 +1,11 @@
# $NetBSD: Makefile,v 1.7 2002/09/18 06:16:41 lukem Exp $
# @(#)Makefile 8.1 (Berkeley) 5/31/93
NOMAN= # defined
PROG= snscore
CPPFLAGS+= -I${.CURDIR}/../snake
HIDEGAME= hidegame
.include "../../Makefile.inc"
.include <bsd.prog.mk>

View file

@ -0,0 +1,132 @@
/* $NetBSD: snscore.c,v 1.19 2012/06/19 05:46:09 dholland Exp $ */
/*
* Copyright (c) 1980, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1980, 1993\
The Regents of the University of California. All rights reserved.");
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)snscore.c 8.1 (Berkeley) 7/19/93";
#else
__RCSID("$NetBSD: snscore.c,v 1.19 2012/06/19 05:46:09 dholland Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <err.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "pathnames.h"
static const char *recfile = _PATH_RAWSCORES;
#define MAXPLAYERS 256
struct player {
short uids;
short scores;
char *name;
};
static struct player players[MAXPLAYERS], temp;
int main(void);
int
main(void)
{
short uid, score;
FILE *fd;
int noplayers;
int i, j, notsorted;
short whoallbest, allbest;
const char *q;
struct passwd *p;
/* Revoke setgid privileges */
setgid(getgid());
fd = fopen(recfile, "r");
if (fd == NULL)
err(1, "opening `%s'", recfile);
printf("Snake players scores to date\n");
if (fread(&whoallbest, sizeof(short), 1, fd) == 0) {
printf("No scores recorded yet!\n");
exit(0);
}
fread(&allbest, sizeof(short), 1, fd);
noplayers = 0;
for (uid = 2; ;uid++) {
if(fread(&score, sizeof(short), 1, fd) == 0)
break;
if (score > 0) {
if (noplayers >= MAXPLAYERS) {
printf("too many players\n");
exit(2);
}
players[noplayers].uids = uid;
players[noplayers].scores = score;
p = getpwuid(uid);
if (p == NULL)
continue;
q = p -> pw_name;
players[noplayers].name = strdup(q);
if (players[noplayers].name == NULL)
err(1, NULL);
noplayers++;
}
}
/* bubble sort scores */
for (notsorted = 1; notsorted; ) {
notsorted = 0;
for (i = 0; i < noplayers - 1; i++)
if (players[i].scores < players[i + 1].scores) {
temp = players[i];
players[i] = players[i + 1];
players[i + 1] = temp;
notsorted++;
}
}
j = 1;
for (i = 0; i < noplayers; i++) {
printf("%d:\t$%d\t%s\n", j, players[i].scores, players[i].name);
if (players[i].scores > players[i + 1].scores)
j = i + 2;
}
exit(0);
}