source: trunk/ncurses/test/worm.c@ 2787

Last change on this file since 2787 was 2621, checked in by bird, 19 years ago

GNU ncurses 5.5

File size: 9.3 KB
Line 
1/*
2
3 @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@
4 @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@
5 @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@
6 @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
7 @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@
8 @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@
9 @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@
10 @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@
11 @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@
12
13 Eric P. Scott
14 Caltech High Energy Physics
15 October, 1980
16
17 Hacks to turn this into a test frame for cursor movement:
18 Eric S. Raymond <esr@snark.thyrsus.com>
19 January, 1995
20
21 July 1995 (esr): worms is now in living color! :-)
22
23Options:
24 -f fill screen with copies of 'WORM' at start.
25 -l <n> set worm length
26 -n <n> set number of worms
27 -t make worms leave droppings
28 -T <start> <end> set trace interval
29 -S set single-stepping during trace interval
30 -N suppress cursor-movement optimization
31
32 This program makes a good torture-test for the ncurses cursor-optimization
33 code. You can use -T to set the worm move interval over which movement
34 traces will be dumped. The program stops and waits for one character of
35 input at the beginning and end of the interval.
36
37 $Id: worm.c,v 1.39 2005/08/20 20:26:29 tom Exp $
38*/
39
40#include <test.priv.h>
41
42static chtype flavor[] =
43{
44 'O', '*', '#', '$', '%', '0', '@',
45};
46static const short xinc[] =
47{
48 1, 1, 1, 0, -1, -1, -1, 0
49}, yinc[] =
50{
51 -1, 0, 1, 1, 1, 0, -1, -1
52};
53static struct worm {
54 int orientation, head;
55 short *xpos, *ypos;
56} worm[40];
57
58static const char *field;
59static int length = 16, number = 3;
60static chtype trail = ' ';
61
62#ifdef TRACE
63static int generation, trace_start, trace_end, singlestep;
64#endif /* TRACE */
65/* *INDENT-OFF* */
66static const struct options {
67 int nopts;
68 int opts[3];
69} normal[8]={
70 { 3, { 7, 0, 1 } },
71 { 3, { 0, 1, 2 } },
72 { 3, { 1, 2, 3 } },
73 { 3, { 2, 3, 4 } },
74 { 3, { 3, 4, 5 } },
75 { 3, { 4, 5, 6 } },
76 { 3, { 5, 6, 7 } },
77 { 3, { 6, 7, 0 } }
78}, upper[8]={
79 { 1, { 1, 0, 0 } },
80 { 2, { 1, 2, 0 } },
81 { 0, { 0, 0, 0 } },
82 { 0, { 0, 0, 0 } },
83 { 0, { 0, 0, 0 } },
84 { 2, { 4, 5, 0 } },
85 { 1, { 5, 0, 0 } },
86 { 2, { 1, 5, 0 } }
87}, left[8]={
88 { 0, { 0, 0, 0 } },
89 { 0, { 0, 0, 0 } },
90 { 0, { 0, 0, 0 } },
91 { 2, { 2, 3, 0 } },
92 { 1, { 3, 0, 0 } },
93 { 2, { 3, 7, 0 } },
94 { 1, { 7, 0, 0 } },
95 { 2, { 7, 0, 0 } }
96}, right[8]={
97 { 1, { 7, 0, 0 } },
98 { 2, { 3, 7, 0 } },
99 { 1, { 3, 0, 0 } },
100 { 2, { 3, 4, 0 } },
101 { 0, { 0, 0, 0 } },
102 { 0, { 0, 0, 0 } },
103 { 0, { 0, 0, 0 } },
104 { 2, { 6, 7, 0 } }
105}, lower[8]={
106 { 0, { 0, 0, 0 } },
107 { 2, { 0, 1, 0 } },
108 { 1, { 1, 0, 0 } },
109 { 2, { 1, 5, 0 } },
110 { 1, { 5, 0, 0 } },
111 { 2, { 5, 6, 0 } },
112 { 0, { 0, 0, 0 } },
113 { 0, { 0, 0, 0 } }
114}, upleft[8]={
115 { 0, { 0, 0, 0 } },
116 { 0, { 0, 0, 0 } },
117 { 0, { 0, 0, 0 } },
118 { 0, { 0, 0, 0 } },
119 { 0, { 0, 0, 0 } },
120 { 1, { 3, 0, 0 } },
121 { 2, { 1, 3, 0 } },
122 { 1, { 1, 0, 0 } }
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}, 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}, lowright[8]={
142 { 0, { 0, 0, 0 } },
143 { 1, { 7, 0, 0 } },
144 { 2, { 5, 7, 0 } },
145 { 1, { 5, 0, 0 } },
146 { 0, { 0, 0, 0 } },
147 { 0, { 0, 0, 0 } },
148 { 0, { 0, 0, 0 } },
149 { 0, { 0, 0, 0 } }
150};
151/* *INDENT-ON* */
152
153static void
154cleanup(void)
155{
156 standend();
157 refresh();
158 curs_set(1);
159 endwin();
160}
161
162static RETSIGTYPE
163onsig(int sig GCC_UNUSED)
164{
165 cleanup();
166 ExitProgram(EXIT_FAILURE);
167}
168
169static float
170ranf(void)
171{
172 long r = (rand() & 077777);
173 return ((float) r / 32768.);
174}
175
176int
177main(int argc, char *argv[])
178{
179 short **ref;
180 int x, y;
181 int n;
182 struct worm *w;
183 const struct options *op;
184 int h;
185 short *ip;
186 int last, bottom;
187
188 setlocale(LC_ALL, "");
189
190 for (x = 1; x < argc; x++) {
191 char *p;
192 p = argv[x];
193 if (*p == '-')
194 p++;
195 switch (*p) {
196 case 'f':
197 field = "WORM";
198 break;
199 case 'l':
200 if (++x == argc)
201 goto usage;
202 if ((length = atoi(argv[x])) < 2 || length > 1024) {
203 fprintf(stderr, "%s: Invalid length\n", *argv);
204 ExitProgram(EXIT_FAILURE);
205 }
206 break;
207 case 'n':
208 if (++x == argc)
209 goto usage;
210 if ((number = atoi(argv[x])) < 1 || number > 40) {
211 fprintf(stderr, "%s: Invalid number of worms\n", *argv);
212 ExitProgram(EXIT_FAILURE);
213 }
214 break;
215 case 't':
216 trail = '.';
217 break;
218#ifdef TRACE
219 case 'S':
220 singlestep = TRUE;
221 break;
222 case 'T':
223 trace_start = atoi(argv[++x]);
224 trace_end = atoi(argv[++x]);
225 break;
226 case 'N':
227 _nc_optimize_enable ^= OPTIMIZE_ALL; /* declared by ncurses */
228 break;
229#endif /* TRACE */
230 default:
231 usage:
232 fprintf(stderr,
233 "usage: %s [-field] [-length #] [-number #] [-trail]\n", *argv);
234 ExitProgram(EXIT_FAILURE);
235 }
236 }
237
238 signal(SIGINT, onsig);
239 initscr();
240 noecho();
241 cbreak();
242 nonl();
243
244 curs_set(0);
245
246 bottom = LINES - 1;
247 last = COLS - 1;
248
249#ifdef A_COLOR
250 if (has_colors()) {
251 int bg = COLOR_BLACK;
252 start_color();
253#if HAVE_USE_DEFAULT_COLORS
254 if (use_default_colors() == OK)
255 bg = -1;
256#endif
257
258#define SET_COLOR(num, fg) \
259 init_pair(num+1, fg, bg); \
260 flavor[num] |= COLOR_PAIR(num+1) | A_BOLD
261
262 SET_COLOR(0, COLOR_GREEN);
263 SET_COLOR(1, COLOR_RED);
264 SET_COLOR(2, COLOR_CYAN);
265 SET_COLOR(3, COLOR_WHITE);
266 SET_COLOR(4, COLOR_MAGENTA);
267 SET_COLOR(5, COLOR_BLUE);
268 SET_COLOR(6, COLOR_YELLOW);
269 }
270#endif /* A_COLOR */
271
272 ref = typeMalloc(short *, LINES);
273 for (y = 0; y < LINES; y++) {
274 ref[y] = typeMalloc(short, COLS);
275 for (x = 0; x < COLS; x++) {
276 ref[y][x] = 0;
277 }
278 }
279
280#ifdef BADCORNER
281 /* if addressing the lower right corner doesn't work in your curses */
282 ref[bottom][last] = 1;
283#endif /* BADCORNER */
284
285 for (n = number, w = &worm[0]; --n >= 0; w++) {
286 w->orientation = w->head = 0;
287 if (!(ip = typeMalloc(short, (length + 1)))) {
288 fprintf(stderr, "%s: out of memory\n", *argv);
289 ExitProgram(EXIT_FAILURE);
290 }
291 w->xpos = ip;
292 for (x = length; --x >= 0;)
293 *ip++ = -1;
294 if (!(ip = typeMalloc(short, (length + 1)))) {
295 fprintf(stderr, "%s: out of memory\n", *argv);
296 ExitProgram(EXIT_FAILURE);
297 }
298 w->ypos = ip;
299 for (y = length; --y >= 0;)
300 *ip++ = -1;
301 }
302 if (field) {
303 const char *p;
304 p = field;
305 for (y = bottom; --y >= 0;) {
306 for (x = COLS; --x >= 0;) {
307 addch((chtype) (*p++));
308 if (!*p)
309 p = field;
310 }
311 }
312 }
313 napms(10);
314 refresh();
315#ifndef TRACE
316 nodelay(stdscr, TRUE);
317#endif
318
319 for (;;) {
320#ifdef TRACE
321 if (trace_start || trace_end) {
322 if (generation == trace_start) {
323 trace(TRACE_CALLS);
324 getch();
325 } else if (generation == trace_end) {
326 trace(0);
327 getch();
328 }
329
330 if (singlestep && generation > trace_start && generation < trace_end)
331 getch();
332
333 generation++;
334 }
335#else
336 int ch;
337
338 if ((ch = getch()) > 0) {
339#ifdef KEY_RESIZE
340 if (ch == KEY_RESIZE) {
341 if (last != COLS - 1) {
342 for (y = 0; y <= bottom; y++) {
343 ref[y] = typeRealloc(short, COLS, ref[y]);
344 for (x = last + 1; x < COLS; x++)
345 ref[y][x] = 0;
346 }
347 last = COLS - 1;
348 }
349 if (bottom != LINES - 1) {
350 for (y = LINES; y <= bottom; y++)
351 free(ref[y]);
352 ref = typeRealloc(short *, LINES, ref);
353 for (y = bottom + 1; y < LINES; y++) {
354 ref[y] = typeMalloc(short, COLS);
355 for (x = 0; x < COLS; x++)
356 ref[y][x] = 0;
357 }
358 bottom = LINES - 1;
359 }
360 }
361#endif
362 /*
363 * Make it simple to put this into single-step mode, or resume
364 * normal operation -T.Dickey
365 */
366 if (ch == 'q') {
367 cleanup();
368 ExitProgram(EXIT_SUCCESS);
369 } else if (ch == 's') {
370 nodelay(stdscr, FALSE);
371 } else if (ch == ' ') {
372 nodelay(stdscr, TRUE);
373 }
374 }
375#endif /* TRACE */
376
377 for (n = 0, w = &worm[0]; n < number; n++, w++) {
378 if ((x = w->xpos[h = w->head]) < 0) {
379 move(y = w->ypos[h] = bottom, x = w->xpos[h] = 0);
380 addch(flavor[n % SIZEOF(flavor)]);
381 ref[y][x]++;
382 } else {
383 y = w->ypos[h];
384 }
385 if (x > last)
386 x = last;
387 if (y > bottom)
388 y = bottom;
389 if (++h == length)
390 h = 0;
391 if (w->xpos[w->head = h] >= 0) {
392 int x1, y1;
393 x1 = w->xpos[h];
394 y1 = w->ypos[h];
395 if (y1 < LINES
396 && x1 < COLS
397 && --ref[y1][x1] == 0) {
398 move(y1, x1);
399 addch(trail);
400 }
401 }
402 op = &(x == 0 ? (y == 0 ? upleft : (y == bottom ? lowleft :
403 left)) :
404 (x == last ? (y == 0 ? upright : (y == bottom ? lowright :
405 right)) :
406 (y == 0 ? upper : (y == bottom ? lower : normal))))[w->orientation];
407 switch (op->nopts) {
408 case 0:
409 cleanup();
410 ExitProgram(EXIT_SUCCESS);
411 case 1:
412 w->orientation = op->opts[0];
413 break;
414 default:
415 w->orientation = op->opts[(int) (ranf() * (float) op->nopts)];
416 }
417 move(y += yinc[w->orientation], x += xinc[w->orientation]);
418
419 if (y < 0)
420 y = 0;
421 addch(flavor[n % SIZEOF(flavor)]);
422 ref[w->ypos[h] = y][w->xpos[h] = x]++;
423 }
424 napms(10);
425 refresh();
426 }
427}
Note: See TracBrowser for help on using the repository browser.