|
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(); }