1 /* $NetBSD: worm.c,v 1.29 2009/08/12 08:56:41 dholland 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\ 35 The Regents of the University of California. All rights reserved."); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)worm.c 8.1 (Berkeley) 5/31/93"; 41 #else 42 __RCSID("$NetBSD: worm.c,v 1.29 2009/08/12 08:56:41 dholland Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 /* 47 * Worm. Written by Michael Toy 48 * UCSC 49 */ 50 51 #include <ctype.h> 52 #include <curses.h> 53 #include <err.h> 54 #include <signal.h> 55 #include <stdlib.h> 56 #include <termios.h> 57 #include <unistd.h> 58 59 #define newlink() (struct body *) malloc(sizeof (struct body)); 60 #define HEAD '@' 61 #define BODY 'o' 62 #define LENGTH 7 63 #define RUNLEN 8 64 #define CNTRL(p) (p-'A'+1) 65 66 struct body { 67 int x; 68 int y; 69 struct body *prev; 70 struct body *next; 71 }; 72 73 static WINDOW *tv; 74 static WINDOW *stw; 75 static struct body *head, *tail, goody; 76 static int growing = 0; 77 static int running = 0; 78 static int slow = 0; 79 static int score = 0; 80 static int start_len = LENGTH; 81 static int visible_len; 82 static int lastch; 83 static char outbuf[BUFSIZ]; 84 85 int main(int, char **); 86 static void crash(void) __dead; 87 static void display(const struct body *, char); 88 static void leave(int) __dead; 89 static void life(void); 90 static void newpos(struct body *); 91 static void process(int); 92 static void prize(void); 93 static int rnd(int); 94 static void setup(void); 95 static void wake(int); 96 97 int 98 main(argc, argv) 99 int argc; 100 char **argv; 101 { 102 103 /* Revoke setgid privileges */ 104 setgid(getgid()); 105 106 setbuf(stdout, outbuf); 107 srand(getpid()); 108 signal(SIGALRM, wake); 109 signal(SIGINT, leave); 110 signal(SIGQUIT, leave); 111 if (!initscr()) 112 errx(0, "couldn't initialize screen"); 113 cbreak(); 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 static 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 visible_len = start_len + 1; 193 } 194 195 static void 196 display(pos, chr) 197 const struct body *pos; 198 char chr; 199 { 200 wmove(tv, pos->y, pos->x); 201 waddch(tv, chr); 202 } 203 204 static void 205 leave(dummy) 206 int dummy; 207 { 208 endwin(); 209 210 if (dummy == 0){ /* called via crash() */ 211 printf("\nWell, you ran into something and the game is over.\n"); 212 printf("Your final score was %d\n\n", score); 213 } 214 exit(0); 215 } 216 217 static void 218 wake(dummy) 219 int dummy __unused; 220 { 221 signal(SIGALRM, wake); 222 fflush(stdout); 223 process(lastch); 224 } 225 226 static int 227 rnd(range) 228 int range; 229 { 230 return abs((rand()>>5)+(rand()>>5)) % range; 231 } 232 233 static void 234 newpos(bp) 235 struct body * bp; 236 { 237 if (visible_len == (LINES-3) * (COLS-3) - 1) { 238 endwin(); 239 240 printf("\nYou won!\n"); 241 printf("Your final score was %d\n\n", score); 242 exit(0); 243 } 244 do { 245 bp->y = rnd(LINES-3)+ 1; 246 bp->x = rnd(COLS-3) + 1; 247 wmove(tv, bp->y, bp->x); 248 } while(winch(tv) != ' '); 249 } 250 251 static void 252 prize() 253 { 254 int value; 255 256 value = rnd(9) + 1; 257 newpos(&goody); 258 waddch(tv, value+'0'); 259 wrefresh(tv); 260 } 261 262 static void 263 process(ch) 264 int ch; 265 { 266 int x,y; 267 struct body *nh; 268 269 alarm(0); 270 x = head->x; 271 y = head->y; 272 switch(ch) 273 { 274 #ifdef KEY_LEFT 275 case KEY_LEFT: 276 #endif 277 case 'h': 278 x--; break; 279 280 #ifdef KEY_DOWN 281 case KEY_DOWN: 282 #endif 283 case 'j': 284 y++; break; 285 286 #ifdef KEY_UP 287 case KEY_UP: 288 #endif 289 case 'k': 290 y--; break; 291 292 #ifdef KEY_RIGHT 293 case KEY_RIGHT: 294 #endif 295 case 'l': 296 x++; break; 297 298 case 'H': x--; running = RUNLEN; ch = tolower(ch); break; 299 case 'J': y++; running = RUNLEN/2; ch = tolower(ch); break; 300 case 'K': y--; running = RUNLEN/2; ch = tolower(ch); break; 301 case 'L': x++; running = RUNLEN; ch = tolower(ch); break; 302 case '\f': setup(); return; 303 304 case ERR: 305 case CNTRL('C'): 306 case CNTRL('D'): 307 crash(); 308 return; 309 310 default: if (! running) alarm(1); 311 return; 312 } 313 lastch = ch; 314 if (growing == 0) 315 { 316 display(tail, ' '); 317 tail->next->prev = NULL; 318 nh = tail->next; 319 free(tail); 320 tail = nh; 321 visible_len--; 322 } 323 else growing--; 324 display(head, BODY); 325 wmove(tv, y, x); 326 if (isdigit(ch = winch(tv))) 327 { 328 growing += ch-'0'; 329 prize(); 330 score += growing; 331 running = 0; 332 wmove(stw, 0, COLS - 12); 333 wprintw(stw, "Score: %3d", score); 334 wrefresh(stw); 335 } 336 else if(ch != ' ') crash(); 337 nh = newlink(); 338 if (nh == NULL) 339 err(1, NULL); 340 nh->next = NULL; 341 nh->prev = head; 342 head->next = nh; 343 nh->y = y; 344 nh->x = x; 345 display(nh, HEAD); 346 head = nh; 347 visible_len++; 348 if (!(slow && running)) 349 { 350 wmove(tv, head->y, head->x); 351 wrefresh(tv); 352 } 353 if (!running) 354 alarm(1); 355 } 356 357 static void 358 crash() 359 { 360 leave(0); 361 } 362 363 static void 364 setup() 365 { 366 clear(); 367 refresh(); 368 touchwin(stw); 369 wrefresh(stw); 370 touchwin(tv); 371 wrefresh(tv); 372 alarm(1); 373 } 374