games: Massive style(9) cleanup commit. Reduces differences to NetBSD.
[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  * $DragonFly: src/games/worms/worms.c,v 1.5 2007/04/18 18:32:12 swildner Exp $
33  */
34
35 /*
36  *
37  *       @@@        @@@    @@@@@@@@@@     @@@@@@@@@@@    @@@@@@@@@@@@
38  *       @@@        @@@   @@@@@@@@@@@@    @@@@@@@@@@@@   @@@@@@@@@@@@@
39  *       @@@        @@@  @@@@      @@@@   @@@@           @@@@ @@@  @@@@
40  *       @@@   @@   @@@  @@@        @@@   @@@            @@@  @@@   @@@
41  *       @@@  @@@@  @@@  @@@        @@@   @@@            @@@  @@@   @@@
42  *       @@@@ @@@@ @@@@  @@@        @@@   @@@            @@@  @@@   @@@
43  *        @@@@@@@@@@@@   @@@@      @@@@   @@@            @@@  @@@   @@@
44  *         @@@@  @@@@     @@@@@@@@@@@@    @@@            @@@  @@@   @@@
45  *          @@    @@       @@@@@@@@@@     @@@            @@@  @@@   @@@
46  *
47  *                               Eric P. Scott
48  *                        Caltech High Energy Physics
49  *                               October, 1980
50  *
51  */
52 #include <sys/types.h>
53 #include <curses.h>
54 #include <err.h>
55 #include <signal.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59
60 static const struct options {
61         int nopts;
62         int opts[3];
63 }
64         normal[8] = {
65         { 3, { 7, 0, 1 } },
66         { 3, { 0, 1, 2 } },
67         { 3, { 1, 2, 3 } },
68         { 3, { 2, 3, 4 } },
69         { 3, { 3, 4, 5 } },
70         { 3, { 4, 5, 6 } },
71         { 3, { 5, 6, 7 } },
72         { 3, { 6, 7, 0 } }
73 },      upper[8] = {
74         { 1, { 1, 0, 0 } },
75         { 2, { 1, 2, 0 } },
76         { 0, { 0, 0, 0 } },
77         { 0, { 0, 0, 0 } },
78         { 0, { 0, 0, 0 } },
79         { 2, { 4, 5, 0 } },
80         { 1, { 5, 0, 0 } },
81         { 2, { 1, 5, 0 } }
82 },
83         left[8] = {
84         { 0, { 0, 0, 0 } },
85         { 0, { 0, 0, 0 } },
86         { 0, { 0, 0, 0 } },
87         { 2, { 2, 3, 0 } },
88         { 1, { 3, 0, 0 } },
89         { 2, { 3, 7, 0 } },
90         { 1, { 7, 0, 0 } },
91         { 2, { 7, 0, 0 } }
92 },
93         right[8] = {
94         { 1, { 7, 0, 0 } },
95         { 2, { 3, 7, 0 } },
96         { 1, { 3, 0, 0 } },
97         { 2, { 3, 4, 0 } },
98         { 0, { 0, 0, 0 } },
99         { 0, { 0, 0, 0 } },
100         { 0, { 0, 0, 0 } },
101         { 2, { 6, 7, 0 } }
102 },
103         lower[8] = {
104         { 0, { 0, 0, 0 } },
105         { 2, { 0, 1, 0 } },
106         { 1, { 1, 0, 0 } },
107         { 2, { 1, 5, 0 } },
108         { 1, { 5, 0, 0 } },
109         { 2, { 5, 6, 0 } },
110         { 0, { 0, 0, 0 } },
111         { 0, { 0, 0, 0 } }
112 },
113         upleft[8] = {
114         { 0, { 0, 0, 0 } },
115         { 0, { 0, 0, 0 } },
116         { 0, { 0, 0, 0 } },
117         { 0, { 0, 0, 0 } },
118         { 0, { 0, 0, 0 } },
119         { 1, { 3, 0, 0 } },
120         { 2, { 1, 3, 0 } },
121         { 1, { 1, 0, 0 } }
122 },
123         upright[8] = {
124         { 2, { 3, 5, 0 } },
125         { 1, { 3, 0, 0 } },
126         { 0, { 0, 0, 0 } },
127         { 0, { 0, 0, 0 } },
128         { 0, { 0, 0, 0 } },
129         { 0, { 0, 0, 0 } },
130         { 0, { 0, 0, 0 } },
131         { 1, { 5, 0, 0 } }
132 },
133         lowleft[8] = {
134         { 3, { 7, 0, 1 } },
135         { 0, { 0, 0, 0 } },
136         { 0, { 0, 0, 0 } },
137         { 1, { 1, 0, 0 } },
138         { 2, { 1, 7, 0 } },
139         { 1, { 7, 0, 0 } },
140         { 0, { 0, 0, 0 } },
141         { 0, { 0, 0, 0 } }
142 },
143         lowright[8] = {
144         { 0, { 0, 0, 0 } },
145         { 1, { 7, 0, 0 } },
146         { 2, { 5, 7, 0 } },
147         { 1, { 5, 0, 0 } },
148         { 0, { 0, 0, 0 } },
149         { 0, { 0, 0, 0 } },
150         { 0, { 0, 0, 0 } },
151         { 0, { 0, 0, 0 } }
152 };
153
154
155 static const char       flavor[] = {
156         'O', '*', '#', '$', '%', '0', '@', '~'
157 };
158 static const short      xinc[] = {
159         1,  1,  1,  0, -1, -1, -1,  0
160 }, yinc[] = {
161         -1,  0,  1,  1,  1,  0, -1, -1
162 };
163 static struct   worm {
164         int orientation, head;
165         short *xpos, *ypos;
166 } *worm;
167
168 volatile sig_atomic_t sig_caught = 0;
169
170 void nomem(void);
171 void onsig(int);
172
173 int
174 main(int argc, char **argv)
175 {
176         int x, y, h, n;
177         struct worm *w;
178         const struct options *op;
179         short *ip;
180         int CO, LI, last, bottom, ch, length, number, trail;
181         short **ref;
182         const char *field;
183         char *mp;
184         unsigned int delay = 0;
185
186         mp = NULL;
187         length = 16;
188         number = 3;
189         trail = ' ';
190         field = NULL;
191         while ((ch = getopt(argc, argv, "d:fl:n:t")) != -1)
192                 switch(ch) {
193                 case 'd':
194                         if ((delay = (unsigned int)strtoul(optarg, NULL, 10)) < 1 || delay > 1000)
195                                 errx(1, "invalid delay (1-1000)");
196                         delay *= 1000;  /* ms -> us */
197                         break;
198                 case 'f':
199                         field = "WORM";
200                         break;
201                 case 'l':
202                         if ((length = atoi(optarg)) < 2 || length > 1024) {
203                                 errx(1, "invalid length (%d - %d).",
204                                      2, 1024);
205                         }
206                         break;
207                 case 'n':
208                         if ((number = atoi(optarg)) < 1) {
209                                 errx(1, "invalid number of worms.");
210                         }
211                         break;
212                 case 't':
213                         trail = '.';
214                         break;
215                 case '?':
216                 default:
217                         (void)fprintf(stderr,
218                             "usage: worms [-ft] [-d delay] [-l length] [-n number]\n");
219                         exit(1);
220                 }
221
222         if (!(worm = malloc((size_t)number *
223             sizeof(struct worm))) || !(mp = malloc((size_t)1024)))
224                 nomem();
225         initscr();
226         CO = COLS;
227         LI = LINES;
228         last = CO - 1;
229         bottom = LI - 1;
230         if (!(ip = malloc((size_t)(LI * CO * sizeof(short)))))
231                 nomem();
232         if (!(ref = malloc((size_t)(LI * sizeof(short *)))))
233                 nomem();
234         for (n = 0; n < LI; ++n) {
235                 ref[n] = ip;
236                 ip += CO;
237         }
238         for (ip = ref[0], n = LI * CO; --n >= 0;)
239                 *ip++ = 0;
240         for (n = number, w = &worm[0]; --n >= 0; w++) {
241                 w->orientation = w->head = 0;
242                 if (!(ip = malloc((size_t)(length * sizeof(short)))))
243                         nomem();
244                 w->xpos = ip;
245                 for (x = length; --x >= 0;)
246                         *ip++ = -1;
247                 if (!(ip = malloc((size_t)(length * sizeof(short)))))
248                         nomem();
249                 w->ypos = ip;
250                 for (y = length; --y >= 0;)
251                         *ip++ = -1;
252         }
253
254         (void)signal(SIGHUP, onsig);
255         (void)signal(SIGINT, onsig);
256         (void)signal(SIGQUIT, onsig);
257         (void)signal(SIGSTOP, onsig);
258         (void)signal(SIGTSTP, onsig);
259         (void)signal(SIGTERM, onsig);
260
261         if (field) {
262                 const char *p = field;
263
264                 for (y = LI; --y >= 0;) {
265                         for (x = CO; --x >= 0;) {
266                                 addch(*p++);
267                                 if (!*p)
268                                         p = field;
269                         }
270                         refresh();
271                 }
272         }
273         for (;;) {
274                 refresh();
275                 if (sig_caught) {
276                         endwin();
277                         exit(0);
278                 }
279                 for (n = 0, w = &worm[0]; n < number; n++, w++) {
280                         if ((x = w->xpos[h = w->head]) < 0) {
281                                 mvaddch(y = w->ypos[h] = bottom,
282                                         x = w->xpos[h] = 0,
283                                         flavor[n % sizeof(flavor)]);
284                                 ref[y][x]++;
285                         }
286                         else
287                                 y = w->ypos[h];
288                         if (++h == length)
289                                 h = 0;
290                         if (w->xpos[w->head = h] >= 0) {
291                                 int x1, y1;
292
293                                 x1 = w->xpos[h];
294                                 y1 = w->ypos[h];
295                                 if (--ref[y1][x1] == 0) {
296                                         mvaddch(y1, x1, trail);
297                                 }
298                         }
299                         op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation];
300                         switch (op->nopts) {
301                         case 0:
302                                 refresh();
303                                 abort();
304                                 return(1);
305                         case 1:
306                                 w->orientation = op->opts[0];
307                                 break;
308                         default:
309                                 w->orientation =
310                                     op->opts[(int)random() % op->nopts];
311                         }
312                         mvaddch(y += yinc[w->orientation],
313                                 x += xinc[w->orientation],
314                                 flavor[n % sizeof(flavor)]);
315                         ref[w->ypos[h] = y][w->xpos[h] = x]++;
316                 }
317                 if (usleep(delay))
318                         onsig(SIGTERM);
319         }
320 }
321
322 void
323 onsig(int signo __unused)
324 {
325         sig_caught = 1;
326 }
327
328 void
329 nomem(void)
330 {
331         errx(1, "not enough memory.");
332 }