d5070d24a0305a6445abd1857c891da376973ba6
[xscreensaver] / hacks / ant.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /*-
3  * ant --- Chris Langton's generalized turing machine ants (also known
4  *         as Greg Turk's turmites) whose tape is the screen
5  */
6
7 #if !defined( lint ) && !defined( SABER )
8 static const char sccsid[] = "@(#)ant.c 4.04 97/07/28 xlockmore";
9
10 #endif
11
12 /*-
13  * Copyright (c) 1995 by David Bagley.
14  *
15  * Permission to use, copy, modify, and distribute this software and its
16  * documentation for any purpose and without fee is hereby granted,
17  * provided that the above copyright notice appear in all copies and that
18  * both that copyright notice and this permission notice appear in
19  * supporting documentation.
20  *
21  * This file is provided AS IS with no warranties of any kind.  The author
22  * shall have no liability with respect to the infringement of copyrights,
23  * trade secrets or any patents by this file or any part thereof.  In no
24  * event will the author be liable for any lost revenue or profits or
25  * other special, indirect and consequential damages.
26  *
27  * Revision History:
28  * 10-May-97: Compatible with xscreensaver
29  * 16-Apr-97: -neighbors 3 and 8 added
30  * 01-Jan-97: Updated ant.c to handle more kinds of ants.  Thanks to
31  *            J Austin David <Austin.David@tlogic.com>.  Check it out in
32  *            java at http://havoc.gtf.gatech.edu/austin  He thought up the
33  *            new Ladder ant.
34  * 04-Apr-96: -neighbors 6 runtime-time option added for hexagonal ants
35  *            (bees), coded from an idea of Jim Propp's in Science News,
36  *            Oct 28, 1995 VOL. 148 page 287
37  * 20-Sep-95: Memory leak in ant fixed.  Now random colors.
38  * 05-Sep-95: Coded from A.K. Dewdney's "Computer Recreations", Scientific
39  *            American Magazine" Sep 1989 pp 180-183, Mar 1990 p 121
40  *            Also used Ian Stewart's Mathematical Recreations, Scientific
41  *            American Jul 1994 pp 104-107
42  *            also used demon.c and life.c as a guide.
43  */
44
45 /*-
46   Species Grid     Number of Neigbors
47   ------- ----     ------------------
48   Ants    Square   4 or 8
49   Bees    Hexagon  6
50   Bees    Triangle 3 (9? or 12) <- 9 and 12 are not implemented
51
52   Neighbors 6 and neighbors 3 produce the same Turk ants.
53 */
54
55 #ifdef STANDALONE
56 # define PROGCLASS "Ant"
57 # define HACK_INIT init_ant
58 # define HACK_DRAW draw_ant
59 # define ant_opts xlockmore_opts
60 # define DEFAULTS       "*delay:   1000 \n"             \
61                                         "*count:  -3 \n"                \
62                                         "*cycles:  40000 \n"    \
63                                         "*size:   -7 \n"                \
64                                         "*ncolors: 64 \n"
65 # include "xlockmore.h"         /* in xscreensaver distribution */
66 # include "erase.h"
67 #else /* STANDALONE */
68 # include "xlock.h"             /* in xlockmore distribution */
69
70 #endif /* STANDALONE */
71
72 #define DEF_TRUCHET  "True"
73
74 #ifdef STANDALONE
75 static int neighbors;
76 #else
77 extern int  neighbors;
78 #endif /* !STANDALONE */
79
80 static Bool truchet;
81
82 static XrmOptionDescRec opts[] =
83 {
84         {"-truchet", ".ant.truchet", XrmoptionNoArg, (caddr_t) "on"},
85         {"+truchet", ".ant.truchet", XrmoptionNoArg, (caddr_t) "off"},
86
87 #ifdef STANDALONE
88         {"-neighbors", ".ant.neighbors", XrmoptionNoArg, (caddr_t) "on"},
89         {"+neighbors", ".ant.neighbors", XrmoptionNoArg, (caddr_t) "off"}
90 #endif /* STANDALONE */
91
92 };
93 static argtype vars[] =
94 {
95         {(caddr_t *) & truchet, "truchet", "Truchet", DEF_TRUCHET, t_Bool},
96 #ifdef STANDALONE
97         {(caddr_t *) & neighbors, "neighbors", "Neighbors", 0, t_Bool}
98 #endif /* STANDALONE */
99 };
100 static OptionStruct desc[] =
101 {
102         {"-/+truchet", "turn on/off Truchet lines"}
103 };
104
105 ModeSpecOpt ant_opts =
106 {2, opts, 1, vars, desc};
107
108
109 #define ANTBITS(n,w,h)\
110   ap->pixmaps[ap->init_bits++]=\
111   XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1)
112
113 /* If you change the table you may have to change the following 2 constants */
114 #define STATES 2
115 #define COLORS 11
116 #define MINANTS 1
117 #define PATTERNSIZE 8
118 #define REDRAWSTEP 2000         /* How much tape to draw per cycle */
119 #define MINGRIDSIZE 24
120 #define MINSIZE 1
121 #define ANGLES 360
122 #define NEIGHBORKINDS 2
123
124 #ifdef STANDALONE
125 static XPoint hexagonUnit[6] =
126 {
127         {0, 0},
128         {1, 1},
129         {0, 2},
130         {-1, 1},
131         {-1, -1},
132         {0, -2}
133 };
134
135 static XPoint triangleUnit[2][3] =
136 {
137         {
138                 {0, 0},
139                 {1, -1},
140                 {0, 2}
141         },
142         {
143                 {0, 0},
144                 {-1, 1},
145                 {0, -2}
146         }
147 };
148
149 #endif /* STANDALONE */
150
151
152 static unsigned char patterns[COLORS - 1][PATTERNSIZE] =
153 {
154         {0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22},       /* grey+white | stripe */
155         {0x00, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00},       /* spots */
156         {0x89, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11},       /* lt. / stripe */
157         {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66},       /* | bars */
158         {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa},       /* 50% grey */
159         {0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00},       /* - bars */
160         {0xee, 0xdd, 0xbb, 0x77, 0xee, 0xdd, 0xbb, 0x76},       /* dark \ stripe */
161         {0xff, 0x99, 0x99, 0xff, 0xff, 0x99, 0x99, 0xff},       /* spots */
162         {0xaa, 0xff, 0xff, 0x55, 0xaa, 0xff, 0xff, 0x55},       /* black+grey - stripe */
163         {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}        /* black */
164 };
165
166 typedef struct {
167         unsigned char color;
168         short       direction;
169         unsigned char next;
170 } statestruct;
171
172 typedef struct {
173         int         col, row;
174         short       direction;
175         unsigned char state;
176 } antstruct;
177
178 typedef struct {
179         int         init_bits;
180         int         neighbors;
181         int         generation;
182         int         xs, ys;
183         int         xb, yb;
184         int         nrows, ncols;
185         int         width, height;
186         unsigned char ncolors, nstates;
187         int         n;
188         int         redrawing, redrawpos;
189         int         truchet;    /* Only for Turk modes */
190         statestruct machine[COLORS * STATES];
191         unsigned char *tape;
192         unsigned char *truchet_state;
193         antstruct  *ants;
194         unsigned char colors[COLORS - 1];
195         GC          stippledGC;
196         Pixmap      pixmaps[COLORS - 1];
197         XPoint      hexagonList[7];
198         XPoint      triangleList[2][4];
199 } antfarmstruct;
200
201 static int  initVal[NEIGHBORKINDS] =
202 {3, 6};                 /* Neighborhoods, 8 just makes a mess */
203
204
205 /* Relative ant moves */
206 #define FS 0                    /* Step */
207 #define TRS 1                   /* Turn right, then step */
208 #define THRS 2                  /* Turn hard right, then step */
209 #define TBS 3                   /* Turn back, then step */
210 #define THLS 4                  /* Turn hard left, then step */
211 #define TLS 5                   /* Turn left, then step */
212 #define SF 6                    /* Step */
213 #define STR 7                   /* Step then turn right */
214 #define STHR 8                  /* Step then turn hard right */
215 #define STB 9                   /* Step then turn back */
216 #define STHL 10                 /* Step then turn hard left */
217 #define STL 11                  /* Step then turn left */
218
219 static antfarmstruct *antfarms = NULL;
220
221 /* LANGTON'S ANT (10) Chaotic after 500, Builder after 10,000 (104p) */
222 /* TURK'S 100 ANT Always chaotic?, tested past 150,000,000 */
223 /* TURK'S 101 ANT Always chaotic? */
224 /* TURK'S 110 ANT Builder at 150 (18p) */
225 /* TURK'S 1000 ANT Always chaotic? */
226 /* TURK'S 1100 SYMMETRIC ANT  all even run 1's and 0's are symmetric */
227 /* other examples 1001, 110011, 110000, 1001101 */
228 /* TURK'S 1101 ANT Builder after 250,000 (388p) */
229 /* Once saw a chess horse type builder (i.e. non-45 degree builder) */
230
231 /* BEE ONLY */
232 /* All alternating 10 appear symmetric, no proof (i.e. 10, 1010, etc) */
233 /* Even runs of 0's and 1's are also symmetric */
234 /* I have seen Hexagonal builders but they are more rare. */
235
236 static unsigned char tables[][3 * COLORS * STATES + 2] =
237 {
238 #if 0
239   /* Here just so you can figure out notation */
240         {                       /* Langton's ant */
241                 2, 1,
242                 1, TLS, 0, 0, TRS, 0
243         },
244 #else
245   /* First 2 numbers are the size (ncolors, nstates) */
246         {                       /* LADDER BUILDER */
247                 4, 1,
248                 1, STR, 0, 2, STL, 0, 3, TRS, 0, 0, TLS, 0
249         },
250         {                       /* SPIRALING PATTERN */
251                 2, 2,
252                 1, TLS, 0, 0, FS, 1,
253                 1, TRS, 0, 1, TRS, 0
254         },
255         {                       /* SQUARE (HEXAGON) BUILDER */
256                 2, 2,
257                 1, TLS, 0, 0, FS, 1,
258                 0, TRS, 0, 1, TRS, 0
259         },
260 #endif
261 };
262
263 #define NTABLES   (sizeof tables / sizeof tables[0])
264
265 static void
266 position_of_neighbor(antfarmstruct * ap, int dir, int *pcol, int *prow)
267 {
268         int         col = *pcol, row = *prow;
269
270         if (ap->neighbors == 6) {
271                 switch (dir) {
272                         case 0:
273                                 col = (col + 1 == ap->ncols) ? 0 : col + 1;
274                                 break;
275                         case 60:
276                                 if (!(row & 1))
277                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
278                                 row = (!row) ? ap->nrows - 1 : row - 1;
279                                 break;
280                         case 120:
281                                 if (row & 1)
282                                         col = (!col) ? ap->ncols - 1 : col - 1;
283                                 row = (!row) ? ap->nrows - 1 : row - 1;
284                                 break;
285                         case 180:
286                                 col = (!col) ? ap->ncols - 1 : col - 1;
287                                 break;
288                         case 240:
289                                 if (row & 1)
290                                         col = (!col) ? ap->ncols - 1 : col - 1;
291                                 row = (row + 1 == ap->nrows) ? 0 : row + 1;
292                                 break;
293                         case 300:
294                                 if (!(row & 1))
295                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
296                                 row = (row + 1 == ap->nrows) ? 0 : row + 1;
297                                 break;
298                         default:
299                                 (void) fprintf(stderr, "wrong direction %d\n", dir);
300                 }
301         } else if (ap->neighbors == 4 || ap->neighbors == 8) {
302                 switch (dir) {
303                         case 0:
304                                 col = (col + 1 == ap->ncols) ? 0 : col + 1;
305                                 break;
306                         case 45:
307                                 col = (col + 1 == ap->ncols) ? 0 : col + 1;
308                                 row = (!row) ? ap->nrows - 1 : row - 1;
309                                 break;
310                         case 90:
311                                 row = (!row) ? ap->nrows - 1 : row - 1;
312                                 break;
313                         case 135:
314                                 col = (!col) ? ap->ncols - 1 : col - 1;
315                                 row = (!row) ? ap->nrows - 1 : row - 1;
316                                 break;
317                         case 180:
318                                 col = (!col) ? ap->ncols - 1 : col - 1;
319                                 break;
320                         case 225:
321                                 col = (!col) ? ap->ncols - 1 : col - 1;
322                                 row = (row + 1 == ap->nrows) ? 0 : row + 1;
323                                 break;
324                         case 270:
325                                 row = (row + 1 == ap->nrows) ? 0 : row + 1;
326                                 break;
327                         case 315:
328                                 col = (col + 1 == ap->ncols) ? 0 : col + 1;
329                                 row = (row + 1 == ap->nrows) ? 0 : row + 1;
330                                 break;
331                         default:
332                                 (void) fprintf(stderr, "wrong direction %d\n", dir);
333                 }
334         } else {                /* TRI */
335                 if ((col + row) % 2) {  /* right */
336                         switch (dir) {
337                                 case 0:
338                                         col = (!col) ? ap->ncols - 1 : col - 1;
339                                         break;
340                                 case 30:
341                                 case 40:
342                                         col = (!col) ? ap->ncols - 1 : col - 1;
343                                         row = (!row) ? ap->nrows - 1 : row - 1;
344                                         break;
345                                 case 60:
346                                         col = (!col) ? ap->ncols - 1 : col - 1;
347                                         if (!row)
348                                                 row = ap->nrows - 2;
349                                         else if (!(row - 1))
350                                                 row = ap->nrows - 1;
351                                         else
352                                                 row = row - 2;
353                                         break;
354                                 case 80:
355                                 case 90:
356                                         if (!row)
357                                                 row = ap->nrows - 2;
358                                         else if (!(row - 1))
359                                                 row = ap->nrows - 1;
360                                         else
361                                                 row = row - 2;
362                                         break;
363                                 case 120:
364                                         row = (!row) ? ap->nrows - 1 : row - 1;
365                                         break;
366                                 case 150:
367                                 case 160:
368                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
369                                         row = (!row) ? ap->nrows - 1 : row - 1;
370                                         break;
371                                 case 180:
372                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
373                                         break;
374                                 case 200:
375                                 case 210:
376                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
377                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
378                                         break;
379                                 case 240:
380                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
381                                         break;
382                                 case 270:
383                                 case 280:
384                                         if (row + 1 == ap->nrows)
385                                                 row = 1;
386                                         else if (row + 2 == ap->nrows)
387                                                 row = 0;
388                                         else
389                                                 row = row + 2;
390                                         break;
391                                 case 300:
392                                         col = (!col) ? ap->ncols - 1 : col - 1;
393                                         if (row + 1 == ap->nrows)
394                                                 row = 1;
395                                         else if (row + 2 == ap->nrows)
396                                                 row = 0;
397                                         else
398                                                 row = row + 2;
399                                         break;
400                                 case 320:
401                                 case 330:
402                                         col = (!col) ? ap->ncols - 1 : col - 1;
403                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
404                                         break;
405                                 default:
406                                         (void) fprintf(stderr, "wrong direction %d\n", dir);
407                         }
408                 } else {        /* left */
409                         switch (dir) {
410                                 case 0:
411                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
412                                         break;
413                                 case 30:
414                                 case 40:
415                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
416                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
417                                         break;
418                                 case 60:
419                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
420                                         if (row + 1 == ap->nrows)
421                                                 row = 1;
422                                         else if (row + 2 == ap->nrows)
423                                                 row = 0;
424                                         else
425                                                 row = row + 2;
426                                         break;
427                                 case 80:
428                                 case 90:
429                                         if (row + 1 == ap->nrows)
430                                                 row = 1;
431                                         else if (row + 2 == ap->nrows)
432                                                 row = 0;
433                                         else
434                                                 row = row + 2;
435                                         break;
436                                 case 120:
437                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
438                                         break;
439                                 case 150:
440                                 case 160:
441                                         col = (!col) ? ap->ncols - 1 : col - 1;
442                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
443                                         break;
444                                 case 180:
445                                         col = (!col) ? ap->ncols - 1 : col - 1;
446                                         break;
447                                 case 200:
448                                 case 210:
449                                         col = (!col) ? ap->ncols - 1 : col - 1;
450                                         row = (!row) ? ap->nrows - 1 : row - 1;
451                                         break;
452                                 case 240:
453                                         row = (!row) ? ap->nrows - 1 : row - 1;
454                                         break;
455                                 case 270:
456                                 case 280:
457                                         if (!row)
458                                                 row = ap->nrows - 2;
459                                         else if (row == 1)
460                                                 row = ap->nrows - 1;
461                                         else
462                                                 row = row - 2;
463                                         break;
464                                 case 300:
465                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
466                                         if (!row)
467                                                 row = ap->nrows - 2;
468                                         else if (row == 1)
469                                                 row = ap->nrows - 1;
470                                         else
471                                                 row = row - 2;
472                                         break;
473                                 case 320:
474                                 case 330:
475                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
476                                         row = (!row) ? ap->nrows - 1 : row - 1;
477                                         break;
478                                 default:
479                                         (void) fprintf(stderr, "wrong direction %d\n", dir);
480                         }
481                 }
482         }
483         *pcol = col;
484         *prow = row;
485 }
486
487 static void
488 fillcell(ModeInfo * mi, GC gc, int col, int row)
489 {
490         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
491
492         if (ap->neighbors == 6) {
493                 int         ccol = 2 * col + !(row & 1), crow = 2 * row;
494
495                 ap->hexagonList[0].x = ap->xb + ccol * ap->xs;
496                 ap->hexagonList[0].y = ap->yb + crow * ap->ys;
497                 if (ap->xs == 1 && ap->ys == 1)
498                         XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
499                            ap->hexagonList[0].x, ap->hexagonList[0].y, 1, 1);
500                 else
501                         XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
502                               ap->hexagonList, 6, Convex, CoordModePrevious);
503
504         } else if (ap->neighbors == 4 || ap->neighbors == 8) {
505                 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
506                 ap->xb + ap->xs * col, ap->yb + ap->ys * row, ap->xs, ap->ys);
507
508         } else {                /* TRI */
509                 int         orient = (col + row) % 2;   /* O left 1 right */
510
511                 ap->triangleList[orient][0].x = ap->xb + col * ap->xs;
512                 ap->triangleList[orient][0].y = ap->yb + row * ap->ys;
513                 if (ap->xs <= 3 || ap->ys <= 3)
514                         XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
515                          ((orient) ? -1 : 1) + ap->triangleList[orient][0].x,
516                                        ap->triangleList[orient][0].y, 1, 1);
517                 else {
518                         if (orient)
519                                 ap->triangleList[orient][0].x += (ap->xs / 2 - 1);
520                         else
521                                 ap->triangleList[orient][0].x -= (ap->xs / 2 - 1);
522                         XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
523                                      ap->triangleList[orient], 3, Convex, CoordModePrevious);
524                 }
525         }
526 }
527
528 static void
529 truchetcell(ModeInfo * mi, int col, int row, int truchetstate)
530 {
531         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
532
533         if (ap->neighbors == 6) {
534                 int         ccol = 2 * col + !(row & 1), crow = 2 * row;
535                 int         side;
536                 XPoint      hex, hex2;
537
538                 /* Very crude approx of Sqrt 3, so it will not cause drawing errors. */
539                 hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs * 1.6 / 2.0);
540                 hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys * 1.6 / 2.0);
541                 for (side = 0; side < 6; side++) {
542                         if (side > 0) {
543                                 hex.x += ap->hexagonList[side].x;
544                                 hex.y += ap->hexagonList[side].y;
545                         }
546                         hex2.x = hex.x + ap->hexagonList[side + 1].x / 2;
547                         hex2.y = hex.y + ap->hexagonList[side + 1].y / 2;
548                         if (truchetstate == side % 3)
549                                 /* Crude approx of 120 deg, so it will not cause drawing errors. */
550                                 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
551                                          hex2.x, hex2.y,
552                                          (int) ((double) ap->xs * 1.5), (int) ((double) ap->ys * 1.5),
553                                   ((555 - (side * 60)) % 360) * 64, 90 * 64);
554                 }
555         } else if (ap->neighbors == 4) {
556                 if (truchetstate) {
557                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
558                                  ap->xb + ap->xs * col - ap->xs / 2,
559                                  ap->yb + ap->ys * row + ap->ys / 2,
560                                  ap->xs, ap->ys,
561                                  1 * 64, 88 * 64);
562                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
563                                  ap->xb + ap->xs * col + ap->xs / 2,
564                                  ap->yb + ap->ys * row - ap->ys / 2,
565                                  ap->xs, ap->ys,
566                                  -91 * 64, -88 * 64);
567                 } else {
568                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
569                                  ap->xb + ap->xs * col - ap->xs / 2,
570                                  ap->yb + ap->ys * row - ap->ys / 2,
571                                  ap->xs, ap->ys,
572                                  -1 * 64, -88 * 64);
573                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
574                                  ap->xb + ap->xs * col + ap->xs / 2,
575                                  ap->yb + ap->ys * row + ap->ys / 2,
576                                  ap->xs, ap->ys,
577                                  91 * 64, 88 * 64);
578                 }
579         } else if (ap->neighbors == 3) {
580                 int         orient = (col + row) % 2;   /* O left 1 right */
581                 int         side, ang;
582                 XPoint      tri;
583
584                 tri.x = ap->xb + col * ap->xs;
585                 tri.y = ap->yb + row * ap->ys;
586                 if (orient) {
587                         tri.x += (ap->xs / 2 - 2);
588                 } else {
589                         tri.x -= (ap->xs / 2 + 2);
590                 }
591                 for (side = 0; side < 3; side++) {
592                         if (side > 0) {
593                                 tri.x += ap->triangleList[orient][side].x;
594                                 tri.y += ap->triangleList[orient][side].y;
595                         }
596                         if (truchetstate == side % 3) {
597                                 if (orient)
598                                         ang = (518 - side * 120) % 360;         /* Right */
599                                 else
600                                         ang = (690 - side * 120) % 360;         /* Left */
601                                 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
602                                   tri.x - ap->xs / 2, tri.y - 3 * ap->ys / 4,
603                                          ap->xs, 3 * ap->ys / 2,
604                                          ang * 64, 45 * 64);
605                         }
606                 }
607         }
608 }
609
610 static void
611 drawcell(ModeInfo * mi, int col, int row, unsigned char color)
612 {
613         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
614   GC gc;
615
616         if (!color) {
617                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
618                 gc = MI_GC(mi);
619         } else if (MI_NPIXELS(mi) > 2) {
620                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
621                                MI_PIXEL(mi, ap->colors[color - 1]));
622                 gc = MI_GC(mi);
623         } else {
624                 XGCValues   gcv;
625
626                 gcv.stipple = ap->pixmaps[color - 1];
627                 gcv.foreground = MI_WIN_WHITE_PIXEL(mi);
628                 gcv.background = MI_WIN_BLACK_PIXEL(mi);
629                 XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
630                           GCStipple | GCForeground | GCBackground, &gcv);
631                 gc = ap->stippledGC;
632         }
633         fillcell(mi, gc, col, row);
634 }
635
636 static void
637 drawtruchet(ModeInfo * mi, int col, int row,
638             unsigned char color, unsigned char truchetstate)
639 {
640         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
641
642         if (!color)
643                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
644         else if (MI_NPIXELS(mi) > 2 || color > ap->ncolors / 2)
645                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
646         else
647                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
648         truchetcell(mi, col, row, truchetstate);
649 }
650
651 static void
652 draw_anant(ModeInfo * mi, int col, int row)
653 {
654         XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
655         fillcell(mi, MI_GC(mi), col, row);
656 #if 0                           /* Can not see eyes */
657         {
658                 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
659                 Display    *display = MI_DISPLAY(mi);
660                 Window      window = MI_WINDOW(mi);
661
662                 if (ap->xs > 2 && ap->ys > 2) {         /* Draw Eyes */
663
664                         XSetForeground(display, MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
665                         switch (direction) {
666                                 case 0:
667                                         XDrawPoint(display, window, MI_GC(mi),
668                                             ap->xb + ap->xs - 1, ap->yb + 1);
669                                         XDrawPoint(display, window, MI_GC(mi),
670                                                    ap->xb + ap->xs - 1, ap->yb + ap->ys - 2);
671                                         break;
672                                 case 180:
673                                         XDrawPoint(display, window, MI_GC(mi), ap->xb, ap->yb + 1);
674                                         XDrawPoint(display, window, MI_GC(mi), ap->xb, ap->yb + ap->ys - 2);
675                                         break;
676                                         if (neighbors == 4) {
677                                 case 90:
678                                                 XDrawPoint(display, window, MI_GC(mi), ap->xb + 1, ap->yb);
679                                                 XDrawPoint(display, window, MI_GC(mi),
680                                                 ap->xb + ap->xs - 2, ap->yb);
681                                                 break;
682                                 case 270:
683                                                 XDrawPoint(display, window, MI_GC(mi),
684                                                            ap->xb + 1, ap->yb + ap->ys - 1);
685                                                 XDrawPoint(display, window, MI_GC(mi),
686                                                            ap->xb + ap->xs - 2, ap->yb + ap->ys - 1);
687                                                 break;
688                                         }       /* else BEE */
689                                 default:
690                         }
691                 }
692         }
693 #endif
694 }
695
696 #if 0
697 static void
698 RandomSoup(mi)
699         ModeInfo   *mi;
700 {
701         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
702         int         row, col, mrow = 0;
703
704         for (row = 0; row < ap->nrows; ++row) {
705                 for (col = 0; col < ap->ncols; ++col) {
706                         ap->old[col + mrow] = (unsigned char) NRAND((int) ap->ncolors);
707                         drawcell(mi, col, row, ap->old[col + mrow]);
708                 }
709                 mrow += ap->nrows;
710         }
711 }
712
713 #endif
714
715 static short
716 fromTableDirection(unsigned char dir, int neighbors)
717 {
718         switch (dir) {
719                 case FS:
720                         return 0;
721                 case TRS:
722                         return (ANGLES / neighbors);
723                 case THRS:
724                         return (ANGLES / (2 * neighbors));
725                 case TBS:
726                         return (ANGLES / 2);
727                 case THLS:
728                         return (ANGLES - ANGLES / (2 * neighbors));
729                 case TLS:
730                         return (ANGLES - ANGLES / neighbors);
731                 case SF:
732                         return ANGLES;
733                 case STR:
734                         return (ANGLES + ANGLES / neighbors);
735                 case STHR:
736                         return (ANGLES + ANGLES / (2 * neighbors));
737                 case STB:
738                         return (3 * ANGLES / 2);
739                 case STHL:
740                         return (2 * ANGLES - ANGLES / (2 * neighbors));
741                 case STL:
742                         return (2 * ANGLES - ANGLES / neighbors);
743                 default:
744                         (void) fprintf(stderr, "wrong direction %d\n", dir);
745         }
746         return -1;
747 }
748
749 static void
750 getTable(ModeInfo * mi, int i)
751 {
752         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
753         int         j, total;
754         unsigned char *patptr;
755
756         patptr = &tables[i][0];
757         ap->ncolors = *patptr++;
758         ap->nstates = *patptr++;
759         total = ap->ncolors * ap->nstates;
760         if (MI_WIN_IS_VERBOSE(mi))
761                 (void) fprintf(stdout,
762                      "neighbors %d, table number %d, colors %d, states %d\n",
763                                ap->neighbors, i, ap->ncolors, ap->nstates);
764         for (j = 0; j < total; j++) {
765                 ap->machine[j].color = *patptr++;
766                 ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors);
767                 ap->machine[j].next = *patptr++;
768         }
769         ap->truchet = False;
770 }
771
772 static void
773 getTurk(ModeInfo * mi, int i)
774 {
775         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
776         int         power2, j, number, total;
777
778         /* To force a number, say <i = 2;> has  i + 2 (or 4) digits in binary */
779         power2 = 1 << (i + 1);
780         /* Dont want numbers which in binary are all 1's. */
781         number = NRAND(power2 - 1) + power2;
782         /* To force a particular number, say <number = 10;> */
783
784         ap->ncolors = i + 2;
785         ap->nstates = 1;
786         total = ap->ncolors * ap->nstates;
787         for (j = 0; j < total; j++) {
788                 ap->machine[j].color = (j + 1) % total;
789                 ap->machine[j].direction = (power2 & number) ?
790                         fromTableDirection(TRS, ap->neighbors) :
791                         fromTableDirection(TLS, ap->neighbors);
792                 ap->machine[j].next = 0;
793                 power2 >>= 1;
794         }
795         if (ap->neighbors != 3 && ap->neighbors != 4 && ap->neighbors != 6)
796                 ap->truchet = False;
797         else if (truchet)
798                 ap->truchet = True;
799         if (MI_WIN_IS_VERBOSE(mi))
800                 (void) fprintf(stdout, "neighbors %d, Turk's number %d, colors %d\n",
801                                ap->neighbors, number, ap->ncolors);
802 }
803
804 void
805 init_ant(ModeInfo * mi)
806 {
807         Display    *display = MI_DISPLAY(mi);
808         Window      window = MI_WINDOW(mi);
809         int         size = MI_SIZE(mi);
810         XGCValues   gcv;
811         antfarmstruct *ap;
812         int         col, row, i, dir;
813
814         /* jwz sez: small sizes look like crap */
815         if (size < 0)
816           size = NRAND(-size)+1;
817         if (size < 5)
818           size += 5;
819
820         if (antfarms == NULL) {
821                 if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi),
822                                             sizeof (antfarmstruct))) == NULL)
823                         return;
824         }
825         ap = &antfarms[MI_SCREEN(mi)];
826         ap->redrawing = 0;
827         if (MI_NPIXELS(mi) <= 2) {
828                 if (ap->stippledGC == None) {
829                         gcv.fill_style = FillOpaqueStippled;
830                         ap->stippledGC = XCreateGC(display, window, GCFillStyle, &gcv);
831                 }
832                 if (ap->init_bits == 0) {
833                         for (i = 0; i < COLORS - 1; i++)
834                                 ANTBITS(patterns[i], PATTERNSIZE, PATTERNSIZE);
835                 }
836         }
837         ap->generation = 0;
838         ap->n = MI_BATCHCOUNT(mi);
839         if (ap->n < -MINANTS) {
840                 /* if ap->n is random ... the size can change */
841                 if (ap->ants != NULL) {
842                         (void) free((void *) ap->ants);
843                         ap->ants = NULL;
844                 }
845                 ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;
846         } else if (ap->n < MINANTS)
847                 ap->n = MINANTS;
848
849         ap->width = MI_WIN_WIDTH(mi);
850         ap->height = MI_WIN_HEIGHT(mi);
851
852         if (neighbors == 8 || neighbors == 9 || neighbors == 12)
853                 ap->neighbors = neighbors;      /* Discourage but not deny use... */
854         else
855                 for (i = 0; i < NEIGHBORKINDS; i++) {
856                         if (neighbors == initVal[i]) {
857                                 ap->neighbors = initVal[i];
858                                 break;
859                         }
860                         if (i == NEIGHBORKINDS - 1) {
861                                 ap->neighbors = initVal[NRAND(NEIGHBORKINDS)];
862                                 break;
863                         }
864                 }
865
866         if (ap->neighbors == 6) {
867                 int         nccols, ncrows;
868
869                 if (ap->width < 2)
870                         ap->width = 2;
871                 if (ap->height < 4)
872                         ap->height = 4;
873                 if (size < -MINSIZE)
874                         ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
875                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
876                 else if (size < MINSIZE) {
877                         if (!size)
878                                 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
879                         else
880                                 ap->ys = MINSIZE;
881                 } else
882                         ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
883                                                MINGRIDSIZE));
884                 ap->xs = ap->ys;
885                 nccols = MAX(ap->width / ap->xs - 2, 2);
886                 ncrows = MAX(ap->height / ap->ys - 1, 2);
887                 ap->ncols = nccols / 2;
888                 ap->nrows = 2 * (ncrows / 4);
889                 ap->xb = (ap->width - ap->xs * nccols) / 2 + ap->xs / 2;
890                 ap->yb = (ap->height - ap->ys * (ncrows / 2) * 2) / 2 + ap->ys;
891                 for (i = 0; i < 7; i++) {
892                         ap->hexagonList[i].x = (ap->xs - 1) * hexagonUnit[i].x;
893                         ap->hexagonList[i].y = ((ap->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
894                 }
895         } else if (ap->neighbors == 4 && ap->neighbors == 8) {
896                 if (size < -MINSIZE)
897                         ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
898                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
899                 else if (size < MINSIZE) {
900                         if (!size)
901                                 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
902                         else
903                                 ap->ys = MINSIZE;
904                 } else
905                         ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
906                                                MINGRIDSIZE));
907                 ap->xs = ap->ys;
908                 ap->ncols = MAX(ap->width / ap->xs, 2);
909                 ap->nrows = MAX(ap->height / ap->ys, 2);
910                 ap->xb = (ap->width - ap->xs * ap->ncols) / 2;
911                 ap->yb = (ap->height - ap->ys * ap->nrows) / 2;
912         } else {                /* TRI */
913                 int         orient;
914
915                 if (ap->width < 2)
916                         ap->width = 2;
917                 if (ap->height < 2)
918                         ap->height = 2;
919                 if (size < -MINSIZE)
920                         ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
921                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
922                 else if (size < MINSIZE) {
923                         if (!size)
924                                 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
925                         else
926                                 ap->ys = MINSIZE;
927                 } else
928                         ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
929                                                MINGRIDSIZE));
930                 ap->xs = (int) (1.52 * ap->ys);
931                 ap->ncols = (MAX(ap->width / ap->xs - 1, 2) / 2) * 2;
932                 ap->nrows = (MAX(ap->height / ap->ys - 1, 2) / 2) * 2;
933                 ap->xb = (ap->width - ap->xs * ap->ncols) / 2 + ap->xs / 2;
934                 ap->yb = (ap->height - ap->ys * ap->nrows) / 2 + ap->ys;
935                 for (orient = 0; orient < 2; orient++) {
936                         for (i = 0; i < 4; i++) {
937                                 ap->triangleList[orient][i].x =
938                                         (ap->xs - 2) * triangleUnit[orient][i].x;
939                                 ap->triangleList[orient][i].y =
940                                         (ap->ys - 2) * triangleUnit[orient][i].y;
941                         }
942                 }
943         }
944         XClearWindow(display, MI_WINDOW(mi));
945
946         /* Exclude odd # of neighbors, stepping forward not defined */
947         if (!NRAND(COLORS) && ((ap->neighbors + 1) % 2)) {
948                 getTable(mi, (int) (NRAND(NTABLES)));
949         } else
950                 getTurk(mi, (int) (NRAND(COLORS - 1)));
951         if (MI_NPIXELS(mi) > 2)
952                 for (i = 0; i < (int) ap->ncolors - 1; i++)
953                         ap->colors[i] = (NRAND(MI_NPIXELS(mi)) +
954                              i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1));
955         if (ap->ants == NULL)
956                 ap->ants = (antstruct *) malloc(ap->n * sizeof (antstruct));
957         if (ap->tape != NULL)
958                 (void) free((void *) ap->tape);
959         ap->tape = (unsigned char *)
960                 calloc(ap->ncols * ap->nrows, sizeof (unsigned char));
961
962         if (ap->truchet_state != NULL)
963                 (void) free((void *) ap->truchet_state);
964         ap->truchet_state = (unsigned char *)
965                 calloc(ap->ncols * ap->nrows, sizeof (unsigned char));
966
967         col = ap->ncols / 2;
968         row = ap->nrows / 2;
969         dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors;
970         /* Have them all start in the same spot, why not? */
971         for (i = 0; i < ap->n; i++) {
972                 ap->ants[i].col = col;
973                 ap->ants[i].row = row;
974                 ap->ants[i].direction = dir;
975                 ap->ants[i].state = 0;
976         }
977         draw_anant(mi, col, row);
978 }
979
980 void
981 draw_ant(ModeInfo * mi)
982 {
983         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
984         antstruct  *anant;
985         statestruct *status;
986         int         i, state_pos, tape_pos;
987         unsigned char color;
988         short       chg_dir, old_dir;
989
990         for (i = 0; i < ap->n; i++) {
991                 anant = &ap->ants[i];
992                 tape_pos = anant->col + anant->row * ap->ncols;
993                 color = ap->tape[tape_pos];     /* read tape */
994                 state_pos = color + anant->state * ap->ncolors;
995                 status = &(ap->machine[state_pos]);
996                 drawcell(mi, anant->col, anant->row, status->color);
997                 ap->tape[tape_pos] = status->color;     /* write on tape */
998
999                 /* Find direction of Bees or Ants. */
1000                 /* Translate relative direction to actual direction */
1001                 old_dir = anant->direction;
1002                 chg_dir = (2 * ANGLES - status->direction) % ANGLES;
1003                 anant->direction = (chg_dir + old_dir) % ANGLES;
1004                 if (ap->truchet) {
1005                         int         a = 0, b;
1006
1007                         if (ap->neighbors == 6) {
1008                                 a = (old_dir / 60) % 3;
1009                                 b = (anant->direction / 60) % 3;
1010                                 a = (a + b + 1) % 3;
1011                                 drawtruchet(mi, anant->col, anant->row, status->color, a);
1012                         } else if (ap->neighbors == 4) {
1013                                 a = old_dir / 180;
1014                                 b = anant->direction / 180;
1015                                 a = ((a && !b) || (b && !a));
1016                                 drawtruchet(mi, anant->col, anant->row, status->color, a);
1017                         } else if (ap->neighbors == 3) {
1018                                 if (chg_dir == 240)
1019                                         a = (2 + anant->direction / 120) % 3;
1020                                 else
1021                                         a = (1 + anant->direction / 120) % 3;
1022                                 drawtruchet(mi, anant->col, anant->row, status->color, a);
1023                         }
1024                         ap->truchet_state[tape_pos] = a + 1;
1025                 }
1026                 anant->state = status->next;
1027
1028                 /* If edge than wrap it */
1029                 old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir);
1030                 position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row));
1031                 draw_anant(mi, anant->col, anant->row);
1032         }
1033         if (++ap->generation > MI_CYCLES(mi)) {
1034 #ifdef STANDALONE
1035           erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
1036 #endif
1037           init_ant(mi);
1038         }
1039         if (ap->redrawing) {
1040                 for (i = 0; i < REDRAWSTEP; i++) {
1041                         if (ap->tape[ap->redrawpos] ||
1042                          (ap->truchet && ap->truchet_state[ap->redrawpos])) {
1043                                 drawcell(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1044                                          ap->tape[ap->redrawpos]);
1045                                 if (ap->truchet)
1046                                         drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1047                                                     ap->tape[ap->redrawpos],
1048                                         ap->truchet_state[ap->redrawpos] - 1);
1049                         }
1050                         if (++(ap->redrawpos) >= ap->ncols * ap->nrows) {
1051                                 ap->redrawing = 0;
1052                                 break;
1053                         }
1054                 }
1055         }
1056 }
1057
1058 void
1059 release_ant(ModeInfo * mi)
1060 {
1061         if (antfarms != NULL) {
1062                 int         screen;
1063
1064                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1065                         antfarmstruct *ap = &antfarms[screen];
1066                         int         shade;
1067
1068                         if (ap->stippledGC != None) {
1069                                 XFreeGC(MI_DISPLAY(mi), ap->stippledGC);
1070                         }
1071                         for (shade = 0; shade < ap->init_bits; shade++)
1072                                 XFreePixmap(MI_DISPLAY(mi), ap->pixmaps[shade]);
1073                         if (ap->tape != NULL)
1074                                 (void) free((void *) ap->tape);
1075                         if (ap->ants != NULL)
1076                                 (void) free((void *) ap->ants);
1077                         if (ap->truchet_state != NULL)
1078                                 (void) free((void *) ap->truchet_state);
1079                 }
1080                 (void) free((void *) antfarms);
1081                 antfarms = NULL;
1082         }
1083 }
1084
1085 void
1086 refresh_ant(ModeInfo * mi)
1087 {
1088         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
1089
1090         ap->redrawing = 1;
1091         ap->redrawpos = 0;
1092 }