[net.sources] snake.c -- a slightly enhanced version of the "worm" game

david@infopro.UUCP (Buckaroo Banzai) (01/01/85)

Happy New Year to Everyone! I was taking a leisure time break when I
suddenly realized a small enhancement could be made to "worm". 
Snake has a cute little serpentine head that points in the direction
you're going, after the snake wakes up and starts stalking his food.
Apart from flushing buffers at the end so you won't lose your score, 
this is the only real change. The whole source is here in case you
didn't already have it. Don't forget to remove the .signature at the end.

So long, and thanks for all the fish.
Dave Fiedler

-------------------- cut here -----------------------
/*
 * Snake, from worm Written by Michael Toy
 * UCSC
 * modified by a.wiedemann 05.17.82
 * Siemens AG Munich
 * ZTI INF 212
 *
 * herpetology added by David Fiedler, InfoPro Systems
 * {astrovax, harpo, whuxcc}!infopro!dave
 *
 * compile with "cc -O -s -o snake snake.c -lcurses -ltermcap
 *
 */

#include <ctype.h>
#include "curses.h"
#include <signal.h>

char *getenv();

#define newlink() (struct body *) malloc(sizeof (struct body));
#define HEAD '@'
#define BODY 'o'
#define	UP	1
#define	DOWN	2
#define	LEFT	3
#define	RIGHT	4
#define LENGTH 7
#define RUNLEN 8
#define when break;case
#define otherwise break;default
#define CNTRL(p) ('p'-'A'+1)

WINDOW *tv;
WINDOW *stw;
struct body {
	int x;
	int y;
	struct body *prev;
	struct body *next;
} *head, *tail, goody, *malloc();

int growing = 0;
int running = 0;
int score = 0;
int start_len = LENGTH;
char lastch;
char outbuf[BUFSIZ];

main(argc, argv)
char **argv;
{
	int leave(), wake(), suspend();
	char ch;

	if (argc == 2)
		{
		start_len = atoi(argv[1]);
		score += (start_len - LENGTH);
		}
	setbuf(stdout, outbuf);
	srand(getpid());
	signal(SIGALRM, wake);
	signal(SIGINT, leave);
	signal(SIGQUIT, leave);
#ifdef SIGTSTP
	signal(SIGTSTP, suspend);	/* process control signal */
#endif
	initscr();
	crmode();
	noecho();
	clear();
	stw = newwin(1, COLS-1, 0, 0);
	tv = newwin(LINES-1, COLS-1, 1, 0);
	/* snake cannot be bigger than the inner width of tv window !! */
	if ((start_len <= 0) || (start_len > COLS - 6))
		start_len = LENGTH;
	box(tv, '*', '*');
	scrollok(tv, FALSE);
	scrollok(stw, FALSE);
	wmove(stw, 0, 0);
	wprintw(stw, " Snake");
	refresh();
	wrefresh(stw);
	wrefresh(tv);
	life();                 /* Create the snake */
	prize();                /* Put up a goal */
	for (;;)
	{
		if (running)
		{
			running--;
			process(lastch);
		}
		else
		{
		    fflush(stdout);
		    if (read(0, &ch, 1) >= 0)
			process(ch);
		}
	}
}

life()
{
	register struct body *bp, *np;
	register int i;

	head = newlink();
	head->x = start_len+2;
	head->y = 12;
	head->next = NULL;
	display(head, HEAD);
	for (i = 0, bp = head; i < start_len; i++, bp = np) {
		np = newlink();
		np->next = bp;
		bp->prev = np;
		np->x = bp->x - 1;
		np->y = bp->y;
		display(np, BODY);
	}
	tail = np;
	tail->prev = NULL;
	wrefresh(tv);
}

display(pos, chr)
struct body *pos;
char chr;
{
	wmove(tv, pos->y, pos->x);
	waddch(tv, chr);
}

leave()
{
	move(LINES - 1, 0);
	refresh();
	endwin();
	exit(0);
}

wake()
{
	signal(SIGALRM, wake);
	fflush(stdout);
	process(lastch);
}

rnd(range)
{
	return abs((rand()>>5)+(rand()>>5)) % range;
}

