|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 12293 (0x3005)
Types: TextFile
Names: »snake2.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/Snake2/snake2.c«
/* snake2
*
* Copyright (C) 1981 by Don Libes. This software may be freely copied
* and distributed for noncommercial purposes provided that this notice
* remains intact. Commercial use of this software requires my prior
* written permission.
*
* HISTORY
* 04-Feb-86 Tony Hansen at pegasus!hansen
* Modified to support System V
*
* 20-Sep-85 libes at National Bureau of Standards
* Modified to support BSD 4.2 and Eunice (BSD 4.1)
* Modified to run on any size screen.
*
* 07-Aug-81 don at University of Rochester
* Fixed lack of rollover bug.
* ioctl(FIONREAD,...) gives # of NEW unread chars added to input
* buffer since last call, not just # of unread chars in buffer.
*
* 18-Jul-81 don at University of Rochester
* Ring structure for snake body was being corrupted. It seems C's
* idea on how to mod negative numbers is backwards. Hard to tell
* if this is a bug, because reference manual is fuzzy on this.
*
* 16-Jul-81 don at University of Rochester
* Created after playing similar game on DG at Xerox.
* Different scoring. Diagonal moves allowed. Boxes are people
* rather than just points. Various other hacks. See man file.
* cc snake2.c -lcurses -ltermcap -lipc
*/
#include <sys/types.h>
#include <signal.h>
#include <curses.h>
#include <ctype.h>
#include <pwd.h>
#include "snake2.h"
#define MAXUSERS 255 /* A large number */
#define MAXLEN ((LINES-2)*(COLS-2)) /* Maximum length of snake */
#define MAXBOXES 6
#define SKILL (12-6) /* How often we grow */
#ifdef SYSV
#define bell() beep()
#else
#define bell() putchar('\07') /* Ring my chimes */
#endif
time_t time(); /* For random factor */
int *snakex, *snakey; /* position of snake */
int sptr; /* ptr to snake in its array */
int length; /* length of snake */
int turn = 0; /* number of turns we've had */
int points = 0; /* Points by eating */
int diry = 1; /* direction we are moving */
int dirx = 1; /* initially diagonally and down */
/* Data structures for boxes */
struct {
int y;
int x;
int inuse;
char *name;
int length;
int points; /* point value of box */
} boxes[MAXBOXES];
char names[MAXUSERS][USERNAME_LENGTH+1];
int numnames = 0; /* number of names in /etc/passwd */
/* Data structures for log */
struct logtype {
char name[USERNAME_LENGTH+1];
int length;
int points;
int rows, columns;
} log[MAXUSERS];
long our_offset; /* position of our name in log file */
/* scoring algorithm */
#define score(length,points,rows,columns) ((points)+(length))
/* parameters for lseek */
#define L_SET 0
#define L_INCR 1
#define L_XTND 2
char *getlogin(), *whoami;
char *strncpy(), *malloc();
int sortlog();
FILE *fopen();
FILE *lf;
int reluid; /* uid relative to log file */
int usersknown; /* number of users in log */
int userknown = FALSE; /* if user in log file */
int maxlen;
WINDOW *tmpscr; /* save screen for clear */
WINDOW *newwin();
main()
{
init();
while (TRUE) {
if (!snake()) break; /* get user input */
#ifndef SYSV
quick_sleep(TIMEOUT);
#endif
ranbox(); /* randomly box */
ranbox2(); /* randomly unbox */
}
quit();
}
intr()
{
cleanup();
exit(0);
}
init()
{
int i = 0;
extern struct passwd *getpwent(), *getpwuid();
struct passwd *pwent;
long last_offset; /* keep track of offsets in log file */
#ifdef EUNICE
/* if invoked from raw VMS, getlogin() screws up by returning */
/* an empty string rather than a null string */
if (!((whoami = getlogin()) && whoami[0])) {
#else
if (!(whoami = getlogin())) {
#endif
/* can't just copy ptr from getpwuid since this is */
/* static data which will be reused when we read in */
/* /etc/passwd! */
whoami = malloc(USERNAME_LENGTH+1);
strncpy(whoami,getpwuid(getuid())->pw_name, USERNAME_LENGTH);
}
setuid(geteuid());
initscr();
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, intr);
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
signal(SIGQUIT, intr);
tmpscr = newwin(LINES,COLS,0,0);
box(stdscr,'|','-');
noecho(); /* Don't let directions echo! */
#ifdef SYSV
cbreak();
makehalfdelay();
#else
raw();
#endif
refresh();
maxlen = MAXLEN;
snakex = (int *)malloc(maxlen*sizeof(int));
snakey = (int *)malloc(maxlen*sizeof(int));
snakex[0] = snakey[0] = 2;
move(2,2);
addch('s');
snakey[1] = 3; snakex[1] = 3;
move(3,3);
addch('s');
length = 2;
sptr = 1;
srand((int) time((time_t *)0));
/* read in names */
while ((pwent = getpwent()) && numnames < MAXUSERS) {
strncpy(names[numnames++],pwent->pw_name, USERNAME_LENGTH);
}
if (!(lf = fopen(LOG,"r+"))) {
cleanup();
printf("can't read/update score file (%s)\n",LOG);
exit(0);
}
last_offset = our_offset = 0L;
while (5 == fscanf(lf,"%s%d%d%d%d",log[i].name,&log[i].length,
&log[i].points,
&log[i].rows,
&log[i].columns)) {
if (!userknown) {
if (!strcmp(whoami,log[i].name)) {
our_offset = last_offset;
reluid = i;
userknown = TRUE;
/* Give'm something to shoot for */
move(LINES-1,50);
printw("Personal high score: %d",
score(log[i].length,log[i].points,
log[i].rows,log[i].columns));
} else last_offset = ftell(lf);
}
i++;
}
if (!userknown) { /* New entry for this user */
our_offset = last_offset;
strcpy(log[i].name,whoami);
log[i].length = 0;
log[i].points = 0;
log[i].rows = LINES;
log[i].columns = COLS;
reluid = i;
userknown = TRUE;
/* make new entry in log file */
fseek(lf,0L,L_XTND); /* EOF */
fprintf(lf,"%*s%8d%8d%8d%8d\n",USERNAME_LENGTH,
log[i].name,
log[i].length,
log[i].points,
log[i].rows,
log[i].columns);
i++;
}
fclose(lf);
usersknown = i;
}
quit()
{
int i = 0;
if (score(length,points,LINES,COLS) >
score(log[reluid].length,
log[reluid].points,
log[reluid].rows,
log[reluid].columns)) { /* new personal high score! */
log[reluid].length = length;
log[reluid].points = points;
log[reluid].rows = LINES;
log[reluid].columns = COLS;
if (!(lf = fopen(LOG,"r+"))) {
cleanup();
printf("can't update score file (%s)\n",LOG);
exit(0);
}
fseek(lf,our_offset+1,L_SET);
fprintf(lf,"%*s%8d%8d%8d%8d\n",USERNAME_LENGTH,
whoami,length,points,LINES,COLS);
fclose(lf);
}
/* the 36 here is just the width of the stripe we are painting */
/* i.e. it equals the width of the printw */
move(1,(COLS-36)/2);
printw("%*s%8s%8s%8s",USERNAME_LENGTH,
"Who","Length","Points","Score");
/* print out top LINES-4 scorers (right on top of game) */
qsort(log,usersknown,sizeof(struct logtype),sortlog);
for (i=0;i<(LINES-4) && i<usersknown;i++) {
move(2+i,(COLS-36)/2);
printw("%*s%8d%8d%8d",USERNAME_LENGTH,
log[i].name,log[i].length,log[i].points,
score(log[i].points,log[i].length,
log[i].rows,log[i].columns));
}
cleanup();
}
snake()
{
int key; /* last key struck */
turn++;
if (-1 != (key = getkey())) {
switch (key) {
case 'i': case '8': case 'e':
if (diry == 1 && dirx == 0) bell();
else {
diry = -1;
dirx = 0;
}
break;
case 'l': case '6': case 'f':
if (diry == 0 && dirx == -1) bell();
else {
diry = 0;
dirx = 1;
}
break;
case ',': case '2': case 'c':
if (diry == -1 && dirx == 0) bell();
else {
diry = 1;
dirx = 0;
}
break;
case 'j': case '4': case 's':
if (diry == 0 && dirx == 1) bell();
else {
diry = 0;
dirx = -1;
}
break;
case '9': case 'o': case 'r':
if (diry == 1 && dirx == -1) bell();
else {
diry = -1;
dirx = 1;
}
break;
case '3': case '.': case 'v':
if (diry == -1 && dirx == -1) bell();
else {
diry = 1;
dirx = 1;
}
break;
case '1': case 'm': case 'x':
if (diry == -1 && dirx == 1) bell();
else {
diry = 1;
dirx = -1;
}
break;
case '7': case 'u': case 'w':
if (diry == 1 && dirx == 1) bell();
else {
diry = -1;
dirx = -1;
}
break;
case 003: /* Ctrl-C */
case 004: /* Ctrl-D */
case 0177: /* Rubout */
case 034: /* FS */
case 'q': case 'Q':
return(0);
break;
case 014: /* Ctrl-L */
/* Really refresh screen */
wclear(tmpscr);
overlay(stdscr,tmpscr);
clear();
refresh();
overlay(tmpscr,stdscr);
break;
}
}
return movesnake(diry,dirx);
}
movesnake(y,x) /* check if snake hits money or edge of window, too */
{
int c;
int newsptr; /* temp snake pointer */
newsptr = (1+sptr)%maxlen;
/* keep snake at right length */
if (turn%SKILL) {
move(snakey[(maxlen+1+sptr-length)%maxlen],
snakex[(maxlen+1+sptr-length)%maxlen]);
addch(' ');
} else {
length++;
move(0,15);
printw("Length = %d",length);
move(0,33);
printw("Points = %d",points);
move(0,51);
printw("Score = %d",score(length,points,LINES,COLS));
}
/* move head of snake one step further */
snakey[newsptr] = snakey[sptr]+y;
snakex[newsptr] = snakex[sptr]+x;
/* check for a hit! */
move(snakey[newsptr],snakex[newsptr]);
if (snakey[newsptr] == 0 || snakey[newsptr] == LINES-1 ||
snakex[newsptr] == 0 || snakex[newsptr] == COLS-1) {
move(LINES-2,2);
addstr("You hit the edge, you snake!");
return(0);
}
c = inch();
if (c != ' ') { /* musta hit sumptin, duh... */
int i;
for (i=0;i<MAXBOXES;i++) {
if (!boxes[i].inuse) continue;
if (boxes[i].x <= snakex[newsptr] &&
boxes[i].x + boxes[i].length > snakex[newsptr] &&
boxes[i].y <= snakey[newsptr] &&
boxes[i].y + boxes[i].length > snakey[newsptr]) {
/* hit box i */
delbox(i);
/* double points after 250 */
if (points+length>=250)
points += 2*boxes[i].points;
else points += boxes[i].points;
move(0,33);
printw("Points = %d",points);
move(0,51);
printw("Score = %d",points+length);
break;
}
}
if (i == MAXBOXES) {
move(LINES-2,2);
addstr("You hit yourself, you snake!");
return(0);
}
}
move(snakey[sptr],snakex[sptr]);
addch('s');
move(snakey[newsptr],snakex[newsptr]);
addch('S');
sptr = newsptr;
refresh();
return(TRUE);
}
ranbox() /* randomly draw a box */
{
int i, j, y, x, y2, x2, s;
int length;
i = rand()%MAXBOXES;
if (boxes[i].inuse) return;
j = rand()%numnames;
length = strlen(names[j]);
y = 1 + rand()%((LINES-1)-length);
x = 1 + rand()%((COLS-1)-length);
/* check if area is clear */
for(y2=y;y2<y+length;y2++) {
for (x2=x;x2<x+length;x2++) {
move(y2,x2);
if (' ' != inch()) return;
}
}
boxes[i].inuse = TRUE;
boxes[i].x = x;
boxes[i].y = y;
boxes[i].name = names[j];
boxes[i].length = length;
if (!(s = rand()%9)) boxes[i].points = length*3;
else boxes[i].points = length;
if (names[j] == names[0] ) { /* root! */
boxes[i].points = (rand()%40) - 20;
}
/* draw box */
/* top */
move(y,x);
addstr(names[j]);
/* show triple value by capitalizing first letter */
if ((!s) && (islower(names[j][0]))) {
move(y,x);
addch(names[j][0]-('a'-'A'));
}
for (y2=y+1;y2<y+length;y2++) {
/* left side */
move(y2,x);
addch(names[j][y2-y]);
/* right side */
move(y2,x+length-1);
addch(names[j][length-(y2-y)-1]);
}
/* bottom */
for (x2=x+1;x2<x+length-1;x2++) {
move(y+length-1,x2);
addch(names[j][length-(x2-x)-1]);
}
}
ranbox2() /* randomly delete a box */
{
/* about every 10 times try and delete a randomly selected box */
if (!(rand()%10)) {
delbox(rand()%MAXBOXES);
}
}
delbox(i) /* delete a box */
int i;
{
int x2, y2, x, y;
int length;
if (!boxes[i].inuse) return;
x = boxes[i].x;
y = boxes[i].y;
length = boxes[i].length;
boxes[i].inuse = FALSE;
/* delete box (this should probably be written as one loop) */
move(y,x);
/* delete top of box */
for (x2=x;x2<x+length;x2++) {
/* to */
move(y,x2);
addch(' ');
}
/* sides */
for (y2=y+1;y2<y+length;y2++) {
move(y2,x);
addch(' ');
move(y2,x+length-1);
addch(' ');
}
/* bottom */
for (x2=x+1;x2<x+length-1;x2++) {
move(y+length-1,x2);
addch(' ');
}
}
sortlog(foo,bar) /* sort function for log */
struct logtype *foo;
struct logtype *bar;
{
int x, y;
x = score(foo->length,foo->points,foo->rows,foo->columns);
y = score(bar->length,bar->points,bar->rows,bar->columns);
if (x == y) return(0);
else if (x > y) return(-1);
else return(1);
}
cleanup()
{
/* move UNIX prompt to bottom line (from where?) */
move(LINES-1,0);
echo();
noraw();
refresh();
endwin();
}