xref: /original-bsd/games/worm/worm.c (revision 33586e34)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)worm.c	5.6 (Berkeley) 08/02/89";
26 #endif /* not lint */
27 
28 /*
29  * Worm.  Written by Michael Toy
30  * UCSC
31  */
32 
33 #include <ctype.h>
34 #include <curses.h>
35 #include <signal.h>
36 
37 #define newlink() (struct body *) malloc(sizeof (struct body));
38 #define HEAD '@'
39 #define BODY 'o'
40 #define LENGTH 7
41 #define RUNLEN 8
42 #define when break;case
43 #define otherwise break;default
44 #define CNTRL(p) (p-'A'+1)
45 #ifndef baudrate
46 # define	baudrate()	_tty.sg_ospeed
47 #endif
48 
49 WINDOW *tv;
50 WINDOW *stw;
51 struct body {
52 	int x;
53 	int y;
54 	struct body *prev;
55 	struct body *next;
56 } *head, *tail, goody;
57 int growing = 0;
58 int running = 0;
59 int slow = 0;
60 int score = 0;
61 int start_len = LENGTH;
62 char lastch;
63 char outbuf[BUFSIZ];
64 
65 main(argc, argv)
66 char **argv;
67 {
68 	int leave(), wake(), suspend();
69 	char ch;
70 
71 	if (argc == 2)
72 		start_len = atoi(argv[1]);
73 	if ((start_len <= 0) || (start_len > 500))
74 		start_len = LENGTH;
75 	setbuf(stdout, outbuf);
76 	srand(getpid());
77 	signal(SIGALRM, wake);
78 	signal(SIGINT, leave);
79 	signal(SIGQUIT, leave);
80 	signal(SIGTSTP, suspend);	/* process control signal */
81 	initscr();
82 	crmode();
83 	noecho();
84 	slow = (baudrate() <= B1200);
85 	clear();
86 	stw = newwin(1, COLS-1, 0, 0);
87 	tv = newwin(LINES-1, COLS-1, 1, 0);
88 	box(tv, '*', '*');
89 	scrollok(tv, FALSE);
90 	scrollok(stw, FALSE);
91 	wmove(stw, 0, 0);
92 	wprintw(stw, " Worm");
93 	refresh();
94 	wrefresh(stw);
95 	wrefresh(tv);
96 	life();			/* Create the worm */
97 	prize();		/* Put up a goal */
98 	while(1)
99 	{
100 		if (running)
101 		{
102 			running--;
103 			process(lastch);
104 		}
105 		else
106 		{
107 		    fflush(stdout);
108 		    if (read(0, &ch, 1) >= 0)
109 			process(ch);
110 		}
111 	}
112 }
113 
114 life()
115 {
116 	register struct body *bp, *np;
117 	register int i;
118 
119 	head = newlink();
120 	head->x = start_len+2;
121 	head->y = 12;
122 	head->next = NULL;
123 	display(head, HEAD);
124 	for (i = 0, bp = head; i < start_len; i++, bp = np) {
125 		np = newlink();
126 		np->next = bp;
127 		bp->prev = np;
128 		np->x = bp->x - 1;
129 		np->y = bp->y;
130 		display(np, BODY);
131 	}
132 	tail = np;
133 	tail->prev = NULL;
134 }
135 
136 display(pos, chr)
137 struct body *pos;
138 char chr;
139 {
140 	wmove(tv, pos->y, pos->x);
141 	waddch(tv, chr);
142 }
143 
144 leave()
145 {
146 	endwin();
147 	exit(0);
148 }
149 
150 wake()
151 {
152 	signal(SIGALRM, wake);
153 	fflush(stdout);
154 	process(lastch);
155 }
156 
157 rnd(range)
158 {
159 	return abs((rand()>>5)+(rand()>>5)) % range;
160 }
161 
162 newpos(bp)
163 struct body * bp;
164 {
165 	do {
166 		bp->y = rnd(LINES-3)+ 2;
167 		bp->x = rnd(COLS-3) + 1;
168 		wmove(tv, bp->y, bp->x);
169 	} while(winch(tv) != ' ');
170 }
171 
172 prize()
173 {
174 	int value;
175 
176 	value = rnd(9) + 1;
177 	newpos(&goody);
178 	waddch(tv, value+'0');
179 	wrefresh(tv);
180 }
181 
182 process(ch)
183 char ch;
184 {
185 	register int x,y;
186 	struct body *nh;
187 
188 	alarm(0);
189 	x = head->x;
190 	y = head->y;
191 	switch(ch)
192 	{
193 		when 'h': x--;
194 		when 'j': y++;
195 		when 'k': y--;
196 		when 'l': x++;
197 		when 'H': x--; running = RUNLEN; ch = tolower(ch);
198 		when 'J': y++; running = RUNLEN/2; ch = tolower(ch);
199 		when 'K': y--; running = RUNLEN/2; ch = tolower(ch);
200 		when 'L': x++; running = RUNLEN; ch = tolower(ch);
201 		when '\f': setup(); return;
202 		when CNTRL('Z'): suspend(); return;
203 		when CNTRL('C'): crash(); return;
204 		when CNTRL('D'): crash(); return;
205 		otherwise: if (! running) alarm(1);
206 			   return;
207 	}
208 	lastch = ch;
209 	if (growing == 0)
210 	{
211 		display(tail, ' ');
212 		tail->next->prev = NULL;
213 		nh = tail->next;
214 		free(tail);
215 		tail = nh;
216 	}
217 	else growing--;
218 	display(head, BODY);
219 	wmove(tv, y, x);
220 	if (isdigit(ch = winch(tv)))
221 	{
222 		growing += ch-'0';
223 		prize();
224 		score += growing;
225 		running = 0;
226 		wmove(stw, 0, 68);
227 		wprintw(stw, "Score: %3d", score);
228 		wrefresh(stw);
229 	}
230 	else if(ch != ' ') crash();
231 	nh = newlink();
232 	nh->next = NULL;
233 	nh->prev = head;
234 	head->next = nh;
235 	nh->y = y;
236 	nh->x = x;
237 	display(nh, HEAD);
238 	head = nh;
239 	if (!(slow && running))
240 		wrefresh(tv);
241 	if (!running)
242 		alarm(1);
243 }
244 
245 crash()
246 {
247 	sleep(2);
248 	clear();
249 	move(23, 0);
250 	refresh();
251 	printf("Well, you ran into something and the game is over.\n");
252 	printf("Your final score was %d\n", score);
253 	leave();
254 }
255 
256 suspend()
257 {
258 	char *sh;
259 
260 	move(LINES-1, 0);
261 	refresh();
262 	endwin();
263 	fflush(stdout);
264 	kill(getpid(), SIGTSTP);
265 	signal(SIGTSTP, suspend);
266 	crmode();
267 	noecho();
268 	setup();
269 }
270 
271 setup()
272 {
273 	clear();
274 	refresh();
275 	touchwin(stw);
276 	wrefresh(stw);
277 	touchwin(tv);
278 	wrefresh(tv);
279 	alarm(1);
280 }
281