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