Home | History | Annotate | Line # | Download | only in worm
worm.c revision 1.21
      1 /*	$NetBSD: worm.c,v 1.21 2001/08/30 10:49:50 jsm Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1980, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
     39 	The Regents of the University of California.  All rights reserved.\n");
     40 #endif /* not lint */
     41 
     42 #ifndef lint
     43 #if 0
     44 static char sccsid[] = "@(#)worm.c	8.1 (Berkeley) 5/31/93";
     45 #else
     46 __RCSID("$NetBSD: worm.c,v 1.21 2001/08/30 10:49:50 jsm Exp $");
     47 #endif
     48 #endif /* not lint */
     49 
     50 /*
     51  * Worm.  Written by Michael Toy
     52  * UCSC
     53  */
     54 
     55 #include <ctype.h>
     56 #include <curses.h>
     57 #include <err.h>
     58 #include <signal.h>
     59 #include <stdlib.h>
     60 #include <termios.h>
     61 #include <unistd.h>
     62 
     63 #define newlink() (struct body *) malloc(sizeof (struct body));
     64 #define HEAD '@'
     65 #define BODY 'o'
     66 #define LENGTH 7
     67 #define RUNLEN 8
     68 #define CNTRL(p) (p-'A'+1)
     69 
     70 WINDOW *tv;
     71 WINDOW *stw;
     72 struct body {
     73 	int x;
     74 	int y;
     75 	struct body *prev;
     76 	struct body *next;
     77 } *head, *tail, goody;
     78 int growing = 0;
     79 int running = 0;
     80 int slow = 0;
     81 int score = 0;
     82 int start_len = LENGTH;
     83 int lastch;
     84 char outbuf[BUFSIZ];
     85 
     86 void	crash __P((void)) __attribute__((__noreturn__));
     87 void	display __P((const struct body *, char));
     88 int	main __P((int, char **));
     89 void	leave __P((int)) __attribute__((__noreturn__));
     90 void	life __P((void));
     91 void	newpos __P((struct body *));
     92 void	process __P((int));
     93 void	prize __P((void));
     94 int	rnd __P((int));
     95 void	setup __P((void));
     96 void	wake __P((int));
     97 
     98 int
     99 main(argc, argv)
    100 	int argc;
    101 	char **argv;
    102 {
    103 
    104 	/* Revoke setgid privileges */
    105 	setgid(getgid());
    106 
    107 	setbuf(stdout, outbuf);
    108 	srand(getpid());
    109 	signal(SIGALRM, wake);
    110 	signal(SIGINT, leave);
    111 	signal(SIGQUIT, leave);
    112 	initscr();
    113 	crmode();
    114 	noecho();
    115 #ifdef KEY_LEFT
    116 	keypad(stdscr, TRUE);
    117 #endif
    118 	slow = (baudrate() <= 1200);
    119 	clear();
    120 	if (COLS < 18 || LINES < 5) {
    121 		/*
    122 		 * Insufficient room for the line with " Worm" and the
    123 		 * score if fewer than 18 columns; insufficient room for
    124 		 * anything much if fewer than 5 lines.
    125 		 */
    126 		endwin();
    127 		errx(1, "screen too small");
    128 	}
    129 	if (argc == 2)
    130 		start_len = atoi(argv[1]);
    131 	if ((start_len <= 0) || (start_len > ((LINES-3) * (COLS-2)) / 3))
    132 		start_len = LENGTH;
    133 	stw = newwin(1, COLS-1, 0, 0);
    134 	tv = newwin(LINES-1, COLS-1, 1, 0);
    135 	box(tv, '*', '*');
    136 	scrollok(tv, FALSE);
    137 	scrollok(stw, FALSE);
    138 	wmove(stw, 0, 0);
    139 	wprintw(stw, " Worm");
    140 	refresh();
    141 	wrefresh(stw);
    142 	wrefresh(tv);
    143 	life();			/* Create the worm */
    144 	prize();		/* Put up a goal */
    145 	while(1)
    146 	{
    147 		if (running)
    148 		{
    149 			running--;
    150 			process(lastch);
    151 		}
    152 		else
    153 		{
    154 		    fflush(stdout);
    155 		    process(getch());
    156 		}
    157 	}
    158 }
    159 
    160 void
    161 life()
    162 {
    163 	struct body *bp, *np;
    164 	int i, j = 1;
    165 
    166 	np = NULL;
    167 	head = newlink();
    168 	if (head == NULL)
    169 		err(1, NULL);
    170 	head->x = start_len % (COLS-5) + 2;
    171 	head->y = LINES / 2;
    172 	head->next = NULL;
    173 	display(head, HEAD);
    174 	for (i = 0, bp = head; i < start_len; i++, bp = np) {
    175 		np = newlink();
    176 		if (np == NULL)
    177 			err(1, NULL);
    178 		np->next = bp;
    179 		bp->prev = np;
    180 		if (((bp->x <= 2) && (j == 1)) || ((bp->x >= COLS-4) && (j == -1))) {
    181 			j *= -1;
    182 			np->x = bp->x;
    183 			np->y = bp->y + 1;
    184 		} else {
    185 			np->x = bp->x - j;
    186 			np->y = bp->y;
    187 		}
    188 		display(np, BODY);
    189 	}
    190 	tail = np;
    191 	tail->prev = NULL;
    192 }
    193 
    194 void
    195 display(pos, chr)
    196 	const struct body *pos;
    197 	char chr;
    198 {
    199 	wmove(tv, pos->y, pos->x);
    200 	waddch(tv, chr);
    201 }
    202 
    203 void
    204 leave(dummy)
    205 	int dummy;
    206 {
    207 	endwin();
    208 
    209 	if (dummy == 0){	/* called via crash() */
    210 		printf("\nWell, you ran into something and the game is over.\n");
    211 		printf("Your final score was %d\n\n", score);
    212 	}
    213 	exit(0);
    214 }
    215 
    216 void
    217 wake(dummy)
    218 	int dummy __attribute__((__unused__));
    219 {
    220 	signal(SIGALRM, wake);
    221 	fflush(stdout);
    222 	process(lastch);
    223 }
    224 
    225 int
    226 rnd(range)
    227 	int range;
    228 {
    229 	return abs((rand()>>5)+(rand()>>5)) % range;
    230 }
    231 
    232 void
    233 newpos(bp)
    234 	struct body * bp;
    235 {
    236 	do {
    237 		bp->y = rnd(LINES-3)+ 1;
    238 		bp->x = rnd(COLS-3) + 1;
    239 		wmove(tv, bp->y, bp->x);
    240 	} while(winch(tv) != ' ');
    241 }
    242 
    243 void
    244 prize()
    245 {
    246 	int value;
    247 
    248 	value = rnd(9) + 1;
    249 	newpos(&goody);
    250 	waddch(tv, value+'0');
    251 	wrefresh(tv);
    252 }
    253 
    254 void
    255 process(ch)
    256 	int ch;
    257 {
    258 	int x,y;
    259 	struct body *nh;
    260 
    261 	alarm(0);
    262 	x = head->x;
    263 	y = head->y;
    264 	switch(ch)
    265 	{
    266 #ifdef KEY_LEFT
    267 		case KEY_LEFT:
    268 #endif
    269 		case 'h':
    270 			x--; break;
    271 
    272 #ifdef KEY_DOWN
    273 		case KEY_DOWN:
    274 #endif
    275 		case 'j':
    276 			y++; break;
    277 
    278 #ifdef KEY_UP
    279 		case KEY_UP:
    280 #endif
    281 		case 'k':
    282 			y--; break;
    283 
    284 #ifdef KEY_RIGHT
    285 		case KEY_RIGHT:
    286 #endif
    287 		case 'l':
    288 			x++; break;
    289 
    290 		case 'H': x--; running = RUNLEN; ch = tolower(ch); break;
    291 		case 'J': y++; running = RUNLEN/2; ch = tolower(ch); break;
    292 		case 'K': y--; running = RUNLEN/2; ch = tolower(ch); break;
    293 		case 'L': x++; running = RUNLEN; ch = tolower(ch); break;
    294 		case '\f': setup(); return;
    295 
    296 		case ERR:
    297 		case CNTRL('C'):
    298 		case CNTRL('D'):
    299 			crash();
    300 			return;
    301 
    302 		default: if (! running) alarm(1);
    303 			   return;
    304 	}
    305 	lastch = ch;
    306 	if (growing == 0)
    307 	{
    308 		display(tail, ' ');
    309 		tail->next->prev = NULL;
    310 		nh = tail->next;
    311 		free(tail);
    312 		tail = nh;
    313 	}
    314 	else growing--;
    315 	display(head, BODY);
    316 	wmove(tv, y, x);
    317 	if (isdigit(ch = winch(tv)))
    318 	{
    319 		growing += ch-'0';
    320 		prize();
    321 		score += growing;
    322 		running = 0;
    323 		wmove(stw, 0, COLS - 12);
    324 		wprintw(stw, "Score: %3d", score);
    325 		wrefresh(stw);
    326 	}
    327 	else if(ch != ' ') crash();
    328 	nh = newlink();
    329 	if (nh == NULL)
    330 		err(1, NULL);
    331 	nh->next = NULL;
    332 	nh->prev = head;
    333 	head->next = nh;
    334 	nh->y = y;
    335 	nh->x = x;
    336 	display(nh, HEAD);
    337 	head = nh;
    338 	if (!(slow && running))
    339 	{
    340 		wmove(tv, head->y, head->x);
    341 		wrefresh(tv);
    342 	}
    343 	if (!running)
    344 		alarm(1);
    345 }
    346 
    347 void
    348 crash()
    349 {
    350 	leave(0);
    351 }
    352 
    353 void
    354 setup()
    355 {
    356 	clear();
    357 	refresh();
    358 	touchwin(stw);
    359 	wrefresh(stw);
    360 	touchwin(tv);
    361 	wrefresh(tv);
    362 	alarm(1);
    363 }
    364