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