1 /* $NetBSD: worm.c,v 1.30 2011/05/23 23:03:38 joerg 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.30 2011/05/23 23:03:38 joerg 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(int argc, 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 if (!initscr()) 110 errx(0, "couldn't initialize screen"); 111 cbreak(); 112 noecho(); 113 #ifdef KEY_LEFT 114 keypad(stdscr, TRUE); 115 #endif 116 slow = (baudrate() <= 1200); 117 clear(); 118 if (COLS < 18 || LINES < 5) { 119 /* 120 * Insufficient room for the line with " Worm" and the 121 * score if fewer than 18 columns; insufficient room for 122 * anything much if fewer than 5 lines. 123 */ 124 endwin(); 125 errx(1, "screen too small"); 126 } 127 if (argc == 2) 128 start_len = atoi(argv[1]); 129 if ((start_len <= 0) || (start_len > ((LINES-3) * (COLS-2)) / 3)) 130 start_len = LENGTH; 131 stw = newwin(1, COLS-1, 0, 0); 132 tv = newwin(LINES-1, COLS-1, 1, 0); 133 box(tv, '*', '*'); 134 scrollok(tv, FALSE); 135 scrollok(stw, FALSE); 136 wmove(stw, 0, 0); 137 wprintw(stw, " Worm"); 138 refresh(); 139 wrefresh(stw); 140 wrefresh(tv); 141 life(); /* Create the worm */ 142 prize(); /* Put up a goal */ 143 while(1) 144 { 145 if (running) 146 { 147 running--; 148 process(lastch); 149 } 150 else 151 { 152 fflush(stdout); 153 process(getch()); 154 } 155 } 156 } 157 158 static void 159 life(void) 160 { 161 struct body *bp, *np; 162 int i, j = 1; 163 164 np = NULL; 165 head = newlink(); 166 if (head == NULL) 167 err(1, NULL); 168 head->x = start_len % (COLS-5) + 2; 169 head->y = LINES / 2; 170 head->next = NULL; 171 display(head, HEAD); 172 for (i = 0, bp = head; i < start_len; i++, bp = np) { 173 np = newlink(); 174 if (np == NULL) 175 err(1, NULL); 176 np->next = bp; 177 bp->prev = np; 178 if (((bp->x <= 2) && (j == 1)) || ((bp->x >= COLS-4) && (j == -1))) { 179 j *= -1; 180 np->x = bp->x; 181 np->y = bp->y + 1; 182 } else { 183 np->x = bp->x - j; 184 np->y = bp->y; 185 } 186 display(np, BODY); 187 } 188 tail = np; 189 tail->prev = NULL; 190 visible_len = start_len + 1; 191 } 192 193 static void 194 display(const struct body *pos, char chr) 195 { 196 wmove(tv, pos->y, pos->x); 197 waddch(tv, chr); 198 } 199 200 static void 201 leave(int dummy) 202 { 203 endwin(); 204 205 if (dummy == 0){ /* called via crash() */ 206 printf("\nWell, you ran into something and the game is over.\n"); 207 printf("Your final score was %d\n\n", score); 208 } 209 exit(0); 210 } 211 212 static void 213 wake(int dummy) 214 { 215 signal(SIGALRM, wake); 216 fflush(stdout); 217 process(lastch); 218 } 219 220 static int 221 rnd(int range) 222 { 223 return abs((rand()>>5)+(rand()>>5)) % range; 224 } 225 226 static void 227 newpos(struct body *bp) 228 { 229 if (visible_len == (LINES-3) * (COLS-3) - 1) { 230 endwin(); 231 232 printf("\nYou won!\n"); 233 printf("Your final score was %d\n\n", score); 234 exit(0); 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 static void 244 prize(void) 245 { 246 int value; 247 248 value = rnd(9) + 1; 249 newpos(&goody); 250 waddch(tv, value+'0'); 251 wrefresh(tv); 252 } 253 254 static void 255 process(int ch) 256 { 257 int x,y; 258 struct body *nh; 259 260 alarm(0); 261 x = head->x; 262 y = head->y; 263 switch(ch) 264 { 265 #ifdef KEY_LEFT 266 case KEY_LEFT: 267 #endif 268 case 'h': 269 x--; break; 270 271 #ifdef KEY_DOWN 272 case KEY_DOWN: 273 #endif 274 case 'j': 275 y++; break; 276 277 #ifdef KEY_UP 278 case KEY_UP: 279 #endif 280 case 'k': 281 y--; break; 282 283 #ifdef KEY_RIGHT 284 case KEY_RIGHT: 285 #endif 286 case 'l': 287 x++; break; 288 289 case 'H': x--; running = RUNLEN; ch = tolower(ch); break; 290 case 'J': y++; running = RUNLEN/2; ch = tolower(ch); break; 291 case 'K': y--; running = RUNLEN/2; ch = tolower(ch); break; 292 case 'L': x++; running = RUNLEN; ch = tolower(ch); break; 293 case '\f': setup(); return; 294 295 case ERR: 296 case CNTRL('C'): 297 case CNTRL('D'): 298 crash(); 299 return; 300 301 default: if (! running) alarm(1); 302 return; 303 } 304 lastch = ch; 305 if (growing == 0) 306 { 307 display(tail, ' '); 308 tail->next->prev = NULL; 309 nh = tail->next; 310 free(tail); 311 tail = nh; 312 visible_len--; 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 visible_len++; 339 if (!(slow && running)) 340 { 341 wmove(tv, head->y, head->x); 342 wrefresh(tv); 343 } 344 if (!running) 345 alarm(1); 346 } 347 348 static void 349 crash(void) 350 { 351 leave(0); 352 } 353 354 static void 355 setup(void) 356 { 357 clear(); 358 refresh(); 359 touchwin(stw); 360 wrefresh(stw); 361 touchwin(tv); 362 wrefresh(tv); 363 alarm(1); 364 } 365