xref: /csrg-svn/games/worms/worms.c (revision 60868)
133200Sbostic /*
2*60868Sbostic  * Copyright (c) 1980, 1993
3*60868Sbostic  *	The Regents of the University of California.  All rights reserved.
433200Sbostic  *
542608Sbostic  * %sccs.include.redist.c%
633200Sbostic  */
733200Sbostic 
821202Sdist #ifndef lint
9*60868Sbostic static char copyright[] =
10*60868Sbostic "@(#) Copyright (c) 1980, 1993\n\
11*60868Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1233200Sbostic #endif /* not lint */
138873Smckusick 
1421202Sdist #ifndef lint
15*60868Sbostic static char sccsid[] = "@(#)worms.c	8.1 (Berkeley) 05/31/93";
1633200Sbostic #endif /* not lint */
1721202Sdist 
188873Smckusick /*
1933200Sbostic  *
2033200Sbostic  *	 @@@        @@@    @@@@@@@@@@     @@@@@@@@@@@    @@@@@@@@@@@@
2133200Sbostic  *	 @@@        @@@   @@@@@@@@@@@@    @@@@@@@@@@@@   @@@@@@@@@@@@@
2233200Sbostic  *	 @@@        @@@  @@@@      @@@@   @@@@           @@@@ @@@  @@@@
2333200Sbostic  *	 @@@   @@   @@@  @@@        @@@   @@@            @@@  @@@   @@@
2433200Sbostic  *	 @@@  @@@@  @@@  @@@        @@@   @@@            @@@  @@@   @@@
2533200Sbostic  *	 @@@@ @@@@ @@@@  @@@        @@@   @@@            @@@  @@@   @@@
2633200Sbostic  *	  @@@@@@@@@@@@   @@@@      @@@@   @@@            @@@  @@@   @@@
2733200Sbostic  *	   @@@@  @@@@     @@@@@@@@@@@@    @@@            @@@  @@@   @@@
2833200Sbostic  *	    @@    @@       @@@@@@@@@@     @@@            @@@  @@@   @@@
2933200Sbostic  *
3033200Sbostic  *				 Eric P. Scott
3133200Sbostic  *			  Caltech High Energy Physics
3233200Sbostic  *				 October, 1980
3333200Sbostic  *
3433200Sbostic  */
3533200Sbostic #include <sys/types.h>
3658761Sbostic 
3758761Sbostic #include <signal.h>
388873Smckusick #include <stdio.h>
3958761Sbostic #include <stdlib.h>
4058761Sbostic #include <unistd.h>
4133200Sbostic 
4233200Sbostic static struct options {
4333200Sbostic 	int nopts;
4433200Sbostic 	int opts[3];
4533200Sbostic }
4633200Sbostic 	normal[8] = {
4733200Sbostic 	{ 3, { 7, 0, 1 } },
4833200Sbostic 	{ 3, { 0, 1, 2 } },
4933200Sbostic 	{ 3, { 1, 2, 3 } },
5033200Sbostic 	{ 3, { 2, 3, 4 } },
5133200Sbostic 	{ 3, { 3, 4, 5 } },
5233200Sbostic 	{ 3, { 4, 5, 6 } },
5333200Sbostic 	{ 3, { 5, 6, 7 } },
5433200Sbostic 	{ 3, { 6, 7, 0 } }
5533200Sbostic },	upper[8] = {
5633200Sbostic 	{ 1, { 1, 0, 0 } },
5733200Sbostic 	{ 2, { 1, 2, 0 } },
5833200Sbostic 	{ 0, { 0, 0, 0 } },
5933200Sbostic 	{ 0, { 0, 0, 0 } },
6033200Sbostic 	{ 0, { 0, 0, 0 } },
6133200Sbostic 	{ 2, { 4, 5, 0 } },
6233200Sbostic 	{ 1, { 5, 0, 0 } },
6333200Sbostic 	{ 2, { 1, 5, 0 } }
6433200Sbostic },
6533200Sbostic 	left[8] = {
6633200Sbostic 	{ 0, { 0, 0, 0 } },
6733200Sbostic 	{ 0, { 0, 0, 0 } },
6833200Sbostic 	{ 0, { 0, 0, 0 } },
6933200Sbostic 	{ 2, { 2, 3, 0 } },
7033200Sbostic 	{ 1, { 3, 0, 0 } },
7133200Sbostic 	{ 2, { 3, 7, 0 } },
7233200Sbostic 	{ 1, { 7, 0, 0 } },
7333200Sbostic 	{ 2, { 7, 0, 0 } }
7433200Sbostic },
7533200Sbostic 	right[8] = {
7633200Sbostic 	{ 1, { 7, 0, 0 } },
7733200Sbostic 	{ 2, { 3, 7, 0 } },
7833200Sbostic 	{ 1, { 3, 0, 0 } },
7933200Sbostic 	{ 2, { 3, 4, 0 } },
8033200Sbostic 	{ 0, { 0, 0, 0 } },
8133200Sbostic 	{ 0, { 0, 0, 0 } },
8233200Sbostic 	{ 0, { 0, 0, 0 } },
8333200Sbostic 	{ 2, { 6, 7, 0 } }
8433200Sbostic },
8533200Sbostic 	lower[8] = {
8633200Sbostic 	{ 0, { 0, 0, 0 } },
8733200Sbostic 	{ 2, { 0, 1, 0 } },
8833200Sbostic 	{ 1, { 1, 0, 0 } },
8933200Sbostic 	{ 2, { 1, 5, 0 } },
9033200Sbostic 	{ 1, { 5, 0, 0 } },
9133200Sbostic 	{ 2, { 5, 6, 0 } },
9233200Sbostic 	{ 0, { 0, 0, 0 } },
9333200Sbostic 	{ 0, { 0, 0, 0 } }
9433200Sbostic },
9533200Sbostic 	upleft[8] = {
9633200Sbostic 	{ 0, { 0, 0, 0 } },
9733200Sbostic 	{ 0, { 0, 0, 0 } },
9833200Sbostic 	{ 0, { 0, 0, 0 } },
9933200Sbostic 	{ 0, { 0, 0, 0 } },
10033200Sbostic 	{ 0, { 0, 0, 0 } },
10133200Sbostic 	{ 1, { 3, 0, 0 } },
10233200Sbostic 	{ 2, { 1, 3, 0 } },
10333200Sbostic 	{ 1, { 1, 0, 0 } }
10433200Sbostic },
10533200Sbostic 	upright[8] = {
10633200Sbostic 	{ 2, { 3, 5, 0 } },
10733200Sbostic 	{ 1, { 3, 0, 0 } },
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, { 5, 0, 0 } }
11433200Sbostic },
11533200Sbostic 	lowleft[8] = {
11633200Sbostic 	{ 3, { 7, 0, 1 } },
11733200Sbostic 	{ 0, { 0, 0, 0 } },
11833200Sbostic 	{ 0, { 0, 0, 0 } },
11933200Sbostic 	{ 1, { 1, 0, 0 } },
12033200Sbostic 	{ 2, { 1, 7, 0 } },
12133200Sbostic 	{ 1, { 7, 0, 0 } },
12233200Sbostic 	{ 0, { 0, 0, 0 } },
12333200Sbostic 	{ 0, { 0, 0, 0 } }
12433200Sbostic },
12533200Sbostic 	lowright[8] = {
12633200Sbostic 	{ 0, { 0, 0, 0 } },
12733200Sbostic 	{ 1, { 7, 0, 0 } },
12833200Sbostic 	{ 2, { 5, 7, 0 } },
12933200Sbostic 	{ 1, { 5, 0, 0 } },
13033200Sbostic 	{ 0, { 0, 0, 0 } },
13133200Sbostic 	{ 0, { 0, 0, 0 } },
13233200Sbostic 	{ 0, { 0, 0, 0 } },
13333200Sbostic 	{ 0, { 0, 0, 0 } }
1348873Smckusick };
13533200Sbostic 
13633200Sbostic #define	cursor(c, r)	tputs(tgoto(CM, c, r), 1, fputchar)
13733200Sbostic 
13838561Sbostic char *tcp;
13933200Sbostic static char	flavor[] = {
14038560Sbostic 	'O', '*', '#', '$', '%', '0', '@', '~'
1418873Smckusick };
14233200Sbostic static short	xinc[] = {
14333200Sbostic 	1,  1,  1,  0, -1, -1, -1,  0
14433200Sbostic }, yinc[] = {
14533200Sbostic 	-1,  0,  1,  1,  1,  0, -1, -1
14633200Sbostic };
14733200Sbostic static struct	worm {
14833200Sbostic 	int orientation, head;
14933200Sbostic 	short *xpos, *ypos;
15038560Sbostic } *worm;
15133200Sbostic 
15258761Sbostic void	 fputchar __P((int));
15358761Sbostic void	 onsig __P((int));
15458761Sbostic char	*tgetstr __P((char *, char **));
15558761Sbostic char	*tgoto __P((char *, int, int));
15658761Sbostic int	 tputs __P((char *, int, void (*)(int)));
15758761Sbostic 
15858761Sbostic int
main(argc,argv)15933200Sbostic main(argc, argv)
16033200Sbostic 	int argc;
16158761Sbostic 	char *argv[];
1628873Smckusick {
16333200Sbostic 	extern int optind;
16433200Sbostic 	extern char *optarg, *UP;
16533200Sbostic 	register int x, y, h, n;
16633200Sbostic 	register struct worm *w;
16733200Sbostic 	register struct options *op;
16833200Sbostic 	register short *ip;
16933200Sbostic 	register char *term;
17038560Sbostic 	int CO, IN, LI, last, bottom, ch, length, number, trail, Wrap;
17133200Sbostic 	short **ref;
17238561Sbostic 	char *AL, *BC, *CM, *EI, *HO, *IC, *IM, *IP, *SR;
17358761Sbostic 	char *field, tcb[100], *mp;
17433200Sbostic 	long random();
17533200Sbostic 
17633200Sbostic 	length = 16;
17733200Sbostic 	number = 3;
17833200Sbostic 	trail = ' ';
17933200Sbostic 	field = NULL;
18033200Sbostic 	while ((ch = getopt(argc, argv, "fl:n:t")) != EOF)
18138560Sbostic 		switch(ch) {
18233200Sbostic 		case 'f':
18333200Sbostic 			field = "WORM";
18433200Sbostic 			break;
18533200Sbostic 		case 'l':
18633200Sbostic 			if ((length = atoi(optarg)) < 2 || length > 1024) {
18738560Sbostic 				(void)fprintf(stderr,
18838560Sbostic 				    "worms: invalid length (%d - %d).\n",
18938560Sbostic 				     2, 1024);
19033200Sbostic 				exit(1);
19133200Sbostic 			}
19233200Sbostic 			break;
19333200Sbostic 		case 'n':
19438560Sbostic 			if ((number = atoi(optarg)) < 1) {
19538560Sbostic 				(void)fprintf(stderr,
19638560Sbostic 				    "worms: invalid number of worms.\n");
19733200Sbostic 				exit(1);
19833200Sbostic 			}
19933200Sbostic 			break;
20033200Sbostic 		case 't':
20133200Sbostic 			trail = '.';
20233200Sbostic 			break;
20333200Sbostic 		case '?':
20433200Sbostic 		default:
20538560Sbostic 			(void)fprintf(stderr,
20651922Sbostic 			    "usage: worms [-ft] [-l length] [-n number]\n");
20733200Sbostic 			exit(1);
20833200Sbostic 		}
20933200Sbostic 
21033200Sbostic 	if (!(term = getenv("TERM"))) {
21138560Sbostic 		(void)fprintf(stderr, "worms: no TERM environment variable.\n");
2128873Smckusick 		exit(1);
21333200Sbostic 	}
21458761Sbostic 	if (!(worm = malloc((size_t)number *
21558761Sbostic 	    sizeof(struct worm))) || !(mp = malloc((size_t)1024)))
21638560Sbostic 		nomem();
21733200Sbostic 	if (tgetent(mp, term) <= 0) {
21838560Sbostic 		(void)fprintf(stderr, "worms: %s: unknown terminal type.\n",
21938560Sbostic 		    term);
22033200Sbostic 		exit(1);
22133200Sbostic 	}
22233200Sbostic 	tcp = tcb;
22333200Sbostic 	if (!(CM = tgetstr("cm", &tcp))) {
22438560Sbostic 		(void)fprintf(stderr,
22538560Sbostic 		    "worms: terminal incapable of cursor motion.\n");
22633200Sbostic 		exit(1);
22733200Sbostic 	}
22833200Sbostic 	AL = tgetstr("al", &tcp);
22933200Sbostic 	BC = tgetflag("bs") ? "\b" : tgetstr("bc", &tcp);
23033200Sbostic 	if ((CO = tgetnum("co")) <= 0)
23133200Sbostic 		CO = 80;
23233200Sbostic 	last = CO - 1;
23333200Sbostic 	EI = tgetstr("ei", &tcp);
23433200Sbostic 	HO = tgetstr("ho", &tcp);
23533200Sbostic 	IC = tgetstr("ic", &tcp);
23633200Sbostic 	IM = tgetstr("im", &tcp);
23733200Sbostic 	IN = tgetflag("in");
23833200Sbostic 	IP = tgetstr("ip", &tcp);
23933200Sbostic 	if ((LI = tgetnum("li")) <= 0)
24033200Sbostic 		LI = 24;
24133200Sbostic 	bottom = LI - 1;
24233200Sbostic 	SR = tgetstr("sr", &tcp);
24333200Sbostic 	UP = tgetstr("up", &tcp);
24433200Sbostic 	Wrap = tgetflag("am");
24558761Sbostic 	if (!(ip = malloc((size_t)(LI * CO * sizeof(short)))))
24638560Sbostic 		nomem();
24758761Sbostic 	if (!(ref = malloc((size_t)(LI * sizeof(short *)))))
24838560Sbostic 		nomem();
24933200Sbostic 	for (n = 0; n < LI; ++n) {
25033200Sbostic 		ref[n] = ip;
25133200Sbostic 		ip += CO;
25233200Sbostic 	}
25333200Sbostic 	for (ip = ref[0], n = LI * CO; --n >= 0;)
25433200Sbostic 		*ip++ = 0;
25533200Sbostic 	if (Wrap)
25633200Sbostic 		ref[bottom][last] = 1;
25733200Sbostic 	for (n = number, w = &worm[0]; --n >= 0; w++) {
25833200Sbostic 		w->orientation = w->head = 0;
25958761Sbostic 		if (!(ip = malloc((size_t)(length * sizeof(short)))))
26038560Sbostic 			nomem();
26133200Sbostic 		w->xpos = ip;
26233200Sbostic 		for (x = length; --x >= 0;)
26333200Sbostic 			*ip++ = -1;
26458761Sbostic 		if (!(ip = malloc((size_t)(length * sizeof(short)))))
26538560Sbostic 			nomem();
26633200Sbostic 		w->ypos = ip;
26733200Sbostic 		for (y = length; --y >= 0;)
26833200Sbostic 			*ip++ = -1;
2698873Smckusick 	}
27033200Sbostic 
27133200Sbostic 	(void)signal(SIGHUP, onsig);
27233200Sbostic 	(void)signal(SIGINT, onsig);
27333200Sbostic 	(void)signal(SIGQUIT, onsig);
27433200Sbostic 	(void)signal(SIGSTOP, onsig);
27533200Sbostic 	(void)signal(SIGTSTP, onsig);
27633200Sbostic 	(void)signal(SIGTERM, onsig);
27733200Sbostic 
27833200Sbostic 	tputs(tgetstr("ti", &tcp), 1, fputchar);
27933200Sbostic 	tputs(tgetstr("cl", &tcp), 1, fputchar);
28033200Sbostic 	if (field) {
28133200Sbostic 		register char *p = field;
28233200Sbostic 
28333200Sbostic 		for (y = bottom; --y >= 0;) {
28433200Sbostic 			for (x = CO; --x >= 0;) {
28533200Sbostic 				fputchar(*p++);
28633200Sbostic 				if (!*p)
28733200Sbostic 					p = field;
28833200Sbostic 			}
28933200Sbostic 			if (!Wrap)
29033200Sbostic 				fputchar('\n');
29133200Sbostic 			(void)fflush(stdout);
29233200Sbostic 		}
29333200Sbostic 		if (Wrap) {
29433200Sbostic 			if (IM && !IN) {
29533200Sbostic 				for (x = last; --x > 0;) {
29633200Sbostic 					fputchar(*p++);
29733200Sbostic 					if (!*p)
29833200Sbostic 						p = field;
29933200Sbostic 				}
30033200Sbostic 				y = *p++;
30133200Sbostic 				if (!*p)
30233200Sbostic 					p = field;
30333200Sbostic 				fputchar(*p);
30433200Sbostic 				if (BC)
30533200Sbostic 					tputs(BC, 1, fputchar);
30633200Sbostic 				else
30733200Sbostic 					cursor(last - 1, bottom);
30833200Sbostic 				tputs(IM, 1, fputchar);
30933200Sbostic 				if (IC)
31033200Sbostic 					tputs(IC, 1, fputchar);
31133200Sbostic 				fputchar(y);
31233200Sbostic 				if (IP)
31333200Sbostic 					tputs(IP, 1, fputchar);
31433200Sbostic 				tputs(EI, 1, fputchar);
31533200Sbostic 			}
31633200Sbostic 			else if (SR || AL) {
31733200Sbostic 				if (HO)
31833200Sbostic 					tputs(HO, 1, fputchar);
31933200Sbostic 				else
32033200Sbostic 					cursor(0, 0);
32133200Sbostic 				if (SR)
32233200Sbostic 					tputs(SR, 1, fputchar);
32333200Sbostic 				else
32433200Sbostic 					tputs(AL, LI, fputchar);
32533200Sbostic 				for (x = CO; --x >= 0;) {
32633200Sbostic 					fputchar(*p++);
32733200Sbostic 					if (!*p)
32833200Sbostic 						p = field;
32933200Sbostic 				}
33033200Sbostic 			}
33133200Sbostic 			else for (x = last; --x >= 0;) {
33233200Sbostic 				fputchar(*p++);
33333200Sbostic 				if (!*p)
33433200Sbostic 					p = field;
33533200Sbostic 			}
33633200Sbostic 		}
33733200Sbostic 		else for (x = CO; --x >= 0;) {
33833200Sbostic 			fputchar(*p++);
33933200Sbostic 			if (!*p)
34033200Sbostic 				p = field;
34133200Sbostic 		}
3428873Smckusick 	}
34333200Sbostic 	for (;;) {
34433200Sbostic 		(void)fflush(stdout);
34533200Sbostic 		for (n = 0, w = &worm[0]; n < number; n++, w++) {
34633200Sbostic 			if ((x = w->xpos[h = w->head]) < 0) {
34733200Sbostic 				cursor(x = w->xpos[h] = 0,
34833200Sbostic 				     y = w->ypos[h] = bottom);
34938561Sbostic 				fputchar(flavor[n % sizeof(flavor)]);
35033200Sbostic 				ref[y][x]++;
35133200Sbostic 			}
35233200Sbostic 			else
35333200Sbostic 				y = w->ypos[h];
35433200Sbostic 			if (++h == length)
35533200Sbostic 				h = 0;
35633200Sbostic 			if (w->xpos[w->head = h] >= 0) {
35733200Sbostic 				register int x1, y1;
35833200Sbostic 
35933200Sbostic 				x1 = w->xpos[h];
36033200Sbostic 				y1 = w->ypos[h];
36133200Sbostic 				if (--ref[y1][x1] == 0) {
36233200Sbostic 					cursor(x1, y1);
36333200Sbostic 					if (trail)
36433200Sbostic 						fputchar(trail);
36533200Sbostic 				}
36633200Sbostic 			}
36733200Sbostic 			op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation];
36833200Sbostic 			switch (op->nopts) {
36933200Sbostic 			case 0:
37033200Sbostic 				(void)fflush(stdout);
37133200Sbostic 				abort();
37233200Sbostic 				return;
37333200Sbostic 			case 1:
37433200Sbostic 				w->orientation = op->opts[0];
37533200Sbostic 				break;
37633200Sbostic 			default:
37738560Sbostic 				w->orientation =
37838560Sbostic 				    op->opts[(int)random() % op->nopts];
37933200Sbostic 			}
38038560Sbostic 			cursor(x += xinc[w->orientation],
38138560Sbostic 			    y += yinc[w->orientation]);
38233200Sbostic 			if (!Wrap || x != last || y != bottom)
38338561Sbostic 				fputchar(flavor[n % sizeof(flavor)]);
38433200Sbostic 			ref[w->ypos[h] = y][w->xpos[h] = x]++;
3858873Smckusick 		}
3868873Smckusick 	}
3878873Smckusick }
38833200Sbostic 
38946770Sbostic void
onsig(signo)39058761Sbostic onsig(signo)
39158761Sbostic 	int signo;
39223869Smckusick {
39338561Sbostic 	tputs(tgetstr("cl", &tcp), 1, fputchar);
39438561Sbostic 	tputs(tgetstr("te", &tcp), 1, fputchar);
39533200Sbostic 	exit(0);
39623869Smckusick }
39733200Sbostic 
39858761Sbostic void
fputchar(c)3998873Smckusick fputchar(c)
40058761Sbostic 	int c;
4018873Smckusick {
40258761Sbostic 	(void)putchar(c);
4038873Smckusick }
40438560Sbostic 
nomem()40538560Sbostic nomem()
40638560Sbostic {
40738560Sbostic 	(void)fprintf(stderr, "worms: not enough memory.\n");
40838560Sbostic 	exit(1);
40938560Sbostic }
410