newpos(bp)
struct body * bp;
{
	do {
		bp->y = rnd(LINES-3)+ 2;
		bp->x = rnd(COLS-3) + 1;
		wmove(tv, bp->y, bp->x);
	} while(winch(tv) != ' ');
}

prize()
{
	int value;

	value = rnd(9) + 1;
	newpos(&goody);
	waddch(tv, value+'0');
	wrefresh(tv);
}

process(ch)
char ch;
{
	register int x,y;
	struct body *nh;
	static char headchar, dir;

	alarm(0);
	x = head->x;
	y = head->y;
	switch(ch)
	{
		when 'h': x--; dir=LEFT;
		when 'j': y++; dir=DOWN;
		when 'k': y--; dir=UP;
		when 'l': x++; dir=RIGHT;
		when 'H': x--; running = RUNLEN; ch = tolower(ch);dir=LEFT;
		when 'J': y++; running = RUNLEN/2; ch = tolower(ch);dir=DOWN;
		when 'K': y--; running = RUNLEN/2; ch = tolower(ch);dir=UP;
		when 'L': x++; running = RUNLEN; ch = tolower(ch);dir=RIGHT;
		when '\f': setup(); return;
		when CNTRL(Z): suspend(); return;
		when CNTRL(C): crash(); return;
		when CNTRL(D): crash(); return;
		otherwise: if (! running) alarm(1);
			   return;
	}
	lastch = ch;
	if (growing == 0)
	{
		display(tail, ' ');
		tail->next->prev = NULL;
		nh = tail->next;
		free(tail);
		tail = nh;
	}
	else growing--;
	display(head, BODY);
	wmove(tv, y, x);
	if (isdigit(ch = winch(tv)))
	{
		growing += ch-'0';
		prize();
		score += growing;
		running = 0;
		wmove(stw, 0, 68);
		wprintw(stw, "Score: %3d", score);
		wrefresh(stw);
	}
	else if(ch != ' ') crash();
	nh = newlink();
	nh->next = NULL;
	nh->prev = head;
	head->next = nh;
	nh->y = y;
	nh->x = x;
	switch (dir) {
		case UP:
			headchar = '^'; break;
		case DOWN:
			headchar = 'V'; break;
		case LEFT:
			headchar = '<' ; break;
		case RIGHT:
			headchar = '>' ; break;
		default:
			headchar = HEAD ;
		}
	display(nh, headchar);
	head = nh;
	wrefresh(tv);
	if (! running) alarm(1);
}

crash()
{
	sleep(2);
	clear();
	move(LINES - 1, 0);
	refresh();
	endwin();
	fflush(stdout);
	printf("Well you ran into something and the game is over.\n");
	printf("Your final score was %d\n", score);
	leave();
}

suspend()
{
	char *sh;

	move(LINES-1, 0);
	refresh();
	endwin();
	fflush(stdout);
#ifdef SIGTSTP
	kill(getpid(), SIGTSTP);
	signal(SIGTSTP, suspend);
#else
	sh = getenv("SHELL");
	if (sh == NULL)
		sh = "/bin/sh";
	system(sh);
#endif
	crmode();
	noecho();
	setup();
}

setup()
{
	clear();
	refresh();
	touchwin(stw);
	wrefresh(stw);
	touchwin(tv);
	wrefresh(tv);
	alarm(1);
}
-- 
          Dave Fiedler
{harpo,astrovax,whuxcc,clyde}!infopro!dave
USMail: InfoPro Systems, 3108 Route 10, Denville, NJ 07834
People Phone: (201) 989-0570

mitch@gitpyr.UUCP (Mitch Lukaart) (01/07/85)

