1 /* $NetBSD: worm.c,v 1.26 2007/12/15 19:44:45 perry 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\n\ 35 The Regents of the University of California. All rights reserved.\n"); 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.26 2007/12/15 19:44:45 perry 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 WINDOW *tv; 67 WINDOW *stw; 68 struct body { 69 int x; 70 int y; 71 struct body *prev; 72 struct body *next; 73 } *head, *tail, goody; 74 int growing = 0; 75 int running = 0; 76 int slow = 0; 77 int score = 0; 78 int start_len = LENGTH; 79 int visible_len; 80 int lastch; 81 char outbuf[BUFSIZ]; 82 83 void crash(void) __dead; 84 void display(const struct body *, char); 85 int main(int, char **); 86 void leave(int) __dead; 87 void life(void); 88 void newpos(struct body *); 89 void process(int); 90 void prize(void); 91 int rnd(int); 92 void setup(void); 93 void wake(int); 94 95 int 96 main(argc, argv) 97 int argc; 98 char **argv; 99 { 100 101 /* Revoke setgid privileges */ 102 setgid(getgid()); 103 104 setbuf(stdout, outbuf); 105 srand(getpid()); 106 signal(SIGALRM, wake); 107 signal(SIGINT, leave); 108 signal(SIGQUIT, leave); 109 initscr(); 110 cbreak(); 111 noecho(); 112 #ifdef KEY_LEFT 113 keypad(stdscr, TRUE); 114 #endif 115 slow = (baudrate() <= 1200); 116 clear(); 117 if (COLS < 18 || LINES < 5) { 118 /* 119 * Insufficient room for the line with " Worm" and the 120 * score if fewer than 18 columns; insufficient room for 121 * anything much if fewer than 5 lines. 122 */ 123 endwin(); 124 errx(1, "screen too small"); 125 } 126 if (argc == 2) 127 start_len = atoi(argv[1]); 128 if ((start_len <= 0) || (start_len > ((LINES-3) * (COLS-2)) / 3)) 129 start_len = LENGTH; 130 stw = newwin(1, COLS-1, 0, 0); 131 tv = newwin(LINES-1, COLS-1, 1, 0); 132 box(tv, '*', '*'); 133 scrollok(tv, FALSE); 134 scrollok(stw, FALSE); 135 wmove(stw, 0, 0); 136 wprintw(stw, " Worm"); 137 refresh(); 138 wrefresh(stw); 139 wrefresh(tv); 140 life(); /* Create the worm */ 141 prize(); /* Put up a goal */ 142 while(1) 143 { 144 if (running) 145 { 146 running--; 147 process(lastch); 148 } 149 else 150 { 151 fflush(stdout); 152 process(getch()); 153 } 154 } 155 } 156 157 void 158 life() 159 { 160 struct body *bp, *np; 161 int i, j = 1; 162 163 np = NULL; 164 head = newlink(); 165 if (head == NULL) 166 err(1, NULL); 167 head->x = start_len % (COLS-5) + 2; 168 head->y = LINES / 2; 169 head->next = NULL; 170 display(head, HEAD); 171 for (i = 0, bp = head; i < start_len; i++, bp = np) { 172 np = newlink(); 173 if (np == NULL) 174 err(1, NULL); 175 np->next = bp; 176 bp->prev = np; 177 if (((bp->x <= 2) && (j == 1)) || ((bp->x >= COLS-4) && (j == -1))) { 178 j *= -1; 179 np->x = bp->x; 180 np->y = bp->y + 1; 181 } else { 182 np->x = bp->x - j; 183 np->y = bp->y; 184 } 185 display(np, BODY); 186 } 187 tail = np; 188 tail->prev = NULL; 189 visible_len = start_len + 1; 190 } 191 192 void 193 display(pos, chr) 194 const struct body *pos; 195 char chr; 196 { 197 wmove(tv, pos->y, pos->x); 198 waddch(tv, chr); 199 } 200 201 void 202 leave(dummy) 203 int dummy; 204 { 205 endwin(); 206 207 if (dummy == 0){ /* called via crash() */ 208 printf("\nWell, you ran into something and the game is over.\n"); 209 printf("Your final score was %d\n\n", score); 210 } 211 exit(0); 212 } 213 214 void 215 wake(dummy) 216 int dummy __unused; 217 { 218 signal(SIGALRM, wake); 219 fflush(stdout); 220 process(lastch); 221 } 222 223 int 224 rnd(range) 225 int range; 226 { 227 return abs((rand()>>5)+(rand()>>5)) % range; 228 } 229 230 void 231 newpos(bp) 232 struct body * bp; 233 { 234 if (visible_len == (LINES-3) * (COLS-3) - 1) { 235 endwin(); 236 237 printf("\nYou won!\n"); 238 printf("Your final score was %d\n\n", score); 239 exit(0); 240 } 241 do { 242 bp->y = rnd(LINES-3)+ 1; 243 bp->x = rnd(COLS-3) + 1; 244 wmove(tv, bp->y, bp->x); 245 } while(winch(tv) != ' '); 246 } 247 248 void 249 prize() 250 { 251 int value; 252 253 value = rnd(9) + 1; 254 newpos(&goody); 255 waddch(tv, value+'0'); 256 wrefresh(tv); 257 } 258 259 void 260 process(ch) 261 int ch; 262 { 263 int x,y; 264 struct body *nh; 265 266 alarm(0); 267 x = head->x; 268 y = head->y; 269 switch(ch) 270 { 271 #ifdef KEY_LEFT 272 case KEY_LEFT: 273 #endif 274 case 'h': 275 x--; break; 276 277 #ifdef KEY_DOWN 278 case KEY_DOWN: 279 #endif 280 case 'j': 281 y++; break; 282 283 #ifdef KEY_UP 284 case KEY_UP: 285 #endif 286 case 'k': 287 y--; break; 288 289 #ifdef KEY_RIGHT 290 case KEY_RIGHT: 291 #endif 292 case 'l': 293 x++; break; 294 295 case 'H': x--; running = RUNLEN; ch = tolower(ch); break; 296 case 'J': y++; running = RUNLEN/2; ch = tolower(ch); break; 297 case 'K': y--; running = RUNLEN/2; ch = tolower(ch); break; 298 case 'L': x++; running = RUNLEN; ch = tolower(ch); break; 299 case '\f': setup(); return; 300 301 case ERR: 302 case CNTRL('C'): 303 case CNTRL('D'): 304 crash(); 305 return; 306 307 default: if (! running) alarm(1); 308 return; 309 } 310 lastch = ch; 311 if (growing == 0) 312 { 313 display(tail, ' '); 314 tail->next->prev = NULL; 315 nh = tail->next; 316 free(tail); 317 tail = nh; 318 visible_len--; 319 } 320 else growing--; 321 display(head, BODY); 322 wmove(tv, y, x); 323 if (isdigit(ch = winch(tv))) 324 { 325 growing += ch-'0'; 326 prize(); 327 score += growing; 328 running = 0; 329 wmove(stw, 0, COLS - 12); 330 wprintw(stw, "Score: %3d", score); 331 wrefresh(stw); 332 } 333 else if(ch != ' ') crash(); 334 nh = newlink(); 335 if (nh == NULL) 336 err(1, NULL); 337 nh->next = NULL; 338 nh->prev = head; 339 head->next = nh; 340 nh->y = y; 341 nh->x = x; 342 display(nh, HEAD); 343 head = nh; 344 visible_len++; 345 if (!(slow && running)) 346 { 347 wmove(tv, head->y, head->x); 348 wrefresh(tv); 349 } 350 if (!running) 351 alarm(1); 352 } 353 354 void 355 crash() 356 { 357 leave(0); 358 } 359 360 void 361 setup() 362 { 363 clear(); 364 refresh(); 365 touchwin(stw); 366 wrefresh(stw); 367 touchwin(tv); 368 wrefresh(tv); 369 alarm(1); 370 } 371