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