> Happy New Year to Everyone! I was taking a leisure time break when I
> suddenly realized a small enhancement could be made to "worm". 
> Snake has a cute little serpentine head that points in the direction
> you're going, after the snake wakes up and starts stalking his food.
> Apart from flushing buffers at the end so you won't lose your score, 
> this is the only real change. The whole source is here in case you
> didn't already have it. Don't forget to remove the .signature at the end.
> 
> So long, and thanks for all the fish.
> Dave Fiedler
> 
> -------------------- cut here -----------------------
> /*
>  * Snake, from worm Written by Michael Toy
>  * UCSC
>  * modified by a.wiedemann 05.17.82
>  * Siemens AG Munich
>  * ZTI INF 212
>  *
>  * herpetology added by David Fiedler, InfoPro Systems
>  * {astrovax, harpo, whuxcc}!infopro!dave
>  *
>  * compile with "cc -O -s -o snake snake.c -lcurses -ltermcap
>  *
>  */
> 
> #include <ctype.h>
> #include "curses.h"
> #include <signal.h>
> 
> char *getenv();
> 
> #define newlink() (struct body *) malloc(sizeof (struct body));
> #define HEAD '@'
> #define BODY 'o'
> #define	UP	1
> #define	DOWN	2
> #define	LEFT	3
> #define	RIGHT	4
> #define LENGTH 7
> #define RUNLEN 8
> #define when break;case
> #define otherwise break;default
> #define CNTRL(p) ('p'-'A'+1)
> 
> WINDOW *tv;
> WINDOW *stw;
> struct body {
> 	int x;
> 	int y;
> 	struct body *prev;
> 	struct body *next;
> } *head, *tail, goody, *malloc();
> 
> int growing = 0;
> int running = 0;
> int score = 0;
> int start_len = LENGTH;
> char lastch;
> char outbuf[BUFSIZ];
> 
> main(argc, argv)
> char **argv;
> {
> 	int leave(), wake(), suspend();
> 	char ch;
> 
> 	if (argc == 2)
> 		{
> 		start_len = atoi(argv[1]);
> 		score += (start_len - LENGTH);
> 		}
> 	setbuf(stdout, outbuf);
> 	srand(getpid());
> 	signal(SIGALRM, wake);
> 	signal(SIGINT, leave);
> 	signal(SIGQUIT, leave);
> #ifdef SIGTSTP
> 	signal(SIGTSTP, suspend);	/* process control signal */
> #endif
> 	initscr();
> 	crmode();
> 	noecho();
> 	clear();
> 	stw = newwin(1, COLS-1, 0, 0);
> 	tv = newwin(LINES-1, COLS-1, 1, 0);
> 	/* snake cannot be bigger than the inner width of tv window !! */
> 	if ((start_len <= 0) || (start_len > COLS - 6))
> 		start_len = LENGTH;
> 	box(tv, '*', '*');
> 	scrollok(tv, FALSE);
> 	scrollok(stw, FALSE);
> 	wmove(stw, 0, 0);
> 	wprintw(stw, " Snake");
> 	refresh();
> 	wrefresh(stw);
> 	wrefresh(tv);
> 	life();                 /* Create the snake */
> 	prize();                /* Put up a goal */
> 	for (;;)
> 	{
> 		if (running)
> 		{
> 			running--;
> 			process(lastch);
> 		}
> 		else
> 		{
> 		    fflush(stdout);
> 		    if (read(0, &ch, 1) >= 0)
> 			process(ch);
> 		}
> 	}
> }
> 
> life()
> {
> 	register struct body *bp, *np;
> 	register int i;
> 
> 	head = newlink();
> 	head->x = start_len+2;
> 	head->y = 12;
> 	head->next = NULL;
> 	display(head, HEAD);
> 	for (i = 0, bp = head; i < start_len; i++, bp = np) {
> 		np = newlink();
> 		np->next = bp;
> 		bp->prev = np;
> 		np->x = bp->x - 1;
> 		np->y = bp->y;
> 		display(np, BODY);
> 	}
> 	tail = np;
> 	tail->prev = NULL;
> 	wrefresh(tv);
> }
> 
> display(pos, chr)
> struct body *pos;
> char chr;
> {
> 	wmove(tv, pos->y, pos->x);
> 	waddch(tv, chr);
> }
> 
> leave()
> {
> 	move(LINES - 1, 0);
> 	refresh();
> 	endwin();
> 	exit(0);
> }
> 
> wake()
> {
> 	signal(SIGALRM, wake);
> 	fflush(stdout);
> 	process(lastch);
> }
> 
> rnd(range)
> {
> 	return abs((rand()>>5)+(rand()>>5)) % range;
> }
> 
> newpos(bp)
> struct body * bp;
> {
> 	do {
> 		bp->y = rnd(LINES-3)+ 2;
> 		bp->x = rnd(COLS-3) + 1;
> 		wmove(tv, bp->y, bp->x);
> 	} while(winch(tv) != ' ');
> }
> 
> prize()
> {
> 	int value;
> 
> 	value = rnd(9) + 1;
> 	newpos(&goody);
> 	waddch(tv, value+'0');
> 	wrefresh(tv);
> }
> 
> process(ch)
> char ch;
> {
> 	register int x,y;
> 	struct body *nh;
> 	static char headchar, dir;
> 
> 	alarm(0);
> 	x = head->x;
> 	y = head->y;
> 	switch(ch)
> 	{
> 		when 'h': x--; dir=LEFT;
> 		when 'j': y++; dir=DOWN;
> 		when 'k': y--; dir=UP;
> 		when 'l': x++; dir=RIGHT;
> 		when 'H': x--; running = RUNLEN; ch = tolower(ch);dir=LEFT;
> 		when 'J': y++; running = RUNLEN/2; ch = tolower(ch);dir=DOWN;
> 		when 'K': y--; running = RUNLEN/2; ch = tolower(ch);dir=UP;
> 		when 'L': x++; running = RUNLEN; ch = tolower(ch);dir=RIGHT;
> 		when '\f': setup(); return;
> 		when CNTRL(Z): suspend(); return;
> 		when CNTRL(C): crash(); return;
> 		when CNTRL(D): crash(); return;
> 		otherwise: if (! running) alarm(1);
> 			   return;
> 	}
> 	lastch = ch;
> 	if (growing == 0)
> 	{
> 		display(tail, ' ');
> 		tail->next->prev = NULL;
> 		nh = tail->next;
> 		free(tail);
> 		tail = nh;
> 	}
> 	else growing--;
> 	display(head, BODY);
> 	wmove(tv, y, x);
> 	if (isdigit(ch = winch(tv)))
> 	{
> 		growing += ch-'0';
> 		prize();
> 		score += growing;
> 		running = 0;
> 		wmove(stw, 0, 68);
> 		wprintw(stw, "Score: %3d", score);
> 		wrefresh(stw);
> 	}
> 	else if(ch != ' ') crash();
> 	nh = newlink();
> 	nh->next = NULL;
> 	nh->prev = head;
> 	head->next = nh;
> 	nh->y = y;
> 	nh->x = x;
> 	switch (dir) {
> 		case UP:
> 			headchar = '^'; break;
> 		case DOWN:
> 			headchar = 'V'; break;
> 		case LEFT:
> 			headchar = '<' ; break;
> 		case RIGHT:
> 			headchar = '>' ; break;
> 		default:
> 			headchar = HEAD ;
> 		}
> 	display(nh, headchar);
> 	head = nh;
> 	wrefresh(tv);
> 	if (! running) alarm(1);
> }
> 
> crash()
> {
> 	sleep(1);
> 	clear();
> 	move(LINES - 1, 0);
> 	refresh();
> 	endwin();
> 	fflush(stdout);
> 	printf("Well you ran into something and the game is over.\n");
> 	printf("Your final score was %d\n", score);
> 	leave();
> }
> 
> suspend()
> {
> 	char *sh;
> 
> 	move(LINES-1, 0);
> 	refresh();
> 	endwin();
> 	fflush(stdout);
> #ifdef SIGTSTP
> 	kill(getpid(), SIGTSTP);
> 	signal(SIGTSTP, suspend);
> #else
> 	sh = getenv("SHELL");
> 	if (sh == NULL)
> 		sh = "/bin/sh";
> 	system(sh);
> #endif
> 	crmode();
> 	noecho();
> 	setup();
> }
> 
> setup()
> {
> 	clear();
> 	refresh();
> 	touchwin(stw);
> 	wrefresh(stw);
> 	touchwin(tv);
> 	wrefresh(tv);
> 	alarm(1);
> }
> -- 
>           Dave Fiedler
> {harpo,astrovax,whuxcc,clyde}!infopro!dave
> USMail: InfoPro Systems, 3108 Route 10, Denville, NJ 07834
> People Phone: (201) 989-0570

*** REPLACE THIS LINE WITH YOUR MESSAGE ***