xref: /csrg-svn/games/worms/worms.c (revision 38561)
133200Sbostic /*
233200Sbostic  * Copyright (c) 1980 Regents of the University of California.
333200Sbostic  * All rights reserved.
433200Sbostic  *
533200Sbostic  * Redistribution and use in source and binary forms are permitted
634808Sbostic  * provided that the above copyright notice and this paragraph are
734808Sbostic  * duplicated in all such forms and that any documentation,
834808Sbostic  * advertising materials, and other materials related to such
934808Sbostic  * distribution and use acknowledge that the software was developed
1034808Sbostic  * by the University of California, Berkeley.  The name of the
1134808Sbostic  * University may not be used to endorse or promote products derived
1234808Sbostic  * from this software without specific prior written permission.
1334808Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434808Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534808Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633200Sbostic  */
1733200Sbostic 
1821202Sdist #ifndef lint
1921202Sdist char copyright[] =
2021202Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\
2121202Sdist  All rights reserved.\n";
2233200Sbostic #endif /* not lint */
238873Smckusick 
2421202Sdist #ifndef lint
25*38561Sbostic static char sccsid[] = "@(#)worms.c	5.7 (Berkeley) 08/02/89";
2633200Sbostic #endif /* not lint */
2721202Sdist 
288873Smckusick /*
2933200Sbostic  *
3033200Sbostic  *	 @@@        @@@    @@@@@@@@@@     @@@@@@@@@@@    @@@@@@@@@@@@
3133200Sbostic  *	 @@@        @@@   @@@@@@@@@@@@    @@@@@@@@@@@@   @@@@@@@@@@@@@
3233200Sbostic  *	 @@@        @@@  @@@@      @@@@   @@@@           @@@@ @@@  @@@@
3333200Sbostic  *	 @@@   @@   @@@  @@@        @@@   @@@            @@@  @@@   @@@
3433200Sbostic  *	 @@@  @@@@  @@@  @@@        @@@   @@@            @@@  @@@   @@@
3533200Sbostic  *	 @@@@ @@@@ @@@@  @@@        @@@   @@@            @@@  @@@   @@@
3633200Sbostic  *	  @@@@@@@@@@@@   @@@@      @@@@   @@@            @@@  @@@   @@@
3733200Sbostic  *	   @@@@  @@@@     @@@@@@@@@@@@    @@@            @@@  @@@   @@@
3833200Sbostic  *	    @@    @@       @@@@@@@@@@     @@@            @@@  @@@   @@@
3933200Sbostic  *
4033200Sbostic  *				 Eric P. Scott
4133200Sbostic  *			  Caltech High Energy Physics
4233200Sbostic  *				 October, 1980
4333200Sbostic  *
4433200Sbostic  */
4533200Sbostic #include <sys/types.h>
468873Smckusick #include <stdio.h>
4723869Smckusick #ifdef USG
4823869Smckusick #include <termio.h>
4923869Smckusick #else
508873Smckusick #include <sgtty.h>
5123869Smckusick #endif
5223869Smckusick #include <signal.h>
5333200Sbostic 
5433200Sbostic static struct options {
5533200Sbostic 	int nopts;
5633200Sbostic 	int opts[3];
5733200Sbostic }
5833200Sbostic 	normal[8] = {
5933200Sbostic 	{ 3, { 7, 0, 1 } },
6033200Sbostic 	{ 3, { 0, 1, 2 } },
6133200Sbostic 	{ 3, { 1, 2, 3 } },
6233200Sbostic 	{ 3, { 2, 3, 4 } },
6333200Sbostic 	{ 3, { 3, 4, 5 } },
6433200Sbostic 	{ 3, { 4, 5, 6 } },
6533200Sbostic 	{ 3, { 5, 6, 7 } },
6633200Sbostic 	{ 3, { 6, 7, 0 } }
6733200Sbostic },	upper[8] = {
6833200Sbostic 	{ 1, { 1, 0, 0 } },
6933200Sbostic 	{ 2, { 1, 2, 0 } },
7033200Sbostic 	{ 0, { 0, 0, 0 } },
7133200Sbostic 	{ 0, { 0, 0, 0 } },
7233200Sbostic 	{ 0, { 0, 0, 0 } },
7333200Sbostic 	{ 2, { 4, 5, 0 } },
7433200Sbostic 	{ 1, { 5, 0, 0 } },
7533200Sbostic 	{ 2, { 1, 5, 0 } }
7633200Sbostic },
7733200Sbostic 	left[8] = {
7833200Sbostic 	{ 0, { 0, 0, 0 } },
7933200Sbostic 	{ 0, { 0, 0, 0 } },
8033200Sbostic 	{ 0, { 0, 0, 0 } },
8133200Sbostic 	{ 2, { 2, 3, 0 } },
8233200Sbostic 	{ 1, { 3, 0, 0 } },
8333200Sbostic 	{ 2, { 3, 7, 0 } },
8433200Sbostic 	{ 1, { 7, 0, 0 } },
8533200Sbostic 	{ 2, { 7, 0, 0 } }
8633200Sbostic },
8733200Sbostic 	right[8] = {
8833200Sbostic 	{ 1, { 7, 0, 0 } },
8933200Sbostic 	{ 2, { 3, 7, 0 } },
9033200Sbostic 	{ 1, { 3, 0, 0 } },
9133200Sbostic 	{ 2, { 3, 4, 0 } },
9233200Sbostic 	{ 0, { 0, 0, 0 } },
9333200Sbostic 	{ 0, { 0, 0, 0 } },
9433200Sbostic 	{ 0, { 0, 0, 0 } },
9533200Sbostic 	{ 2, { 6, 7, 0 } }
9633200Sbostic },
9733200Sbostic 	lower[8] = {
9833200Sbostic 	{ 0, { 0, 0, 0 } },
9933200Sbostic 	{ 2, { 0, 1, 0 } },
10033200Sbostic 	{ 1, { 1, 0, 0 } },
10133200Sbostic 	{ 2, { 1, 5, 0 } },
10233200Sbostic 	{ 1, { 5, 0, 0 } },
10333200Sbostic 	{ 2, { 5, 6, 0 } },
10433200Sbostic 	{ 0, { 0, 0, 0 } },
10533200Sbostic 	{ 0, { 0, 0, 0 } }
10633200Sbostic },
10733200Sbostic 	upleft[8] = {
10833200Sbostic 	{ 0, { 0, 0, 0 } },
10933200Sbostic 	{ 0, { 0, 0, 0 } },
11033200Sbostic 	{ 0, { 0, 0, 0 } },
11133200Sbostic 	{ 0, { 0, 0, 0 } },
11233200Sbostic 	{ 0, { 0, 0, 0 } },
11333200Sbostic 	{ 1, { 3, 0, 0 } },
11433200Sbostic 	{ 2, { 1, 3, 0 } },
11533200Sbostic 	{ 1, { 1, 0, 0 } }
11633200Sbostic },
11733200Sbostic 	upright[8] = {
11833200Sbostic 	{ 2, { 3, 5, 0 } },
11933200Sbostic 	{ 1, { 3, 0, 0 } },
12033200Sbostic 	{ 0, { 0, 0, 0 } },
12133200Sbostic 	{ 0, { 0, 0, 0 } },
12233200Sbostic 	{ 0, { 0, 0, 0 } },
12333200Sbostic 	{ 0, { 0, 0, 0 } },
12433200Sbostic 	{ 0, { 0, 0, 0 } },
12533200Sbostic 	{ 1, { 5, 0, 0 } }
12633200Sbostic },
12733200Sbostic 	lowleft[8] = {
12833200Sbostic 	{ 3, { 7, 0, 1 } },
12933200Sbostic 	{ 0, { 0, 0, 0 } },
13033200Sbostic 	{ 0, { 0, 0, 0 } },
13133200Sbostic 	{ 1, { 1, 0, 0 } },
13233200Sbostic 	{ 2, { 1, 7, 0 } },
13333200Sbostic 	{ 1, { 7, 0, 0 } },
13433200Sbostic 	{ 0, { 0, 0, 0 } },
13533200Sbostic 	{ 0, { 0, 0, 0 } }
13633200Sbostic },
13733200Sbostic 	lowright[8] = {
13833200Sbostic 	{ 0, { 0, 0, 0 } },
13933200Sbostic 	{ 1, { 7, 0, 0 } },
14033200Sbostic 	{ 2, { 5, 7, 0 } },
14133200Sbostic 	{ 1, { 5, 0, 0 } },
14233200Sbostic 	{ 0, { 0, 0, 0 } },
14333200Sbostic 	{ 0, { 0, 0, 0 } },
14433200Sbostic 	{ 0, { 0, 0, 0 } },
14533200Sbostic 	{ 0, { 0, 0, 0 } }
1468873Smckusick };
14733200Sbostic 
14833200Sbostic #define	cursor(c, r)	tputs(tgoto(CM, c, r), 1, fputchar)
14933200Sbostic 
150*38561Sbostic char *tcp;
151*38561Sbostic int fputchar();
15233200Sbostic 
15333200Sbostic static char	flavor[] = {
15438560Sbostic 	'O', '*', '#', '$', '%', '0', '@', '~'
1558873Smckusick };
15633200Sbostic static short	xinc[] = {
15733200Sbostic 	1,  1,  1,  0, -1, -1, -1,  0
15833200Sbostic }, yinc[] = {
15933200Sbostic 	-1,  0,  1,  1,  1,  0, -1, -1
16033200Sbostic };
16133200Sbostic static struct	worm {
16233200Sbostic 	int orientation, head;
16333200Sbostic 	short *xpos, *ypos;
16438560Sbostic } *worm;
16533200Sbostic 
16633200Sbostic main(argc, argv)
16733200Sbostic 	int argc;
16833200Sbostic 	char **argv;
1698873Smckusick {
17033200Sbostic 	extern int optind;
17133200Sbostic 	extern short ospeed;
17233200Sbostic 	extern char *optarg, *UP;
17333200Sbostic 	register int x, y, h, n;
17433200Sbostic 	register struct worm *w;
17533200Sbostic 	register struct options *op;
17633200Sbostic 	register short *ip;
17733200Sbostic 	register char *term;
17838560Sbostic 	int CO, IN, LI, last, bottom, ch, length, number, trail, Wrap;
17938560Sbostic 	int onsig();
18033200Sbostic 	short **ref;
181*38561Sbostic 	char *AL, *BC, *CM, *EI, *HO, *IC, *IM, *IP, *SR;
18238560Sbostic 	char *field, tcb[100], *mp, *malloc(), *getenv(), *tgetstr(), *tgoto();
18333200Sbostic 	long random();
18423869Smckusick #ifdef USG
18533200Sbostic 	struct termio sg;
18623869Smckusick #else
18733200Sbostic 	struct sgttyb sg;
18823869Smckusick #endif
18933200Sbostic 
19033200Sbostic 	length = 16;
19133200Sbostic 	number = 3;
19233200Sbostic 	trail = ' ';
19333200Sbostic 	field = NULL;
19433200Sbostic 	while ((ch = getopt(argc, argv, "fl:n:t")) != EOF)
19538560Sbostic 		switch(ch) {
19633200Sbostic 		case 'f':
19733200Sbostic 			field = "WORM";
19833200Sbostic 			break;
19933200Sbostic 		case 'l':
20033200Sbostic 			if ((length = atoi(optarg)) < 2 || length > 1024) {
20138560Sbostic 				(void)fprintf(stderr,
20238560Sbostic 				    "worms: invalid length (%d - %d).\n",
20338560Sbostic 				     2, 1024);
20433200Sbostic 				exit(1);
20533200Sbostic 			}
20633200Sbostic 			break;
20733200Sbostic 		case 'n':
20838560Sbostic 			if ((number = atoi(optarg)) < 1) {
20938560Sbostic 				(void)fprintf(stderr,
21038560Sbostic 				    "worms: invalid number of worms.\n");
21133200Sbostic 				exit(1);
21233200Sbostic 			}
21333200Sbostic 			break;
21433200Sbostic 		case 't':
21533200Sbostic 			trail = '.';
21633200Sbostic 			break;
21733200Sbostic 		case '?':
21833200Sbostic 		default:
21938560Sbostic 			(void)fprintf(stderr,
22038560Sbostic 			    "usage: worms [-ft] [-length #] [-number #]\n");
22133200Sbostic 			exit(1);
22233200Sbostic 		}
22333200Sbostic 
22433200Sbostic 	if (!(term = getenv("TERM"))) {
22538560Sbostic 		(void)fprintf(stderr, "worms: no TERM environment variable.\n");
2268873Smckusick 		exit(1);
22733200Sbostic 	}
22838560Sbostic 	if (!(worm = (struct worm *)malloc((u_int)number *
22938560Sbostic 	    sizeof(struct worm))) || !(mp = malloc((u_int)1024)))
23038560Sbostic 		nomem();
23133200Sbostic 	if (tgetent(mp, term) <= 0) {
23238560Sbostic 		(void)fprintf(stderr, "worms: %s: unknown terminal type.\n",
23338560Sbostic 		    term);
23433200Sbostic 		exit(1);
23533200Sbostic 	}
23633200Sbostic 	tcp = tcb;
23733200Sbostic 	if (!(CM = tgetstr("cm", &tcp))) {
23838560Sbostic 		(void)fprintf(stderr,
23938560Sbostic 		    "worms: terminal incapable of cursor motion.\n");
24033200Sbostic 		exit(1);
24133200Sbostic 	}
24233200Sbostic 	AL = tgetstr("al", &tcp);
24333200Sbostic 	BC = tgetflag("bs") ? "\b" : tgetstr("bc", &tcp);
24433200Sbostic 	if ((CO = tgetnum("co")) <= 0)
24533200Sbostic 		CO = 80;
24633200Sbostic 	last = CO - 1;
24733200Sbostic 	EI = tgetstr("ei", &tcp);
24833200Sbostic 	HO = tgetstr("ho", &tcp);
24933200Sbostic 	IC = tgetstr("ic", &tcp);
25033200Sbostic 	IM = tgetstr("im", &tcp);
25133200Sbostic 	IN = tgetflag("in");
25233200Sbostic 	IP = tgetstr("ip", &tcp);
25333200Sbostic 	if ((LI = tgetnum("li")) <= 0)
25433200Sbostic 		LI = 24;
25533200Sbostic 	bottom = LI - 1;
25633200Sbostic 	SR = tgetstr("sr", &tcp);
25733200Sbostic 	UP = tgetstr("up", &tcp);
25823869Smckusick #ifdef USG
25933200Sbostic 	ioctl(1, TCGETA, &sg);
26033200Sbostic 	ospeed = sg.c_cflag&CBAUD;
26123869Smckusick #else
26233200Sbostic 	gtty(1, &sg);
26333200Sbostic 	ospeed = sg.sg_ospeed;
26423869Smckusick #endif
26533200Sbostic 	Wrap = tgetflag("am");
26638560Sbostic 	if (!(ip = (short *)malloc((u_int)(LI * CO * sizeof(short)))))
26738560Sbostic 		nomem();
26838560Sbostic 	if (!(ref = (short **)malloc((u_int)(LI * sizeof(short *)))))
26938560Sbostic 		nomem();
27033200Sbostic 	for (n = 0; n < LI; ++n) {
27133200Sbostic 		ref[n] = ip;
27233200Sbostic 		ip += CO;
27333200Sbostic 	}
27433200Sbostic 	for (ip = ref[0], n = LI * CO; --n >= 0;)
27533200Sbostic 		*ip++ = 0;
27633200Sbostic 	if (Wrap)
27733200Sbostic 		ref[bottom][last] = 1;
27833200Sbostic 	for (n = number, w = &worm[0]; --n >= 0; w++) {
27933200Sbostic 		w->orientation = w->head = 0;
28038560Sbostic 		if (!(ip = (short *)malloc((u_int)(length * sizeof(short)))))
28138560Sbostic 			nomem();
28233200Sbostic 		w->xpos = ip;
28333200Sbostic 		for (x = length; --x >= 0;)
28433200Sbostic 			*ip++ = -1;
28538560Sbostic 		if (!(ip = (short *)malloc((u_int)(length * sizeof(short)))))
28638560Sbostic 			nomem();
28733200Sbostic 		w->ypos = ip;
28833200Sbostic 		for (y = length; --y >= 0;)
28933200Sbostic 			*ip++ = -1;
2908873Smckusick 	}
29133200Sbostic 
29233200Sbostic 	(void)signal(SIGHUP, onsig);
29333200Sbostic 	(void)signal(SIGINT, onsig);
29433200Sbostic 	(void)signal(SIGQUIT, onsig);
29533200Sbostic 	(void)signal(SIGSTOP, onsig);
29633200Sbostic 	(void)signal(SIGTSTP, onsig);
29733200Sbostic 	(void)signal(SIGTERM, onsig);
29833200Sbostic 
29933200Sbostic 	tputs(tgetstr("ti", &tcp), 1, fputchar);
30033200Sbostic 	tputs(tgetstr("cl", &tcp), 1, fputchar);
30133200Sbostic 	if (field) {
30233200Sbostic 		register char *p = field;
30333200Sbostic 
30433200Sbostic 		for (y = bottom; --y >= 0;) {
30533200Sbostic 			for (x = CO; --x >= 0;) {
30633200Sbostic 				fputchar(*p++);
30733200Sbostic 				if (!*p)
30833200Sbostic 					p = field;
30933200Sbostic 			}
31033200Sbostic 			if (!Wrap)
31133200Sbostic 				fputchar('\n');
31233200Sbostic 			(void)fflush(stdout);
31333200Sbostic 		}
31433200Sbostic 		if (Wrap) {
31533200Sbostic 			if (IM && !IN) {
31633200Sbostic 				for (x = last; --x > 0;) {
31733200Sbostic 					fputchar(*p++);
31833200Sbostic 					if (!*p)
31933200Sbostic 						p = field;
32033200Sbostic 				}
32133200Sbostic 				y = *p++;
32233200Sbostic 				if (!*p)
32333200Sbostic 					p = field;
32433200Sbostic 				fputchar(*p);
32533200Sbostic 				if (BC)
32633200Sbostic 					tputs(BC, 1, fputchar);
32733200Sbostic 				else
32833200Sbostic 					cursor(last - 1, bottom);
32933200Sbostic 				tputs(IM, 1, fputchar);
33033200Sbostic 				if (IC)
33133200Sbostic 					tputs(IC, 1, fputchar);
33233200Sbostic 				fputchar(y);
33333200Sbostic 				if (IP)
33433200Sbostic 					tputs(IP, 1, fputchar);
33533200Sbostic 				tputs(EI, 1, fputchar);
33633200Sbostic 			}
33733200Sbostic 			else if (SR || AL) {
33833200Sbostic 				if (HO)
33933200Sbostic 					tputs(HO, 1, fputchar);
34033200Sbostic 				else
34133200Sbostic 					cursor(0, 0);
34233200Sbostic 				if (SR)
34333200Sbostic 					tputs(SR, 1, fputchar);
34433200Sbostic 				else
34533200Sbostic 					tputs(AL, LI, fputchar);
34633200Sbostic 				for (x = CO; --x >= 0;) {
34733200Sbostic 					fputchar(*p++);
34833200Sbostic 					if (!*p)
34933200Sbostic 						p = field;
35033200Sbostic 				}
35133200Sbostic 			}
35233200Sbostic 			else for (x = last; --x >= 0;) {
35333200Sbostic 				fputchar(*p++);
35433200Sbostic 				if (!*p)
35533200Sbostic 					p = field;
35633200Sbostic 			}
35733200Sbostic 		}
35833200Sbostic 		else for (x = CO; --x >= 0;) {
35933200Sbostic 			fputchar(*p++);
36033200Sbostic 			if (!*p)
36133200Sbostic 				p = field;
36233200Sbostic 		}
3638873Smckusick 	}
36433200Sbostic 	for (;;) {
36533200Sbostic 		(void)fflush(stdout);
36633200Sbostic 		for (n = 0, w = &worm[0]; n < number; n++, w++) {
36733200Sbostic 			if ((x = w->xpos[h = w->head]) < 0) {
36833200Sbostic 				cursor(x = w->xpos[h] = 0,
36933200Sbostic 				     y = w->ypos[h] = bottom);
370*38561Sbostic 				fputchar(flavor[n % sizeof(flavor)]);
37133200Sbostic 				ref[y][x]++;
37233200Sbostic 			}
37333200Sbostic 			else
37433200Sbostic 				y = w->ypos[h];
37533200Sbostic 			if (++h == length)
37633200Sbostic 				h = 0;
37733200Sbostic 			if (w->xpos[w->head = h] >= 0) {
37833200Sbostic 				register int x1, y1;
37933200Sbostic 
38033200Sbostic 				x1 = w->xpos[h];
38133200Sbostic 				y1 = w->ypos[h];
38233200Sbostic 				if (--ref[y1][x1] == 0) {
38333200Sbostic 					cursor(x1, y1);
38433200Sbostic 					if (trail)
38533200Sbostic 						fputchar(trail);
38633200Sbostic 				}
38733200Sbostic 			}
38833200Sbostic 			op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation];
38933200Sbostic 			switch (op->nopts) {
39033200Sbostic 			case 0:
39133200Sbostic 				(void)fflush(stdout);
39233200Sbostic 				abort();
39333200Sbostic 				return;
39433200Sbostic 			case 1:
39533200Sbostic 				w->orientation = op->opts[0];
39633200Sbostic 				break;
39733200Sbostic 			default:
39838560Sbostic 				w->orientation =
39938560Sbostic 				    op->opts[(int)random() % op->nopts];
40033200Sbostic 			}
40138560Sbostic 			cursor(x += xinc[w->orientation],
40238560Sbostic 			    y += yinc[w->orientation]);
40333200Sbostic 			if (!Wrap || x != last || y != bottom)
404*38561Sbostic 				fputchar(flavor[n % sizeof(flavor)]);
40533200Sbostic 			ref[w->ypos[h] = y][w->xpos[h] = x]++;
4068873Smckusick 		}
4078873Smckusick 	}
4088873Smckusick }
40933200Sbostic 
41033200Sbostic onsig()
41123869Smckusick {
412*38561Sbostic 	tputs(tgetstr("cl", &tcp), 1, fputchar);
413*38561Sbostic 	tputs(tgetstr("te", &tcp), 1, fputchar);
41433200Sbostic 	exit(0);
41523869Smckusick }
41633200Sbostic 
4178873Smckusick fputchar(c)
41833200Sbostic 	char c;
4198873Smckusick {
42033200Sbostic 	putchar(c);
4218873Smckusick }
42238560Sbostic 
42338560Sbostic nomem()
42438560Sbostic {
42538560Sbostic 	(void)fprintf(stderr, "worms: not enough memory.\n");
42638560Sbostic 	exit(1);
42738560Sbostic }
428