xref: /csrg-svn/games/worms/worms.c (revision 46770)
133200Sbostic /*
233200Sbostic  * Copyright (c) 1980 Regents of the University of California.
333200Sbostic  * All rights reserved.
433200Sbostic  *
542608Sbostic  * %sccs.include.redist.c%
633200Sbostic  */
733200Sbostic 
821202Sdist #ifndef lint
921202Sdist char copyright[] =
1021202Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\
1121202Sdist  All rights reserved.\n";
1233200Sbostic #endif /* not lint */
138873Smckusick 
1421202Sdist #ifndef lint
15*46770Sbostic static char sccsid[] = "@(#)worms.c	5.9 (Berkeley) 02/28/91";
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>
368873Smckusick #include <stdio.h>
3723869Smckusick #ifdef USG
3823869Smckusick #include <termio.h>
3923869Smckusick #else
408873Smckusick #include <sgtty.h>
4123869Smckusick #endif
4223869Smckusick #include <signal.h>
4333200Sbostic 
4433200Sbostic static struct options {
4533200Sbostic 	int nopts;
4633200Sbostic 	int opts[3];
4733200Sbostic }
4833200Sbostic 	normal[8] = {
4933200Sbostic 	{ 3, { 7, 0, 1 } },
5033200Sbostic 	{ 3, { 0, 1, 2 } },
5133200Sbostic 	{ 3, { 1, 2, 3 } },
5233200Sbostic 	{ 3, { 2, 3, 4 } },
5333200Sbostic 	{ 3, { 3, 4, 5 } },
5433200Sbostic 	{ 3, { 4, 5, 6 } },
5533200Sbostic 	{ 3, { 5, 6, 7 } },
5633200Sbostic 	{ 3, { 6, 7, 0 } }
5733200Sbostic },	upper[8] = {
5833200Sbostic 	{ 1, { 1, 0, 0 } },
5933200Sbostic 	{ 2, { 1, 2, 0 } },
6033200Sbostic 	{ 0, { 0, 0, 0 } },
6133200Sbostic 	{ 0, { 0, 0, 0 } },
6233200Sbostic 	{ 0, { 0, 0, 0 } },
6333200Sbostic 	{ 2, { 4, 5, 0 } },
6433200Sbostic 	{ 1, { 5, 0, 0 } },
6533200Sbostic 	{ 2, { 1, 5, 0 } }
6633200Sbostic },
6733200Sbostic 	left[8] = {
6833200Sbostic 	{ 0, { 0, 0, 0 } },
6933200Sbostic 	{ 0, { 0, 0, 0 } },
7033200Sbostic 	{ 0, { 0, 0, 0 } },
7133200Sbostic 	{ 2, { 2, 3, 0 } },
7233200Sbostic 	{ 1, { 3, 0, 0 } },
7333200Sbostic 	{ 2, { 3, 7, 0 } },
7433200Sbostic 	{ 1, { 7, 0, 0 } },
7533200Sbostic 	{ 2, { 7, 0, 0 } }
7633200Sbostic },
7733200Sbostic 	right[8] = {
7833200Sbostic 	{ 1, { 7, 0, 0 } },
7933200Sbostic 	{ 2, { 3, 7, 0 } },
8033200Sbostic 	{ 1, { 3, 0, 0 } },
8133200Sbostic 	{ 2, { 3, 4, 0 } },
8233200Sbostic 	{ 0, { 0, 0, 0 } },
8333200Sbostic 	{ 0, { 0, 0, 0 } },
8433200Sbostic 	{ 0, { 0, 0, 0 } },
8533200Sbostic 	{ 2, { 6, 7, 0 } }
8633200Sbostic },
8733200Sbostic 	lower[8] = {
8833200Sbostic 	{ 0, { 0, 0, 0 } },
8933200Sbostic 	{ 2, { 0, 1, 0 } },
9033200Sbostic 	{ 1, { 1, 0, 0 } },
9133200Sbostic 	{ 2, { 1, 5, 0 } },
9233200Sbostic 	{ 1, { 5, 0, 0 } },
9333200Sbostic 	{ 2, { 5, 6, 0 } },
9433200Sbostic 	{ 0, { 0, 0, 0 } },
9533200Sbostic 	{ 0, { 0, 0, 0 } }
9633200Sbostic },
9733200Sbostic 	upleft[8] = {
9833200Sbostic 	{ 0, { 0, 0, 0 } },
9933200Sbostic 	{ 0, { 0, 0, 0 } },
10033200Sbostic 	{ 0, { 0, 0, 0 } },
10133200Sbostic 	{ 0, { 0, 0, 0 } },
10233200Sbostic 	{ 0, { 0, 0, 0 } },
10333200Sbostic 	{ 1, { 3, 0, 0 } },
10433200Sbostic 	{ 2, { 1, 3, 0 } },
10533200Sbostic 	{ 1, { 1, 0, 0 } }
10633200Sbostic },
10733200Sbostic 	upright[8] = {
10833200Sbostic 	{ 2, { 3, 5, 0 } },
10933200Sbostic 	{ 1, { 3, 0, 0 } },
11033200Sbostic 	{ 0, { 0, 0, 0 } },
11133200Sbostic 	{ 0, { 0, 0, 0 } },
11233200Sbostic 	{ 0, { 0, 0, 0 } },
11333200Sbostic 	{ 0, { 0, 0, 0 } },
11433200Sbostic 	{ 0, { 0, 0, 0 } },
11533200Sbostic 	{ 1, { 5, 0, 0 } }
11633200Sbostic },
11733200Sbostic 	lowleft[8] = {
11833200Sbostic 	{ 3, { 7, 0, 1 } },
11933200Sbostic 	{ 0, { 0, 0, 0 } },
12033200Sbostic 	{ 0, { 0, 0, 0 } },
12133200Sbostic 	{ 1, { 1, 0, 0 } },
12233200Sbostic 	{ 2, { 1, 7, 0 } },
12333200Sbostic 	{ 1, { 7, 0, 0 } },
12433200Sbostic 	{ 0, { 0, 0, 0 } },
12533200Sbostic 	{ 0, { 0, 0, 0 } }
12633200Sbostic },
12733200Sbostic 	lowright[8] = {
12833200Sbostic 	{ 0, { 0, 0, 0 } },
12933200Sbostic 	{ 1, { 7, 0, 0 } },
13033200Sbostic 	{ 2, { 5, 7, 0 } },
13133200Sbostic 	{ 1, { 5, 0, 0 } },
13233200Sbostic 	{ 0, { 0, 0, 0 } },
13333200Sbostic 	{ 0, { 0, 0, 0 } },
13433200Sbostic 	{ 0, { 0, 0, 0 } },
13533200Sbostic 	{ 0, { 0, 0, 0 } }
1368873Smckusick };
13733200Sbostic 
13833200Sbostic #define	cursor(c, r)	tputs(tgoto(CM, c, r), 1, fputchar)
13933200Sbostic 
14038561Sbostic char *tcp;
14138561Sbostic int fputchar();
14233200Sbostic 
14333200Sbostic static char	flavor[] = {
14438560Sbostic 	'O', '*', '#', '$', '%', '0', '@', '~'
1458873Smckusick };
14633200Sbostic static short	xinc[] = {
14733200Sbostic 	1,  1,  1,  0, -1, -1, -1,  0
14833200Sbostic }, yinc[] = {
14933200Sbostic 	-1,  0,  1,  1,  1,  0, -1, -1
15033200Sbostic };
15133200Sbostic static struct	worm {
15233200Sbostic 	int orientation, head;
15333200Sbostic 	short *xpos, *ypos;
15438560Sbostic } *worm;
15533200Sbostic 
15633200Sbostic main(argc, argv)
15733200Sbostic 	int argc;
15833200Sbostic 	char **argv;
1598873Smckusick {
16033200Sbostic 	extern int optind;
16133200Sbostic 	extern short ospeed;
16233200Sbostic 	extern char *optarg, *UP;
16333200Sbostic 	register int x, y, h, n;
16433200Sbostic 	register struct worm *w;
16533200Sbostic 	register struct options *op;
16633200Sbostic 	register short *ip;
16733200Sbostic 	register char *term;
16838560Sbostic 	int CO, IN, LI, last, bottom, ch, length, number, trail, Wrap;
169*46770Sbostic 	void onsig();
17033200Sbostic 	short **ref;
17138561Sbostic 	char *AL, *BC, *CM, *EI, *HO, *IC, *IM, *IP, *SR;
17238560Sbostic 	char *field, tcb[100], *mp, *malloc(), *getenv(), *tgetstr(), *tgoto();
17333200Sbostic 	long random();
17423869Smckusick #ifdef USG
17533200Sbostic 	struct termio sg;
17623869Smckusick #else
17733200Sbostic 	struct sgttyb sg;
17823869Smckusick #endif
17933200Sbostic 
18033200Sbostic 	length = 16;
18133200Sbostic 	number = 3;
18233200Sbostic 	trail = ' ';
18333200Sbostic 	field = NULL;
18433200Sbostic 	while ((ch = getopt(argc, argv, "fl:n:t")) != EOF)
18538560Sbostic 		switch(ch) {
18633200Sbostic 		case 'f':
18733200Sbostic 			field = "WORM";
18833200Sbostic 			break;
18933200Sbostic 		case 'l':
19033200Sbostic 			if ((length = atoi(optarg)) < 2 || length > 1024) {
19138560Sbostic 				(void)fprintf(stderr,
19238560Sbostic 				    "worms: invalid length (%d - %d).\n",
19338560Sbostic 				     2, 1024);
19433200Sbostic 				exit(1);
19533200Sbostic 			}
19633200Sbostic 			break;
19733200Sbostic 		case 'n':
19838560Sbostic 			if ((number = atoi(optarg)) < 1) {
19938560Sbostic 				(void)fprintf(stderr,
20038560Sbostic 				    "worms: invalid number of worms.\n");
20133200Sbostic 				exit(1);
20233200Sbostic 			}
20333200Sbostic 			break;
20433200Sbostic 		case 't':
20533200Sbostic 			trail = '.';
20633200Sbostic 			break;
20733200Sbostic 		case '?':
20833200Sbostic 		default:
20938560Sbostic 			(void)fprintf(stderr,
21038560Sbostic 			    "usage: worms [-ft] [-length #] [-number #]\n");
21133200Sbostic 			exit(1);
21233200Sbostic 		}
21333200Sbostic 
21433200Sbostic 	if (!(term = getenv("TERM"))) {
21538560Sbostic 		(void)fprintf(stderr, "worms: no TERM environment variable.\n");
2168873Smckusick 		exit(1);
21733200Sbostic 	}
21838560Sbostic 	if (!(worm = (struct worm *)malloc((u_int)number *
21938560Sbostic 	    sizeof(struct worm))) || !(mp = malloc((u_int)1024)))
22038560Sbostic 		nomem();
22133200Sbostic 	if (tgetent(mp, term) <= 0) {
22238560Sbostic 		(void)fprintf(stderr, "worms: %s: unknown terminal type.\n",
22338560Sbostic 		    term);
22433200Sbostic 		exit(1);
22533200Sbostic 	}
22633200Sbostic 	tcp = tcb;
22733200Sbostic 	if (!(CM = tgetstr("cm", &tcp))) {
22838560Sbostic 		(void)fprintf(stderr,
22938560Sbostic 		    "worms: terminal incapable of cursor motion.\n");
23033200Sbostic 		exit(1);
23133200Sbostic 	}
23233200Sbostic 	AL = tgetstr("al", &tcp);
23333200Sbostic 	BC = tgetflag("bs") ? "\b" : tgetstr("bc", &tcp);
23433200Sbostic 	if ((CO = tgetnum("co")) <= 0)
23533200Sbostic 		CO = 80;
23633200Sbostic 	last = CO - 1;
23733200Sbostic 	EI = tgetstr("ei", &tcp);
23833200Sbostic 	HO = tgetstr("ho", &tcp);
23933200Sbostic 	IC = tgetstr("ic", &tcp);
24033200Sbostic 	IM = tgetstr("im", &tcp);
24133200Sbostic 	IN = tgetflag("in");
24233200Sbostic 	IP = tgetstr("ip", &tcp);
24333200Sbostic 	if ((LI = tgetnum("li")) <= 0)
24433200Sbostic 		LI = 24;
24533200Sbostic 	bottom = LI - 1;
24633200Sbostic 	SR = tgetstr("sr", &tcp);
24733200Sbostic 	UP = tgetstr("up", &tcp);
24823869Smckusick #ifdef USG
24933200Sbostic 	ioctl(1, TCGETA, &sg);
25033200Sbostic 	ospeed = sg.c_cflag&CBAUD;
25123869Smckusick #else
25233200Sbostic 	gtty(1, &sg);
25333200Sbostic 	ospeed = sg.sg_ospeed;
25423869Smckusick #endif
25533200Sbostic 	Wrap = tgetflag("am");
25638560Sbostic 	if (!(ip = (short *)malloc((u_int)(LI * CO * sizeof(short)))))
25738560Sbostic 		nomem();
25838560Sbostic 	if (!(ref = (short **)malloc((u_int)(LI * sizeof(short *)))))
25938560Sbostic 		nomem();
26033200Sbostic 	for (n = 0; n < LI; ++n) {
26133200Sbostic 		ref[n] = ip;
26233200Sbostic 		ip += CO;
26333200Sbostic 	}
26433200Sbostic 	for (ip = ref[0], n = LI * CO; --n >= 0;)
26533200Sbostic 		*ip++ = 0;
26633200Sbostic 	if (Wrap)
26733200Sbostic 		ref[bottom][last] = 1;
26833200Sbostic 	for (n = number, w = &worm[0]; --n >= 0; w++) {
26933200Sbostic 		w->orientation = w->head = 0;
27038560Sbostic 		if (!(ip = (short *)malloc((u_int)(length * sizeof(short)))))
27138560Sbostic 			nomem();
27233200Sbostic 		w->xpos = ip;
27333200Sbostic 		for (x = length; --x >= 0;)
27433200Sbostic 			*ip++ = -1;
27538560Sbostic 		if (!(ip = (short *)malloc((u_int)(length * sizeof(short)))))
27638560Sbostic 			nomem();
27733200Sbostic 		w->ypos = ip;
27833200Sbostic 		for (y = length; --y >= 0;)
27933200Sbostic 			*ip++ = -1;
2808873Smckusick 	}
28133200Sbostic 
28233200Sbostic 	(void)signal(SIGHUP, onsig);
28333200Sbostic 	(void)signal(SIGINT, onsig);
28433200Sbostic 	(void)signal(SIGQUIT, onsig);
28533200Sbostic 	(void)signal(SIGSTOP, onsig);
28633200Sbostic 	(void)signal(SIGTSTP, onsig);
28733200Sbostic 	(void)signal(SIGTERM, onsig);
28833200Sbostic 
28933200Sbostic 	tputs(tgetstr("ti", &tcp), 1, fputchar);
29033200Sbostic 	tputs(tgetstr("cl", &tcp), 1, fputchar);
29133200Sbostic 	if (field) {
29233200Sbostic 		register char *p = field;
29333200Sbostic 
29433200Sbostic 		for (y = bottom; --y >= 0;) {
29533200Sbostic 			for (x = CO; --x >= 0;) {
29633200Sbostic 				fputchar(*p++);
29733200Sbostic 				if (!*p)
29833200Sbostic 					p = field;
29933200Sbostic 			}
30033200Sbostic 			if (!Wrap)
30133200Sbostic 				fputchar('\n');
30233200Sbostic 			(void)fflush(stdout);
30333200Sbostic 		}
30433200Sbostic 		if (Wrap) {
30533200Sbostic 			if (IM && !IN) {
30633200Sbostic 				for (x = last; --x > 0;) {
30733200Sbostic 					fputchar(*p++);
30833200Sbostic 					if (!*p)
30933200Sbostic 						p = field;
31033200Sbostic 				}
31133200Sbostic 				y = *p++;
31233200Sbostic 				if (!*p)
31333200Sbostic 					p = field;
31433200Sbostic 				fputchar(*p);
31533200Sbostic 				if (BC)
31633200Sbostic 					tputs(BC, 1, fputchar);
31733200Sbostic 				else
31833200Sbostic 					cursor(last - 1, bottom);
31933200Sbostic 				tputs(IM, 1, fputchar);
32033200Sbostic 				if (IC)
32133200Sbostic 					tputs(IC, 1, fputchar);
32233200Sbostic 				fputchar(y);
32333200Sbostic 				if (IP)
32433200Sbostic 					tputs(IP, 1, fputchar);
32533200Sbostic 				tputs(EI, 1, fputchar);
32633200Sbostic 			}
32733200Sbostic 			else if (SR || AL) {
32833200Sbostic 				if (HO)
32933200Sbostic 					tputs(HO, 1, fputchar);
33033200Sbostic 				else
33133200Sbostic 					cursor(0, 0);
33233200Sbostic 				if (SR)
33333200Sbostic 					tputs(SR, 1, fputchar);
33433200Sbostic 				else
33533200Sbostic 					tputs(AL, LI, fputchar);
33633200Sbostic 				for (x = CO; --x >= 0;) {
33733200Sbostic 					fputchar(*p++);
33833200Sbostic 					if (!*p)
33933200Sbostic 						p = field;
34033200Sbostic 				}
34133200Sbostic 			}
34233200Sbostic 			else for (x = last; --x >= 0;) {
34333200Sbostic 				fputchar(*p++);
34433200Sbostic 				if (!*p)
34533200Sbostic 					p = field;
34633200Sbostic 			}
34733200Sbostic 		}
34833200Sbostic 		else for (x = CO; --x >= 0;) {
34933200Sbostic 			fputchar(*p++);
35033200Sbostic 			if (!*p)
35133200Sbostic 				p = field;
35233200Sbostic 		}
3538873Smckusick 	}
35433200Sbostic 	for (;;) {
35533200Sbostic 		(void)fflush(stdout);
35633200Sbostic 		for (n = 0, w = &worm[0]; n < number; n++, w++) {
35733200Sbostic 			if ((x = w->xpos[h = w->head]) < 0) {
35833200Sbostic 				cursor(x = w->xpos[h] = 0,
35933200Sbostic 				     y = w->ypos[h] = bottom);
36038561Sbostic 				fputchar(flavor[n % sizeof(flavor)]);
36133200Sbostic 				ref[y][x]++;
36233200Sbostic 			}
36333200Sbostic 			else
36433200Sbostic 				y = w->ypos[h];
36533200Sbostic 			if (++h == length)
36633200Sbostic 				h = 0;
36733200Sbostic 			if (w->xpos[w->head = h] >= 0) {
36833200Sbostic 				register int x1, y1;
36933200Sbostic 
37033200Sbostic 				x1 = w->xpos[h];
37133200Sbostic 				y1 = w->ypos[h];
37233200Sbostic 				if (--ref[y1][x1] == 0) {
37333200Sbostic 					cursor(x1, y1);
37433200Sbostic 					if (trail)
37533200Sbostic 						fputchar(trail);
37633200Sbostic 				}
37733200Sbostic 			}
37833200Sbostic 			op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation];
37933200Sbostic 			switch (op->nopts) {
38033200Sbostic 			case 0:
38133200Sbostic 				(void)fflush(stdout);
38233200Sbostic 				abort();
38333200Sbostic 				return;
38433200Sbostic 			case 1:
38533200Sbostic 				w->orientation = op->opts[0];
38633200Sbostic 				break;
38733200Sbostic 			default:
38838560Sbostic 				w->orientation =
38938560Sbostic 				    op->opts[(int)random() % op->nopts];
39033200Sbostic 			}
39138560Sbostic 			cursor(x += xinc[w->orientation],
39238560Sbostic 			    y += yinc[w->orientation]);
39333200Sbostic 			if (!Wrap || x != last || y != bottom)
39438561Sbostic 				fputchar(flavor[n % sizeof(flavor)]);
39533200Sbostic 			ref[w->ypos[h] = y][w->xpos[h] = x]++;
3968873Smckusick 		}
3978873Smckusick 	}
3988873Smckusick }
39933200Sbostic 
400*46770Sbostic void
40133200Sbostic onsig()
40223869Smckusick {
40338561Sbostic 	tputs(tgetstr("cl", &tcp), 1, fputchar);
40438561Sbostic 	tputs(tgetstr("te", &tcp), 1, fputchar);
40533200Sbostic 	exit(0);
40623869Smckusick }
40733200Sbostic 
4088873Smckusick fputchar(c)
40933200Sbostic 	char c;
4108873Smckusick {
41133200Sbostic 	putchar(c);
4128873Smckusick }
41338560Sbostic 
41438560Sbostic nomem()
41538560Sbostic {
41638560Sbostic 	(void)fprintf(stderr, "worms: not enough memory.\n");
41738560Sbostic 	exit(1);
41838560Sbostic }
419