xref: /csrg-svn/games/worms/worms.c (revision 8873)
1*8873Smckusick 
2*8873Smckusick static char sccsid[] = "	worms.c	4.1	82/10/24	";
3*8873Smckusick 
4*8873Smckusick /*
5*8873Smckusick 
6*8873Smckusick 	 @@@        @@@    @@@@@@@@@@     @@@@@@@@@@@    @@@@@@@@@@@@
7*8873Smckusick 	 @@@        @@@   @@@@@@@@@@@@    @@@@@@@@@@@@   @@@@@@@@@@@@@
8*8873Smckusick 	 @@@        @@@  @@@@      @@@@   @@@@           @@@@ @@@  @@@@
9*8873Smckusick 	 @@@   @@   @@@  @@@        @@@   @@@            @@@  @@@   @@@
10*8873Smckusick 	 @@@  @@@@  @@@  @@@        @@@   @@@            @@@  @@@   @@@
11*8873Smckusick 	 @@@@ @@@@ @@@@  @@@        @@@   @@@            @@@  @@@   @@@
12*8873Smckusick 	  @@@@@@@@@@@@   @@@@      @@@@   @@@            @@@  @@@   @@@
13*8873Smckusick 	   @@@@  @@@@     @@@@@@@@@@@@    @@@            @@@  @@@   @@@
14*8873Smckusick 	    @@    @@       @@@@@@@@@@     @@@            @@@  @@@   @@@
15*8873Smckusick 
16*8873Smckusick 				 Eric P. Scott
17*8873Smckusick 			  Caltech High Energy Physics
18*8873Smckusick 				 October, 1980
19*8873Smckusick 
20*8873Smckusick */
21*8873Smckusick #include <stdio.h>
22*8873Smckusick #include <sgtty.h>
23*8873Smckusick #define cursor(col,row) tputs(tgoto(CM,col,row),1,outc)
24*8873Smckusick outc(c)
25*8873Smckusick {
26*8873Smckusick 	putchar(c);
27*8873Smckusick }
28*8873Smckusick extern char *UP;
29*8873Smckusick extern short ospeed;
30*8873Smckusick int Wrap;
31*8873Smckusick short *ref[24];
32*8873Smckusick static char flavor[]={
33*8873Smckusick     'O', '*', '#', '$', '%', '0'
34*8873Smckusick };
35*8873Smckusick static short xinc[]={
36*8873Smckusick      1,  1,  1,  0, -1, -1, -1,  0
37*8873Smckusick }, yinc[]={
38*8873Smckusick     -1,  0,  1,  1,  1,  0, -1, -1
39*8873Smckusick };
40*8873Smckusick static struct worm {
41*8873Smckusick     int orientation, head;
42*8873Smckusick     short *xpos, *ypos;
43*8873Smckusick } worm[40];
44*8873Smckusick static char *field;
45*8873Smckusick static int length=16, number=3, trail=' ';
46*8873Smckusick static struct options {
47*8873Smckusick     int nopts;
48*8873Smckusick     int opts[3];
49*8873Smckusick } normal[8]={
50*8873Smckusick     { 3, { 7, 0, 1 } },
51*8873Smckusick     { 3, { 0, 1, 2 } },
52*8873Smckusick     { 3, { 1, 2, 3 } },
53*8873Smckusick     { 3, { 2, 3, 4 } },
54*8873Smckusick     { 3, { 3, 4, 5 } },
55*8873Smckusick     { 3, { 4, 5, 6 } },
56*8873Smckusick     { 3, { 5, 6, 7 } },
57*8873Smckusick     { 3, { 6, 7, 0 } }
58*8873Smckusick }, upper[8]={
59*8873Smckusick     { 1, { 1, 0, 0 } },
60*8873Smckusick     { 2, { 1, 2, 0 } },
61*8873Smckusick     { 0, { 0, 0, 0 } },
62*8873Smckusick     { 0, { 0, 0, 0 } },
63*8873Smckusick     { 0, { 0, 0, 0 } },
64*8873Smckusick     { 2, { 4, 5, 0 } },
65*8873Smckusick     { 1, { 5, 0, 0 } },
66*8873Smckusick     { 2, { 1, 5, 0 } }
67*8873Smckusick }, left[8]={
68*8873Smckusick     { 0, { 0, 0, 0 } },
69*8873Smckusick     { 0, { 0, 0, 0 } },
70*8873Smckusick     { 0, { 0, 0, 0 } },
71*8873Smckusick     { 2, { 2, 3, 0 } },
72*8873Smckusick     { 1, { 3, 0, 0 } },
73*8873Smckusick     { 2, { 3, 7, 0 } },
74*8873Smckusick     { 1, { 7, 0, 0 } },
75*8873Smckusick     { 2, { 7, 0, 0 } }
76*8873Smckusick }, right[8]={
77*8873Smckusick     { 1, { 7, 0, 0 } },
78*8873Smckusick     { 2, { 3, 7, 0 } },
79*8873Smckusick     { 1, { 3, 0, 0 } },
80*8873Smckusick     { 2, { 3, 4, 0 } },
81*8873Smckusick     { 0, { 0, 0, 0 } },
82*8873Smckusick     { 0, { 0, 0, 0 } },
83*8873Smckusick     { 0, { 0, 0, 0 } },
84*8873Smckusick     { 2, { 6, 7, 0 } }
85*8873Smckusick }, lower[8]={
86*8873Smckusick     { 0, { 0, 0, 0 } },
87*8873Smckusick     { 2, { 0, 1, 0 } },
88*8873Smckusick     { 1, { 1, 0, 0 } },
89*8873Smckusick     { 2, { 1, 5, 0 } },
90*8873Smckusick     { 1, { 5, 0, 0 } },
91*8873Smckusick     { 2, { 5, 6, 0 } },
92*8873Smckusick     { 0, { 0, 0, 0 } },
93*8873Smckusick     { 0, { 0, 0, 0 } }
94*8873Smckusick }, upleft[8]={
95*8873Smckusick     { 0, { 0, 0, 0 } },
96*8873Smckusick     { 0, { 0, 0, 0 } },
97*8873Smckusick     { 0, { 0, 0, 0 } },
98*8873Smckusick     { 0, { 0, 0, 0 } },
99*8873Smckusick     { 0, { 0, 0, 0 } },
100*8873Smckusick     { 1, { 3, 0, 0 } },
101*8873Smckusick     { 2, { 1, 3, 0 } },
102*8873Smckusick     { 1, { 1, 0, 0 } }
103*8873Smckusick }, upright[8]={
104*8873Smckusick     { 2, { 3, 5, 0 } },
105*8873Smckusick     { 1, { 3, 0, 0 } },
106*8873Smckusick     { 0, { 0, 0, 0 } },
107*8873Smckusick     { 0, { 0, 0, 0 } },
108*8873Smckusick     { 0, { 0, 0, 0 } },
109*8873Smckusick     { 0, { 0, 0, 0 } },
110*8873Smckusick     { 0, { 0, 0, 0 } },
111*8873Smckusick     { 1, { 5, 0, 0 } }
112*8873Smckusick }, lowleft[8]={
113*8873Smckusick     { 3, { 7, 0, 1 } },
114*8873Smckusick     { 0, { 0, 0, 0 } },
115*8873Smckusick     { 0, { 0, 0, 0 } },
116*8873Smckusick     { 1, { 1, 0, 0 } },
117*8873Smckusick     { 2, { 1, 7, 0 } },
118*8873Smckusick     { 1, { 7, 0, 0 } },
119*8873Smckusick     { 0, { 0, 0, 0 } },
120*8873Smckusick     { 0, { 0, 0, 0 } }
121*8873Smckusick }, lowright[8]={
122*8873Smckusick     { 0, { 0, 0, 0 } },
123*8873Smckusick     { 1, { 7, 0, 0 } },
124*8873Smckusick     { 2, { 5, 7, 0 } },
125*8873Smckusick     { 1, { 5, 0, 0 } },
126*8873Smckusick     { 0, { 0, 0, 0 } },
127*8873Smckusick     { 0, { 0, 0, 0 } },
128*8873Smckusick     { 0, { 0, 0, 0 } },
129*8873Smckusick     { 0, { 0, 0, 0 } }
130*8873Smckusick };
131*8873Smckusick main(argc,argv)
132*8873Smckusick int argc;
133*8873Smckusick char *argv[];
134*8873Smckusick {
135*8873Smckusick     extern fputchar();
136*8873Smckusick     char *malloc();
137*8873Smckusick     char *getenv();
138*8873Smckusick     char *tgetstr(), *tgoto();
139*8873Smckusick     float ranf();
140*8873Smckusick     register int x, y;
141*8873Smckusick     register int n;
142*8873Smckusick     register struct worm *w;
143*8873Smckusick     register struct options *op;
144*8873Smckusick     register int h;
145*8873Smckusick     register short *ip;
146*8873Smckusick     char *AL, *BC, *CM, *EI, *HO, *IC, *IM, *IP, *SR;
147*8873Smckusick     int CO, IN, LI, last, bottom;
148*8873Smckusick     char *tcp;
149*8873Smckusick     register char *term;
150*8873Smckusick     char tcb[100];
151*8873Smckusick     struct sgttyb sg;
152*8873Smckusick     setbuf(stdout,malloc(BUFSIZ));
153*8873Smckusick     for (x=1;x<argc;x++) {
154*8873Smckusick 	register char *p;
155*8873Smckusick 	p=argv[x];
156*8873Smckusick 	if (*p=='-') p++;
157*8873Smckusick 	switch (*p) {
158*8873Smckusick 	case 'f':
159*8873Smckusick 	    field="WORM";
160*8873Smckusick 	    break;
161*8873Smckusick 	case 'l':
162*8873Smckusick 	    if (++x==argc) goto usage;
163*8873Smckusick 	    if ((length=atoi(argv[x]))<2||length>1024) {
164*8873Smckusick 		fprintf(stderr,"%s: Invalid length\n",*argv);
165*8873Smckusick 		exit(1);
166*8873Smckusick 	    }
167*8873Smckusick 	    break;
168*8873Smckusick 	case 'n':
169*8873Smckusick 	    if (++x==argc) goto usage;
170*8873Smckusick 	    if ((number=atoi(argv[x]))<1||number>40) {
171*8873Smckusick 		fprintf(stderr,"%s: Invalid number of worms\n",*argv);
172*8873Smckusick 		exit(1);
173*8873Smckusick 	    }
174*8873Smckusick 	    break;
175*8873Smckusick 	case 't':
176*8873Smckusick 	    trail='.';
177*8873Smckusick 	    break;
178*8873Smckusick 	default:
179*8873Smckusick 	usage:
180*8873Smckusick 	    fprintf(stderr,
181*8873Smckusick 		"usage: %s [-field] [-length #] [-number #] [-trail]\n",*argv);
182*8873Smckusick 	    exit(1);
183*8873Smckusick 	    break;
184*8873Smckusick 	}
185*8873Smckusick     }
186*8873Smckusick     if (!(term=getenv("TERM"))) {
187*8873Smckusick 	fprintf(stderr,"%s: TERM: parameter not set\n",*argv);
188*8873Smckusick 	exit(1);
189*8873Smckusick     }
190*8873Smckusick     if (tgetent(malloc(1024),term)<=0) {
191*8873Smckusick 	fprintf(stderr,"%s: %s: unknown terminal type\n",*argv,term);
192*8873Smckusick 	exit(1);
193*8873Smckusick     }
194*8873Smckusick     tcp=tcb;
195*8873Smckusick     if (!(CM=tgetstr("cm",&tcp))) {
196*8873Smckusick 	fprintf(stderr,"%s: terminal not capable of cursor motion\n",*argv);
197*8873Smckusick 	exit(1);
198*8873Smckusick     }
199*8873Smckusick     AL=tgetstr("al",&tcp);
200*8873Smckusick     BC=tgetflag("bs") ? "\b" : tgetstr("bc",&tcp);
201*8873Smckusick     if ((CO=tgetnum("co"))<=0) CO=80;
202*8873Smckusick     last=CO-1;
203*8873Smckusick     EI=tgetstr("ei",&tcp);
204*8873Smckusick     HO=tgetstr("ho",&tcp);
205*8873Smckusick     IC=tgetstr("ic",&tcp);
206*8873Smckusick     IM=tgetstr("im",&tcp);
207*8873Smckusick     IN=tgetflag("in");
208*8873Smckusick     IP=tgetstr("ip",&tcp);
209*8873Smckusick     if ((LI=tgetnum("li"))<=0) LI=24;
210*8873Smckusick     bottom=LI-1;
211*8873Smckusick     SR=tgetstr("sr",&tcp);
212*8873Smckusick     UP=tgetstr("up",&tcp);
213*8873Smckusick     gtty(fileno(stdout),&sg);
214*8873Smckusick     ospeed=sg.sg_ospeed;
215*8873Smckusick     Wrap=tgetflag("am");
216*8873Smckusick     ip=(short *)malloc(LI*CO*sizeof (short));
217*8873Smckusick     for (n=0;n<LI;) {
218*8873Smckusick 	ref[n++]=ip; ip+=CO;
219*8873Smckusick     }
220*8873Smckusick     for (ip=ref[0],n=LI*CO;--n>=0;) *ip++=0;
221*8873Smckusick     if (Wrap) ref[bottom][last]=1;
222*8873Smckusick     for (n=number, w= &worm[0];--n>=0;w++) {
223*8873Smckusick 	w->orientation=w->head=0;
224*8873Smckusick 	if (!(ip=(short *)malloc(length*sizeof (short)))) {
225*8873Smckusick 	    fprintf(stderr,"%s: out of memory\n",*argv);
226*8873Smckusick 	    exit(1);
227*8873Smckusick 	}
228*8873Smckusick 	w->xpos=ip;
229*8873Smckusick 	for (x=length;--x>=0;) *ip++ = -1;
230*8873Smckusick 	if (!(ip=(short *)malloc(length*sizeof (short)))) {
231*8873Smckusick 	    fprintf(stderr,"%s: out of memory\n",*argv);
232*8873Smckusick 	    exit(1);
233*8873Smckusick 	}
234*8873Smckusick 	w->ypos=ip;
235*8873Smckusick 	for (y=length;--y>=0;) *ip++ = -1;
236*8873Smckusick     }
237*8873Smckusick     tputs(tgetstr("cl",&tcp),1,fputchar);
238*8873Smckusick     if (field) {
239*8873Smckusick 	register char *p;
240*8873Smckusick 	p=field;
241*8873Smckusick 	for (y=bottom;--y>=0;) {
242*8873Smckusick 	    for (x=CO;--x>=0;) {
243*8873Smckusick 		putchar(*p++);
244*8873Smckusick 		if (!*p) p=field;
245*8873Smckusick 	    }
246*8873Smckusick             if (!Wrap) putchar('\n');
247*8873Smckusick             fflush(stdout);
248*8873Smckusick         }
249*8873Smckusick 	if (Wrap) {
250*8873Smckusick 	    if (IM&&!IN) {
251*8873Smckusick 		for (x=last;--x>0;) {
252*8873Smckusick 		    putchar(*p++);
253*8873Smckusick 		    if (!*p) p=field;
254*8873Smckusick 		}
255*8873Smckusick 		y= *p++; if (!*p) p=field;
256*8873Smckusick 		putchar(*p);
257*8873Smckusick 		if (BC) fputs(BC,stdout);
258*8873Smckusick 		else cursor(last-1,bottom);
259*8873Smckusick 		fputs(IM,stdout);
260*8873Smckusick 		if (IC) tputs(IC,1,fputchar);
261*8873Smckusick 		putchar(y);
262*8873Smckusick 		if (IP) tputs(IP,1,fputchar);
263*8873Smckusick 		fputs(EI,stdout);
264*8873Smckusick 	    }
265*8873Smckusick 	    else if (SR||AL) {
266*8873Smckusick 		if (HO) fputs(HO,stdout);
267*8873Smckusick 		else cursor(0,0);
268*8873Smckusick 		if (SR) tputs(SR,1,fputchar);
269*8873Smckusick 		else tputs(AL,LI,fputchar);
270*8873Smckusick 		for (x=CO;--x>=0;) {
271*8873Smckusick 		    putchar(*p++);
272*8873Smckusick 		    if (!*p) p=field;
273*8873Smckusick 		}
274*8873Smckusick 	    }
275*8873Smckusick 	    else for (x=last;--x>=0;) {
276*8873Smckusick 		    putchar(*p++);
277*8873Smckusick 		    if (!*p) p=field;
278*8873Smckusick 	    }
279*8873Smckusick 	}
280*8873Smckusick 	else for (x=CO;--x>=0;) {
281*8873Smckusick 	    putchar(*p++);
282*8873Smckusick 	    if (!*p) p=field;
283*8873Smckusick 	}
284*8873Smckusick     }
285*8873Smckusick     fflush(stdout);
286*8873Smckusick     for (;;) {
287*8873Smckusick 	for (n=0,w= &worm[0];n<number;n++,w++) {
288*8873Smckusick 	    if ((x=w->xpos[h=w->head])<0) {
289*8873Smckusick 		cursor(x=w->xpos[h]=0,y=w->ypos[h]=bottom);
290*8873Smckusick 		putchar(flavor[n%6]);
291*8873Smckusick 		ref[y][x]++;
292*8873Smckusick 	    }
293*8873Smckusick 	    else y=w->ypos[h];
294*8873Smckusick 	    if (++h==length) h=0;
295*8873Smckusick 	    if (w->xpos[w->head=h]>=0) {
296*8873Smckusick 		register int x1, y1;
297*8873Smckusick 		x1=w->xpos[h]; y1=w->ypos[h];
298*8873Smckusick 		if (--ref[y1][x1]==0) {
299*8873Smckusick 		    cursor(x1,y1); putchar(trail);
300*8873Smckusick 		}
301*8873Smckusick 	    }
302*8873Smckusick             op= &(x==0 ? (y==0 ? upleft : (y==bottom ? lowleft : left)) :
303*8873Smckusick                 (x==last ? (y==0 ? upright : (y==bottom ? lowright : right)) :
304*8873Smckusick 		(y==0 ? upper : (y==bottom ? lower : normal))))[w->orientation];
305*8873Smckusick 	    switch (op->nopts) {
306*8873Smckusick 	    case 0:
307*8873Smckusick 		fflush(stdout);
308*8873Smckusick 		abort();
309*8873Smckusick 		return;
310*8873Smckusick 	    case 1:
311*8873Smckusick 		w->orientation=op->opts[0];
312*8873Smckusick 		break;
313*8873Smckusick 	    default:
314*8873Smckusick 		w->orientation=op->opts[(int)(ranf()*(float)op->nopts)];
315*8873Smckusick 	    }
316*8873Smckusick 	    cursor(x+=xinc[w->orientation], y+=yinc[w->orientation]);
317*8873Smckusick 	    if (!Wrap||x!=last||y!=bottom) putchar(flavor[n%6]);
318*8873Smckusick 	    ref[w->ypos[h]=y][w->xpos[h]=x]++;
319*8873Smckusick 	}
320*8873Smckusick 	fflush(stdout);
321*8873Smckusick     }
322*8873Smckusick }
323*8873Smckusick fputchar(c)
324*8873Smckusick char c;
325*8873Smckusick {
326*8873Smckusick     putchar(c);
327*8873Smckusick }
328*8873Smckusick float ranf() {
329*8873Smckusick     return((float)rand()/2147483647.);
330*8873Smckusick }
331