1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
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
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.25 2004/01/27 20:30:31 jsm Exp $");
43: #endif
44: #endif
45:
46:
47:
48:
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) __attribute__((__noreturn__));
84: void display(const struct body *, char);
85: int main(int, char **);
86: void leave(int) __attribute__((__noreturn__));
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:
102: setregid(getgid(), 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:
120:
121:
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();
141: prize();
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){
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 __attribute__((__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: }