xref: /386bsd/usr/src/games/worms/worms.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[] = "@(#)worms.c	5.9 (Berkeley) 2/28/91";
42 #endif /* not lint */
43 
44 /*
45  *
46  *	 @@@        @@@    @@@@@@@@@@     @@@@@@@@@@@    @@@@@@@@@@@@
47  *	 @@@        @@@   @@@@@@@@@@@@    @@@@@@@@@@@@   @@@@@@@@@@@@@
48  *	 @@@        @@@  @@@@      @@@@   @@@@           @@@@ @@@  @@@@
49  *	 @@@   @@   @@@  @@@        @@@   @@@            @@@  @@@   @@@
50  *	 @@@  @@@@  @@@  @@@        @@@   @@@            @@@  @@@   @@@
51  *	 @@@@ @@@@ @@@@  @@@        @@@   @@@            @@@  @@@   @@@
52  *	  @@@@@@@@@@@@   @@@@      @@@@   @@@            @@@  @@@   @@@
53  *	   @@@@  @@@@     @@@@@@@@@@@@    @@@            @@@  @@@   @@@
54  *	    @@    @@       @@@@@@@@@@     @@@            @@@  @@@   @@@
55  *
56  *				 Eric P. Scott
57  *			  Caltech High Energy Physics
58  *				 October, 1980
59  *
60  */
61 #include <sys/types.h>
62 #include <stdio.h>
63 #ifdef USG
64 #include <termio.h>
65 #else
66 #include <sgtty.h>
67 #endif
68 #include <signal.h>
69 
70 static struct options {
71 	int nopts;
72 	int opts[3];
73 }
74 	normal[8] = {
75 	{ 3, { 7, 0, 1 } },
76 	{ 3, { 0, 1, 2 } },
77 	{ 3, { 1, 2, 3 } },
78 	{ 3, { 2, 3, 4 } },
79 	{ 3, { 3, 4, 5 } },
80 	{ 3, { 4, 5, 6 } },
81 	{ 3, { 5, 6, 7 } },
82 	{ 3, { 6, 7, 0 } }
83 },	upper[8] = {
84 	{ 1, { 1, 0, 0 } },
85 	{ 2, { 1, 2, 0 } },
86 	{ 0, { 0, 0, 0 } },
87 	{ 0, { 0, 0, 0 } },
88 	{ 0, { 0, 0, 0 } },
89 	{ 2, { 4, 5, 0 } },
90 	{ 1, { 5, 0, 0 } },
91 	{ 2, { 1, 5, 0 } }
92 },
93 	left[8] = {
94 	{ 0, { 0, 0, 0 } },
95 	{ 0, { 0, 0, 0 } },
96 	{ 0, { 0, 0, 0 } },
97 	{ 2, { 2, 3, 0 } },
98 	{ 1, { 3, 0, 0 } },
99 	{ 2, { 3, 7, 0 } },
100 	{ 1, { 7, 0, 0 } },
101 	{ 2, { 7, 0, 0 } }
102 },
103 	right[8] = {
104 	{ 1, { 7, 0, 0 } },
105 	{ 2, { 3, 7, 0 } },
106 	{ 1, { 3, 0, 0 } },
107 	{ 2, { 3, 4, 0 } },
108 	{ 0, { 0, 0, 0 } },
109 	{ 0, { 0, 0, 0 } },
110 	{ 0, { 0, 0, 0 } },
111 	{ 2, { 6, 7, 0 } }
112 },
113 	lower[8] = {
114 	{ 0, { 0, 0, 0 } },
115 	{ 2, { 0, 1, 0 } },
116 	{ 1, { 1, 0, 0 } },
117 	{ 2, { 1, 5, 0 } },
118 	{ 1, { 5, 0, 0 } },
119 	{ 2, { 5, 6, 0 } },
120 	{ 0, { 0, 0, 0 } },
121 	{ 0, { 0, 0, 0 } }
122 },
123 	upleft[8] = {
124 	{ 0, { 0, 0, 0 } },
125 	{ 0, { 0, 0, 0 } },
126 	{ 0, { 0, 0, 0 } },
127 	{ 0, { 0, 0, 0 } },
128 	{ 0, { 0, 0, 0 } },
129 	{ 1, { 3, 0, 0 } },
130 	{ 2, { 1, 3, 0 } },
131 	{ 1, { 1, 0, 0 } }
132 },
133 	upright[8] = {
134 	{ 2, { 3, 5, 0 } },
135 	{ 1, { 3, 0, 0 } },
136 	{ 0, { 0, 0, 0 } },
137 	{ 0, { 0, 0, 0 } },
138 	{ 0, { 0, 0, 0 } },
139 	{ 0, { 0, 0, 0 } },
140 	{ 0, { 0, 0, 0 } },
141 	{ 1, { 5, 0, 0 } }
142 },
143 	lowleft[8] = {
144 	{ 3, { 7, 0, 1 } },
145 	{ 0, { 0, 0, 0 } },
146 	{ 0, { 0, 0, 0 } },
147 	{ 1, { 1, 0, 0 } },
148 	{ 2, { 1, 7, 0 } },
149 	{ 1, { 7, 0, 0 } },
150 	{ 0, { 0, 0, 0 } },
151 	{ 0, { 0, 0, 0 } }
152 },
153 	lowright[8] = {
154 	{ 0, { 0, 0, 0 } },
155 	{ 1, { 7, 0, 0 } },
156 	{ 2, { 5, 7, 0 } },
157 	{ 1, { 5, 0, 0 } },
158 	{ 0, { 0, 0, 0 } },
159 	{ 0, { 0, 0, 0 } },
160 	{ 0, { 0, 0, 0 } },
161 	{ 0, { 0, 0, 0 } }
162 };
163 
164 #define	cursor(c, r)	tputs(tgoto(CM, c, r), 1, fputchar)
165 
166 char *tcp;
167 int fputchar();
168 
169 static char	flavor[] = {
170 	'O', '*', '#', '$', '%', '0', '@', '~'
171 };
172 static short	xinc[] = {
173 	1,  1,  1,  0, -1, -1, -1,  0
174 }, yinc[] = {
175 	-1,  0,  1,  1,  1,  0, -1, -1
176 };
177 static struct	worm {
178 	int orientation, head;
179 	short *xpos, *ypos;
180 } *worm;
181 
main(argc,argv)182 main(argc, argv)
183 	int argc;
184 	char **argv;
185 {
186 	extern int optind;
187 	extern short ospeed;
188 	extern char *optarg, *UP;
189 	register int x, y, h, n;
190 	register struct worm *w;
191 	register struct options *op;
192 	register short *ip;
193 	register char *term;
194 	int CO, IN, LI, last, bottom, ch, length, number, trail, Wrap;
195 	void onsig();
196 	short **ref;
197 	char *AL, *BC, *CM, *EI, *HO, *IC, *IM, *IP, *SR;
198 	char *field, tcb[100], *mp, *malloc(), *getenv(), *tgetstr(), *tgoto();
199 	long random();
200 #ifdef USG
201 	struct termio sg;
202 #else
203 	struct sgttyb sg;
204 #endif
205 
206 	length = 16;
207 	number = 3;
208 	trail = ' ';
209 	field = NULL;
210 	while ((ch = getopt(argc, argv, "fl:n:t")) != EOF)
211 		switch(ch) {
212 		case 'f':
213 			field = "WORM";
214 			break;
215 		case 'l':
216 			if ((length = atoi(optarg)) < 2 || length > 1024) {
217 				(void)fprintf(stderr,
218 				    "worms: invalid length (%d - %d).\n",
219 				     2, 1024);
220 				exit(1);
221 			}
222 			break;
223 		case 'n':
224 			if ((number = atoi(optarg)) < 1) {
225 				(void)fprintf(stderr,
226 				    "worms: invalid number of worms.\n");
227 				exit(1);
228 			}
229 			break;
230 		case 't':
231 			trail = '.';
232 			break;
233 		case '?':
234 		default:
235 			(void)fprintf(stderr,
236 			    "usage: worms [-ft] [-length #] [-number #]\n");
237 			exit(1);
238 		}
239 
240 	if (!(term = getenv("TERM"))) {
241 		(void)fprintf(stderr, "worms: no TERM environment variable.\n");
242 		exit(1);
243 	}
244 	if (!(worm = (struct worm *)malloc((u_int)number *
245 	    sizeof(struct worm))) || !(mp = malloc((u_int)1024)))
246 		nomem();
247 	if (tgetent(mp, term) <= 0) {
248 		(void)fprintf(stderr, "worms: %s: unknown terminal type.\n",
249 		    term);
250 		exit(1);
251 	}
252 	tcp = tcb;
253 	if (!(CM = tgetstr("cm", &tcp))) {
254 		(void)fprintf(stderr,
255 		    "worms: terminal incapable of cursor motion.\n");
256 		exit(1);
257 	}
258 	AL = tgetstr("al", &tcp);
259 	BC = tgetflag("bs") ? "\b" : tgetstr("bc", &tcp);
260 	if ((CO = tgetnum("co")) <= 0)
261 		CO = 80;
262 	last = CO - 1;
263 	EI = tgetstr("ei", &tcp);
264 	HO = tgetstr("ho", &tcp);
265 	IC = tgetstr("ic", &tcp);
266 	IM = tgetstr("im", &tcp);
267 	IN = tgetflag("in");
268 	IP = tgetstr("ip", &tcp);
269 	if ((LI = tgetnum("li")) <= 0)
270 		LI = 24;
271 	bottom = LI - 1;
272 	SR = tgetstr("sr", &tcp);
273 	UP = tgetstr("up", &tcp);
274 #ifdef USG
275 	ioctl(1, TCGETA, &sg);
276 	ospeed = sg.c_cflag&CBAUD;
277 #else
278 	gtty(1, &sg);
279 	ospeed = sg.sg_ospeed;
280 #endif
281 	Wrap = tgetflag("am");
282 	if (!(ip = (short *)malloc((u_int)(LI * CO * sizeof(short)))))
283 		nomem();
284 	if (!(ref = (short **)malloc((u_int)(LI * sizeof(short *)))))
285 		nomem();
286 	for (n = 0; n < LI; ++n) {
287 		ref[n] = ip;
288 		ip += CO;
289 	}
290 	for (ip = ref[0], n = LI * CO; --n >= 0;)
291 		*ip++ = 0;
292 	if (Wrap)
293 		ref[bottom][last] = 1;
294 	for (n = number, w = &worm[0]; --n >= 0; w++) {
295 		w->orientation = w->head = 0;
296 		if (!(ip = (short *)malloc((u_int)(length * sizeof(short)))))
297 			nomem();
298 		w->xpos = ip;
299 		for (x = length; --x >= 0;)
300 			*ip++ = -1;
301 		if (!(ip = (short *)malloc((u_int)(length * sizeof(short)))))
302 			nomem();
303 		w->ypos = ip;
304 		for (y = length; --y >= 0;)
305 			*ip++ = -1;
306 	}
307 
308 	(void)signal(SIGHUP, onsig);
309 	(void)signal(SIGINT, onsig);
310 	(void)signal(SIGQUIT, onsig);
311 	(void)signal(SIGSTOP, onsig);
312 	(void)signal(SIGTSTP, onsig);
313 	(void)signal(SIGTERM, onsig);
314 
315 	tputs(tgetstr("ti", &tcp), 1, fputchar);
316 	tputs(tgetstr("cl", &tcp), 1, fputchar);
317 	if (field) {
318 		register char *p = field;
319 
320 		for (y = bottom; --y >= 0;) {
321 			for (x = CO; --x >= 0;) {
322 				fputchar(*p++);
323 				if (!*p)
324 					p = field;
325 			}
326 			if (!Wrap)
327 				fputchar('\n');
328 			(void)fflush(stdout);
329 		}
330 		if (Wrap) {
331 			if (IM && !IN) {
332 				for (x = last; --x > 0;) {
333 					fputchar(*p++);
334 					if (!*p)
335 						p = field;
336 				}
337 				y = *p++;
338 				if (!*p)
339 					p = field;
340 				fputchar(*p);
341 				if (BC)
342 					tputs(BC, 1, fputchar);
343 				else
344 					cursor(last - 1, bottom);
345 				tputs(IM, 1, fputchar);
346 				if (IC)
347 					tputs(IC, 1, fputchar);
348 				fputchar(y);
349 				if (IP)
350 					tputs(IP, 1, fputchar);
351 				tputs(EI, 1, fputchar);
352 			}
353 			else if (SR || AL) {
354 				if (HO)
355 					tputs(HO, 1, fputchar);
356 				else
357 					cursor(0, 0);
358 				if (SR)
359 					tputs(SR, 1, fputchar);
360 				else
361 					tputs(AL, LI, fputchar);
362 				for (x = CO; --x >= 0;) {
363 					fputchar(*p++);
364 					if (!*p)
365 						p = field;
366 				}
367 			}
368 			else for (x = last; --x >= 0;) {
369 				fputchar(*p++);
370 				if (!*p)
371 					p = field;
372 			}
373 		}
374 		else for (x = CO; --x >= 0;) {
375 			fputchar(*p++);
376 			if (!*p)
377 				p = field;
378 		}
379 	}
380 	for (;;) {
381 		(void)fflush(stdout);
382 		for (n = 0, w = &worm[0]; n < number; n++, w++) {
383 			if ((x = w->xpos[h = w->head]) < 0) {
384 				cursor(x = w->xpos[h] = 0,
385 				     y = w->ypos[h] = bottom);
386 				fputchar(flavor[n % sizeof(flavor)]);
387 				ref[y][x]++;
388 			}
389 			else
390 				y = w->ypos[h];
391 			if (++h == length)
392 				h = 0;
393 			if (w->xpos[w->head = h] >= 0) {
394 				register int x1, y1;
395 
396 				x1 = w->xpos[h];
397 				y1 = w->ypos[h];
398 				if (--ref[y1][x1] == 0) {
399 					cursor(x1, y1);
400 					if (trail)
401 						fputchar(trail);
402 				}
403 			}
404 			op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation];
405 			switch (op->nopts) {
406 			case 0:
407 				(void)fflush(stdout);
408 				abort();
409 				return;
410 			case 1:
411 				w->orientation = op->opts[0];
412 				break;
413 			default:
414 				w->orientation =
415 				    op->opts[(int)random() % op->nopts];
416 			}
417 			cursor(x += xinc[w->orientation],
418 			    y += yinc[w->orientation]);
419 			if (!Wrap || x != last || y != bottom)
420 				fputchar(flavor[n % sizeof(flavor)]);
421 			ref[w->ypos[h] = y][w->xpos[h] = x]++;
422 		}
423 	}
424 }
425 
426 void
onsig()427 onsig()
428 {
429 	tputs(tgetstr("cl", &tcp), 1, fputchar);
430 	tputs(tgetstr("te", &tcp), 1, fputchar);
431 	exit(0);
432 }
433 
fputchar(c)434 fputchar(c)
435 	char c;
436 {
437 	putchar(c);
438 }
439 
nomem()440 nomem()
441 {
442 	(void)fprintf(stderr, "worms: not enough memory.\n");
443 	exit(1);
444 }
445