Merge branch 'vendor/FILE'
[dragonfly.git] / games / worms / worms.c
1 /*-
2  * Copyright (c) 1980, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#) Copyright (c) 1980, 1993 The Regents of the University of California.  All rights reserved.
30  * @(#)worms.c  8.1 (Berkeley) 5/31/93
31  * $FreeBSD: src/games/worms/worms.c,v 1.8.2.1 2000/12/04 10:36:17 alex Exp $
32  */
33
34 /*
35  *
36  *       @@@        @@@    @@@@@@@@@@     @@@@@@@@@@@    @@@@@@@@@@@@
37  *       @@@        @@@   @@@@@@@@@@@@    @@@@@@@@@@@@   @@@@@@@@@@@@@
38  *       @@@        @@@  @@@@      @@@@   @@@@           @@@@ @@@  @@@@
39  *       @@@   @@   @@@  @@@        @@@   @@@            @@@  @@@   @@@
40  *       @@@  @@@@  @@@  @@@        @@@   @@@            @@@  @@@   @@@
41  *       @@@@ @@@@ @@@@  @@@        @@@   @@@            @@@  @@@   @@@
42  *        @@@@@@@@@@@@   @@@@      @@@@   @@@            @@@  @@@   @@@
43  *         @@@@  @@@@     @@@@@@@@@@@@    @@@            @@@  @@@   @@@
44  *          @@    @@       @@@@@@@@@@     @@@            @@@  @@@   @@@
45  *
46  *                               Eric P. Scott
47  *                        Caltech High Energy Physics
48  *                               October, 1980
49  *
50  */
51 #include <sys/types.h>
52 #include <curses.h>
53 #include <err.h>
54 #include <signal.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <unistd.h>
58
59 static const struct options {
60         int nopts;
61         int opts[3];
62 }
63         normal[8] = {
64         { 3, { 7, 0, 1 } },
65         { 3, { 0, 1, 2 } },
66         { 3, { 1, 2, 3 } },
67         { 3, { 2, 3, 4 } },
68         { 3, { 3, 4, 5 } },
69         { 3, { 4, 5, 6 } },
70         { 3, { 5, 6, 7 } },
71         { 3, { 6, 7, 0 } }
72 },      upper[8] = {
73         { 1, { 1, 0, 0 } },
74         { 2, { 1, 2, 0 } },
75         { 0, { 0, 0, 0 } },
76         { 0, { 0, 0, 0 } },
77         { 0, { 0, 0, 0 } },
78         { 2, { 4, 5, 0 } },
79         { 1, { 5, 0, 0 } },
80         { 2, { 1, 5, 0 } }
81 },
82         left[8] = {
83         { 0, { 0, 0, 0 } },
84         { 0, { 0, 0, 0 } },
85         { 0, { 0, 0, 0 } },
86         { 2, { 2, 3, 0 } },
87         { 1, { 3, 0, 0 } },
88         { 2, { 3, 7, 0 } },
89         { 1, { 7, 0, 0 } },
90         { 2, { 7, 0, 0 } }
91 },
92         right[8] = {
93         { 1, { 7, 0, 0 } },
94         { 2, { 3, 7, 0 } },
95         { 1, { 3, 0, 0 } },
96         { 2, { 3, 4, 0 } },
97         { 0, { 0, 0, 0 } },
98         { 0, { 0, 0, 0 } },
99         { 0, { 0, 0, 0 } },
100         { 2, { 6, 7, 0 } }
101 },
102         lower[8] = {
103         { 0, { 0, 0, 0 } },
104         { 2, { 0, 1, 0 } },
105         { 1, { 1, 0, 0 } },
106         { 2, { 1, 5, 0 } },
107         { 1, { 5, 0, 0 } },
108         { 2, { 5, 6, 0 } },
109         { 0, { 0, 0, 0 } },
110         { 0, { 0, 0, 0 } }
111 },
112         upleft[8] = {
113         { 0, { 0, 0, 0 } },
114         { 0, { 0, 0, 0 } },
115         { 0, { 0, 0, 0 } },
116         { 0, { 0, 0, 0 } },
117         { 0, { 0, 0, 0 } },
118         { 1, { 3, 0, 0 } },
119         { 2, { 1, 3, 0 } },
120         { 1, { 1, 0, 0 } }
121 },
122         upright[8] = {
123         { 2, { 3, 5, 0 } },
124         { 1, { 3, 0, 0 } },
125         { 0, { 0, 0, 0 } },
126         { 0, { 0, 0, 0 } },
127         { 0, { 0, 0, 0 } },
128         { 0, { 0, 0, 0 } },
129         { 0, { 0, 0, 0 } },
130         { 1, { 5, 0, 0 } }
131 },
132         lowleft[8] = {
133         { 3, { 7, 0, 1 } },
134         { 0, { 0, 0, 0 } },
135         { 0, { 0, 0, 0 } },
136         { 1, { 1, 0, 0 } },
137         { 2, { 1, 7, 0 } },
138         { 1, { 7, 0, 0 } },
139         { 0, { 0, 0, 0 } },
140         { 0, { 0, 0, 0 } }
141 },
142         lowright[8] = {
143         { 0, { 0, 0, 0 } },
144         { 1, { 7, 0, 0 } },
145         { 2, { 5, 7, 0 } },
146         { 1, { 5, 0, 0 } },
147         { 0, { 0, 0, 0 } },
148         { 0, { 0, 0, 0 } },
149         { 0, { 0, 0, 0 } },
150         { 0, { 0, 0, 0 } }
151 };
152
153
154 static const char       flavor[] = {
155         'O', '*', '#', '$', '%', '0', '@', '~'
156 };
157 static const short      xinc[] = {
158         1,  1,  1,  0, -1, -1, -1,  0
159 }, yinc[] = {
160         -1,  0,  1,  1,  1,  0, -1, -1
161 };
162 static struct   worm {
163         int orientation, head;
164         short *xpos, *ypos;
165 } *worm;
166
167 static volatile sig_atomic_t sig_caught = 0;
168
169 static void nomem(void) __dead2;
170 static void onsig(int);
171
172 int
173 main(int argc, char **argv)
174 {
175         int x, y, h, n;
176         struct worm *w;
177         const struct options *op;
178         short *ip;
179         int CO, LI, last, bottom, ch, length, number, trail;
180         short **ref;
181         const char *field;
182         char *mp;
183         unsigned int delay = 0;
184
185         mp = NULL;
186         length = 16;
187         number = 3;
188         trail = ' ';
189         field = NULL;
190         while ((ch = getopt(argc, argv, "d:fl:n:t")) != -1)
191                 switch(ch) {
192                 case 'd':
193                         if ((delay = (unsigned int)strtoul(optarg, NULL, 10)) < 1 || delay > 1000)
194                                 errx(1, "invalid delay (1-1000)");
195                         delay *= 1000;  /* ms -> us */
196                         break;
197                 case 'f':
198                         field = "WORM";
199                         break;
200                 case 'l':
201                         if ((length = atoi(optarg)) < 2 || length > 1024) {
202                                 errx(1, "invalid length (%d - %d).",
203                                      2, 1024);
204                         }
205                         break;
206                 case 'n':
207                         if ((number = atoi(optarg)) < 1) {
208                                 errx(1, "invalid number of worms.");
209                         }
210                         break;
211                 case 't':
212                         trail = '.';
213                         break;
214                 case '?':
215                 default:
216                         fprintf(stderr,
217                             "usage: worms [-ft] [-d delay] [-l length] [-n number]\n");
218                         exit(1);
219                 }
220
221         if (!(worm = malloc((size_t)number *
222             sizeof(struct worm))) || !(mp = malloc((size_t)1024)))
223                 nomem();
224         initscr();
225         CO = COLS;
226         LI = LINES;
227         last = CO - 1;
228         bottom = LI - 1;
229         if (!(ip = malloc((size_t)(LI * CO * sizeof(short)))))
230                 nomem();
231         if (!(ref = malloc((size_t)(LI * sizeof(short *)))))
232                 nomem();
233         for (n = 0; n < LI; ++n) {
234                 ref[n] = ip;
235                 ip += CO;
236         }
237         for (ip = ref[0], n = LI * CO; --n >= 0;)
238                 *ip++ = 0;
239         for (n = number, w = &worm[0]; --n >= 0; w++) {
240                 w->orientation = w->head = 0;
241                 if (!(ip = malloc((size_t)(length * sizeof(short)))))
242                         nomem();
243                 w->xpos = ip;
244                 for (x = length; --x >= 0;)
245                         *ip++ = -1;
246                 if (!(ip = malloc((size_t)(length * sizeof(short)))))
247                         nomem();
248                 w->ypos = ip;
249                 for (y = length; --y >= 0;)
250                         *ip++ = -1;
251         }
252
253         signal(SIGHUP, onsig);
254         signal(SIGINT, onsig);
255         signal(SIGQUIT, onsig);
256         signal(SIGSTOP, onsig);
257         signal(SIGTSTP, onsig);
258         signal(SIGTERM, onsig);
259
260         if (field) {
261                 const char *p = field;
262
263                 for (y = LI; --y >= 0;) {
264                         for (x = CO; --x >= 0;) {
265                                 addch(*p++);
266                                 if (!*p)
267                                         p = field;
268                         }
269                         refresh();
270                 }
271         }
272         for (;;) {
273                 refresh();
274                 if (sig_caught) {
275                         endwin();
276                         exit(0);
277                 }
278                 for (n = 0, w = &worm[0]; n < number; n++, w++) {
279                         if ((x = w->xpos[h = w->head]) < 0) {
280                                 mvaddch(y = w->ypos[h] = bottom,
281                                         x = w->xpos[h] = 0,
282                                         flavor[n % sizeof(flavor)]);
283                                 ref[y][x]++;
284                         }
285                         else
286                                 y = w->ypos[h];
287                         if (++h == length)
288                                 h = 0;
289                         if (w->xpos[w->head = h] >= 0) {
290                                 int x1, y1;
291
292                                 x1 = w->xpos[h];
293                                 y1 = w->ypos[h];
294                                 if (--ref[y1][x1] == 0) {
295                                         mvaddch(y1, x1, trail);
296                                 }
297                         }
298                         op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation];
299                         switch (op->nopts) {
300                         case 0:
301                                 refresh();
302                                 abort();
303                                 return(1);
304                         case 1:
305                                 w->orientation = op->opts[0];
306                                 break;
307                         default:
308                                 w->orientation =
309                                     op->opts[(int)random() % op->nopts];
310                         }
311                         mvaddch(y += yinc[w->orientation],
312                                 x += xinc[w->orientation],
313                                 flavor[n % sizeof(flavor)]);
314                         ref[w->ypos[h] = y][w->xpos[h] = x]++;
315                 }
316                 if (usleep(delay))
317                         onsig(SIGTERM);
318         }
319 }
320
321 static void
322 onsig(int signo __unused)
323 {
324         sig_caught = 1;
325 }
326
327 static void
328 nomem(void)
329 {
330         errx(1, "not enough memory.");
331 }