cf019b62b71a4eafd3d7569ce22a17f470d31243
[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  "False"
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 3
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, 4, 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 #if 0 /* jwz sez: this looks like crap */
505         } else if (ap->neighbors == 4 || ap->neighbors == 8) {
506                 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
507                 ap->xb + ap->xs * col, ap->yb + ap->ys * row, ap->xs, ap->ys);
508 #endif
509
510         } else {                /* TRI */
511                 int         orient = (col + row) % 2;   /* O left 1 right */
512
513                 ap->triangleList[orient][0].x = ap->xb + col * ap->xs;
514                 ap->triangleList[orient][0].y = ap->yb + row * ap->ys;
515                 if (ap->xs <= 3 || ap->ys <= 3)
516                         XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
517                          ((orient) ? -1 : 1) + ap->triangleList[orient][0].x,
518                                        ap->triangleList[orient][0].y, 1, 1);
519                 else {
520                         if (orient)
521                                 ap->triangleList[orient][0].x += (ap->xs / 2 - 1);
522                         else
523                                 ap->triangleList[orient][0].x -= (ap->xs / 2 - 1);
524                         XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
525                                      ap->triangleList[orient], 3, Convex, CoordModePrevious);
526                 }
527         }
528 }
529
530 static void
531 truchetcell(ModeInfo * mi, int col, int row, int truchetstate)
532 {
533         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
534
535         if (ap->neighbors == 6) {
536                 int         ccol = 2 * col + !(row & 1), crow = 2 * row;
537                 int         side;
538                 XPoint      hex, hex2;
539
540                 /* Very crude approx of Sqrt 3, so it will not cause drawing errors. */
541                 hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs * 1.6 / 2.0);
542                 hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys * 1.6 / 2.0);
543                 for (side = 0; side < 6; side++) {
544                         if (side > 0) {
545                                 hex.x += ap->hexagonList[side].x;
546                                 hex.y += ap->hexagonList[side].y;
547                         }
548                         hex2.x = hex.x + ap->hexagonList[side + 1].x / 2;
549                         hex2.y = hex.y + ap->hexagonList[side + 1].y / 2;
550                         if (truchetstate == side % 3)
551                                 /* Crude approx of 120 deg, so it will not cause drawing errors. */
552                                 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
553                                          hex2.x, hex2.y,
554                                          (int) ((double) ap->xs * 1.5), (int) ((double) ap->ys * 1.5),
555                                   ((555 - (side * 60)) % 360) * 64, 90 * 64);
556                 }
557         } else if (ap->neighbors == 4) {
558                 if (truchetstate) {
559                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
560                                  ap->xb + ap->xs * col - ap->xs / 2,
561                                  ap->yb + ap->ys * row + ap->ys / 2,
562                                  ap->xs, ap->ys,
563                                  1 * 64, 88 * 64);
564                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
565                                  ap->xb + ap->xs * col + ap->xs / 2,
566                                  ap->yb + ap->ys * row - ap->ys / 2,
567                                  ap->xs, ap->ys,
568                                  -91 * 64, -88 * 64);
569                 } else {
570                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
571                                  ap->xb + ap->xs * col - ap->xs / 2,
572                                  ap->yb + ap->ys * row - ap->ys / 2,
573                                  ap->xs, ap->ys,
574                                  -1 * 64, -88 * 64);
575                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
576                                  ap->xb + ap->xs * col + ap->xs / 2,
577                                  ap->yb + ap->ys * row + ap->ys / 2,
578                                  ap->xs, ap->ys,
579                                  91 * 64, 88 * 64);
580                 }
581         } else if (ap->neighbors == 3) {
582                 int         orient = (col + row) % 2;   /* O left 1 right */
583                 int         side, ang;
584                 XPoint      tri;
585
586                 tri.x = ap->xb + col * ap->xs;
587                 tri.y = ap->yb + row * ap->ys;
588                 if (orient) {
589                         tri.x += (ap->xs / 2 - 2);
590                 } else {
591                         tri.x -= (ap->xs / 2 + 2);
592                 }
593                 for (side = 0; side < 3; side++) {
594                         if (side > 0) {
595                                 tri.x += ap->triangleList[orient][side].x;
596                                 tri.y += ap->triangleList[orient][side].y;
597                         }
598                         if (truchetstate == side % 3) {
599                                 if (orient)
600                                         ang = (518 - side * 120) % 360;         /* Right */
601                                 else
602                                         ang = (690 - side * 120) % 360;         /* Left */
603                                 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
604                                   tri.x - ap->xs / 2, tri.y - 3 * ap->ys / 4,
605                                          ap->xs, 3 * ap->ys / 2,
606                                          ang * 64, 45 * 64);
607                         }
608                 }
609         }
610 }
611
612 static void
613 drawcell(ModeInfo * mi, int col, int row, unsigned char color)
614 {
615         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
616   GC gc;
617
618         if (!color) {
619                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
620                 gc = MI_GC(mi);
621         } else if (MI_NPIXELS(mi) > 2) {
622                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
623                                MI_PIXEL(mi, ap->colors[color - 1]));
624                 gc = MI_GC(mi);
625         } else {
626                 XGCValues   gcv;
627
628                 gcv.stipple = ap->pixmaps[color - 1];
629                 gcv.foreground = MI_WIN_WHITE_PIXEL(mi);
630                 gcv.background = MI_WIN_BLACK_PIXEL(mi);
631                 XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
632                           GCStipple | GCForeground | GCBackground, &gcv);
633                 gc = ap->stippledGC;
634         }
635         fillcell(mi, gc, col, row);
636 }
637
638 static void
639 drawtruchet(ModeInfo * mi, int col, int row,
640             unsigned char color, unsigned char truchetstate)
641 {
642         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
643
644         if (!color)
645                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
646         else if (MI_NPIXELS(mi) > 2 || color > ap->ncolors / 2)
647                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
648         else
649                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
650         truchetcell(mi, col, row, truchetstate);
651 }
652
653 static void
654 draw_anant(ModeInfo * mi, int col, int row)
655 {
656         XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
657         fillcell(mi, MI_GC(mi), col, row);
658 #if 0                           /* Can not see eyes */
659         {
660                 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
661                 Display    *display = MI_DISPLAY(mi);
662                 Window      window = MI_WINDOW(mi);
663
664                 if (ap->xs > 2 && ap->ys > 2) {         /* Draw Eyes */
665
666                         XSetForeground(display, MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
667                         switch (direction) {
668                                 case 0:
669                                         XDrawPoint(display, window, MI_GC(mi),
670                                             ap->xb + ap->xs - 1, ap->yb + 1);
671                                         XDrawPoint(display, window, MI_GC(mi),
672                                                    ap->xb + ap->xs - 1, ap->yb + ap->ys - 2);
673                                         break;
674                                 case 180:
675                                         XDrawPoint(display, window, MI_GC(mi), ap->xb, ap->yb + 1);
676                                         XDrawPoint(display, window, MI_GC(mi), ap->xb, ap->yb + ap->ys - 2);
677                                         break;
678                                         if (neighbors == 4) {
679                                 case 90:
680                                                 XDrawPoint(display, window, MI_GC(mi), ap->xb + 1, ap->yb);
681                                                 XDrawPoint(display, window, MI_GC(mi),
682                                                 ap->xb + ap->xs - 2, ap->yb);
683                                                 break;
684                                 case 270:
685                                                 XDrawPoint(display, window, MI_GC(mi),
686                                                            ap->xb + 1, ap->yb + ap->ys - 1);
687                                                 XDrawPoint(display, window, MI_GC(mi),
688                                                            ap->xb + ap->xs - 2, ap->yb + ap->ys - 1);
689                                                 break;
690                                         }       /* else BEE */
691                                 default:
692                         }
693                 }
694         }
695 #endif
696 }
697
698 #if 0
699 static void
700 RandomSoup(mi)
701         ModeInfo   *mi;
702 {
703         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
704         int         row, col, mrow = 0;
705
706         for (row = 0; row < ap->nrows; ++row) {
707                 for (col = 0; col < ap->ncols; ++col) {
708                         ap->old[col + mrow] = (unsigned char) NRAND((int) ap->ncolors);
709                         drawcell(mi, col, row, ap->old[col + mrow]);
710                 }
711                 mrow += ap->nrows;
712         }
713 }
714
715 #endif
716
717 static short
718 fromTableDirection(unsigned char dir, int neighbors)
719 {
720         switch (dir) {
721                 case FS:
722                         return 0;
723                 case TRS:
724                         return (ANGLES / neighbors);
725                 case THRS:
726                         return (ANGLES / (2 * neighbors));
727                 case TBS:
728                         return (ANGLES / 2);
729                 case THLS:
730                         return (ANGLES - ANGLES / (2 * neighbors));
731                 case TLS:
732                         return (ANGLES - ANGLES / neighbors);
733                 case SF:
734                         return ANGLES;
735                 case STR:
736                         return (ANGLES + ANGLES / neighbors);
737                 case STHR:
738                         return (ANGLES + ANGLES / (2 * neighbors));
739                 case STB:
740                         return (3 * ANGLES / 2);
741                 case STHL:
742                         return (2 * ANGLES - ANGLES / (2 * neighbors));
743                 case STL:
744                         return (2 * ANGLES - ANGLES / neighbors);
745                 default:
746                         (void) fprintf(stderr, "wrong direction %d\n", dir);
747         }
748         return -1;
749 }
750
751 static void
752 getTable(ModeInfo * mi, int i)
753 {
754         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
755         int         j, total;
756         unsigned char *patptr;
757
758         patptr = &tables[i][0];
759         ap->ncolors = *patptr++;
760         ap->nstates = *patptr++;
761         total = ap->ncolors * ap->nstates;
762         if (MI_WIN_IS_VERBOSE(mi))
763                 (void) fprintf(stdout,
764                      "neighbors %d, table number %d, colors %d, states %d\n",
765                                ap->neighbors, i, ap->ncolors, ap->nstates);
766         for (j = 0; j < total; j++) {
767                 ap->machine[j].color = *patptr++;
768                 ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors);
769                 ap->machine[j].next = *patptr++;
770         }
771         ap->truchet = False;
772 }
773
774 static void
775 getTurk(ModeInfo * mi, int i)
776 {
777         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
778         int         power2, j, number, total;
779
780         /* To force a number, say <i = 2;> has  i + 2 (or 4) digits in binary */
781         power2 = 1 << (i + 1);
782         /* Dont want numbers which in binary are all 1's. */
783         number = NRAND(power2 - 1) + power2;
784         /* To force a particular number, say <number = 10;> */
785
786         ap->ncolors = i + 2;
787         ap->nstates = 1;
788         total = ap->ncolors * ap->nstates;
789         for (j = 0; j < total; j++) {
790                 ap->machine[j].color = (j + 1) % total;
791                 ap->machine[j].direction = (power2 & number) ?
792                         fromTableDirection(TRS, ap->neighbors) :
793                         fromTableDirection(TLS, ap->neighbors);
794                 ap->machine[j].next = 0;
795                 power2 >>= 1;
796         }
797         if (ap->neighbors != 3 && ap->neighbors != 4 && ap->neighbors != 6)
798                 ap->truchet = False;
799         else if (truchet)
800                 ap->truchet = True;
801         if (MI_WIN_IS_VERBOSE(mi))
802                 (void) fprintf(stdout, "neighbors %d, Turk's number %d, colors %d\n",
803                                ap->neighbors, number, ap->ncolors);
804 }
805
806 void
807 init_ant(ModeInfo * mi)
808 {
809         Display    *display = MI_DISPLAY(mi);
810         Window      window = MI_WINDOW(mi);
811         int         size = MI_SIZE(mi);
812         XGCValues   gcv;
813         antfarmstruct *ap;
814         int         col, row, i, dir;
815
816         /* jwz sez: small sizes look like crap */
817         if (size < 0)
818           size = NRAND(-size)+1;
819         if (size < 5)
820           size += 5;
821
822         if (antfarms == NULL) {
823                 if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi),
824                                             sizeof (antfarmstruct))) == NULL)
825                         return;
826         }
827         ap = &antfarms[MI_SCREEN(mi)];
828         ap->redrawing = 0;
829         if (MI_NPIXELS(mi) <= 2) {
830                 if (ap->stippledGC == None) {
831                         gcv.fill_style = FillOpaqueStippled;
832                         ap->stippledGC = XCreateGC(display, window, GCFillStyle, &gcv);
833                 }
834                 if (ap->init_bits == 0) {
835                         for (i = 0; i < COLORS - 1; i++)
836                                 ANTBITS(patterns[i], PATTERNSIZE, PATTERNSIZE);
837                 }
838         }
839         ap->generation = 0;
840         ap->n = MI_BATCHCOUNT(mi);
841         if (ap->n < -MINANTS) {
842                 /* if ap->n is random ... the size can change */
843                 if (ap->ants != NULL) {
844                         (void) free((void *) ap->ants);
845                         ap->ants = NULL;
846                 }
847                 ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;
848         } else if (ap->n < MINANTS)
849                 ap->n = MINANTS;
850
851         ap->width = MI_WIN_WIDTH(mi);
852         ap->height = MI_WIN_HEIGHT(mi);
853
854         if (neighbors == 8 || neighbors == 9 || neighbors == 12)
855                 ap->neighbors = neighbors;      /* Discourage but not deny use... */
856         else
857                 for (i = 0; i < NEIGHBORKINDS; i++) {
858                         if (neighbors == initVal[i]) {
859                                 ap->neighbors = initVal[i];
860                                 break;
861                         }
862                         if (i == NEIGHBORKINDS - 1) {
863                                 ap->neighbors = initVal[NRAND(NEIGHBORKINDS)];
864                                 break;
865                         }
866                 }
867
868         if (ap->neighbors == 6) {
869                 int         nccols, ncrows;
870
871                 if (ap->width < 2)
872                         ap->width = 2;
873                 if (ap->height < 4)
874                         ap->height = 4;
875                 if (size < -MINSIZE)
876                         ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
877                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
878                 else if (size < MINSIZE) {
879                         if (!size)
880                                 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
881                         else
882                                 ap->ys = MINSIZE;
883                 } else
884                         ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
885                                                MINGRIDSIZE));
886                 ap->xs = ap->ys;
887                 nccols = MAX(ap->width / ap->xs - 2, 2);
888                 ncrows = MAX(ap->height / ap->ys - 1, 2);
889                 ap->ncols = nccols / 2;
890                 ap->nrows = 2 * (ncrows / 4);
891                 ap->xb = (ap->width - ap->xs * nccols) / 2 + ap->xs / 2;
892                 ap->yb = (ap->height - ap->ys * (ncrows / 2) * 2) / 2 + ap->ys;
893                 for (i = 0; i < 7; i++) {
894                         ap->hexagonList[i].x = (ap->xs - 1) * hexagonUnit[i].x;
895                         ap->hexagonList[i].y = ((ap->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
896                 }
897         } else if (ap->neighbors == 4 && ap->neighbors == 8) {
898                 if (size < -MINSIZE)
899                         ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
900                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
901                 else if (size < MINSIZE) {
902                         if (!size)
903                                 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
904                         else
905                                 ap->ys = MINSIZE;
906                 } else
907                         ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
908                                                MINGRIDSIZE));
909                 ap->xs = ap->ys;
910                 ap->ncols = MAX(ap->width / ap->xs, 2);
911                 ap->nrows = MAX(ap->height / ap->ys, 2);
912                 ap->xb = (ap->width - ap->xs * ap->ncols) / 2;
913                 ap->yb = (ap->height - ap->ys * ap->nrows) / 2;
914         } else {                /* TRI */
915                 int         orient;
916
917                 if (ap->width < 2)
918                         ap->width = 2;
919                 if (ap->height < 2)
920                         ap->height = 2;
921                 if (size < -MINSIZE)
922                         ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
923                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
924                 else if (size < MINSIZE) {
925                         if (!size)
926                                 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
927                         else
928                                 ap->ys = MINSIZE;
929                 } else
930                         ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
931                                                MINGRIDSIZE));
932                 ap->xs = (int) (1.52 * ap->ys);
933                 ap->ncols = (MAX(ap->width / ap->xs - 1, 2) / 2) * 2;
934                 ap->nrows = (MAX(ap->height / ap->ys - 1, 2) / 2) * 2;
935                 ap->xb = (ap->width - ap->xs * ap->ncols) / 2 + ap->xs / 2;
936                 ap->yb = (ap->height - ap->ys * ap->nrows) / 2 + ap->ys;
937                 for (orient = 0; orient < 2; orient++) {
938                         for (i = 0; i < 4; i++) {
939                                 ap->triangleList[orient][i].x =
940                                         (ap->xs - 2) * triangleUnit[orient][i].x;
941                                 ap->triangleList[orient][i].y =
942                                         (ap->ys - 2) * triangleUnit[orient][i].y;
943                         }
944                 }
945         }
946         XClearWindow(display, MI_WINDOW(mi));
947
948         /* Exclude odd # of neighbors, stepping forward not defined */
949         if (!NRAND(COLORS) && ((ap->neighbors + 1) % 2)) {
950                 getTable(mi, (int) (NRAND(NTABLES)));
951         } else
952                 getTurk(mi, (int) (NRAND(COLORS - 1)));
953         if (MI_NPIXELS(mi) > 2)
954                 for (i = 0; i < (int) ap->ncolors - 1; i++)
955                         ap->colors[i] = (NRAND(MI_NPIXELS(mi)) +
956                              i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1));
957         if (ap->ants == NULL)
958                 ap->ants = (antstruct *) malloc(ap->n * sizeof (antstruct));
959         if (ap->tape != NULL)
960                 (void) free((void *) ap->tape);
961         ap->tape = (unsigned char *)
962                 calloc(ap->ncols * ap->nrows, sizeof (unsigned char));
963
964         if (ap->truchet_state != NULL)
965                 (void) free((void *) ap->truchet_state);
966         ap->truchet_state = (unsigned char *)
967                 calloc(ap->ncols * ap->nrows, sizeof (unsigned char));
968
969         col = ap->ncols / 2;
970         row = ap->nrows / 2;
971         dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors;
972         /* Have them all start in the same spot, why not? */
973         for (i = 0; i < ap->n; i++) {
974                 ap->ants[i].col = col;
975                 ap->ants[i].row = row;
976                 ap->ants[i].direction = dir;
977                 ap->ants[i].state = 0;
978         }
979         draw_anant(mi, col, row);
980 }
981
982 void
983 draw_ant(ModeInfo * mi)
984 {
985         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
986         antstruct  *anant;
987         statestruct *status;
988         int         i, state_pos, tape_pos;
989         unsigned char color;
990         short       chg_dir, old_dir;
991
992         for (i = 0; i < ap->n; i++) {
993                 anant = &ap->ants[i];
994                 tape_pos = anant->col + anant->row * ap->ncols;
995                 color = ap->tape[tape_pos];     /* read tape */
996                 state_pos = color + anant->state * ap->ncolors;
997                 status = &(ap->machine[state_pos]);
998                 drawcell(mi, anant->col, anant->row, status->color);
999                 ap->tape[tape_pos] = status->color;     /* write on tape */
1000
1001                 /* Find direction of Bees or Ants. */
1002                 /* Translate relative direction to actual direction */
1003                 old_dir = anant->direction;
1004                 chg_dir = (2 * ANGLES - status->direction) % ANGLES;
1005                 anant->direction = (chg_dir + old_dir) % ANGLES;
1006                 if (ap->truchet) {
1007                         int         a = 0, b;
1008
1009                         if (ap->neighbors == 6) {
1010                                 a = (old_dir / 60) % 3;
1011                                 b = (anant->direction / 60) % 3;
1012                                 a = (a + b + 1) % 3;
1013                                 drawtruchet(mi, anant->col, anant->row, status->color, a);
1014                         } else if (ap->neighbors == 4) {
1015                                 a = old_dir / 180;
1016                                 b = anant->direction / 180;
1017                                 a = ((a && !b) || (b && !a));
1018                                 drawtruchet(mi, anant->col, anant->row, status->color, a);
1019                         } else if (ap->neighbors == 3) {
1020                                 if (chg_dir == 240)
1021                                         a = (2 + anant->direction / 120) % 3;
1022                                 else
1023                                         a = (1 + anant->direction / 120) % 3;
1024                                 drawtruchet(mi, anant->col, anant->row, status->color, a);
1025                         }
1026                         ap->truchet_state[tape_pos] = a + 1;
1027                 }
1028                 anant->state = status->next;
1029
1030                 /* If edge than wrap it */
1031                 old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir);
1032                 position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row));
1033                 draw_anant(mi, anant->col, anant->row);
1034         }
1035         if (++ap->generation > MI_CYCLES(mi)) {
1036 #ifdef STANDALONE
1037           erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
1038 #endif
1039           init_ant(mi);
1040         }
1041         if (ap->redrawing) {
1042                 for (i = 0; i < REDRAWSTEP; i++) {
1043                         if (ap->tape[ap->redrawpos] ||
1044                          (ap->truchet && ap->truchet_state[ap->redrawpos])) {
1045                                 drawcell(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1046                                          ap->tape[ap->redrawpos]);
1047                                 if (ap->truchet)
1048                                         drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1049                                                     ap->tape[ap->redrawpos],
1050                                         ap->truchet_state[ap->redrawpos] - 1);
1051                         }
1052                         if (++(ap->redrawpos) >= ap->ncols * ap->nrows) {
1053                                 ap->redrawing = 0;
1054                                 break;
1055                         }
1056                 }
1057         }
1058 }
1059
1060 void
1061 release_ant(ModeInfo * mi)
1062 {
1063         if (antfarms != NULL) {
1064                 int         screen;
1065
1066                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1067                         antfarmstruct *ap = &antfarms[screen];
1068                         int         shade;
1069
1070                         if (ap->stippledGC != None) {
1071                                 XFreeGC(MI_DISPLAY(mi), ap->stippledGC);
1072                         }
1073                         for (shade = 0; shade < ap->init_bits; shade++)
1074                                 XFreePixmap(MI_DISPLAY(mi), ap->pixmaps[shade]);
1075                         if (ap->tape != NULL)
1076                                 (void) free((void *) ap->tape);
1077                         if (ap->ants != NULL)
1078                                 (void) free((void *) ap->ants);
1079                         if (ap->truchet_state != NULL)
1080                                 (void) free((void *) ap->truchet_state);
1081                 }
1082                 (void) free((void *) antfarms);
1083                 antfarms = NULL;
1084         }
1085 }
1086
1087 void
1088 refresh_ant(ModeInfo * mi)
1089 {
1090         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
1091
1092         ap->redrawing = 1;
1093         ap->redrawpos = 0;
1094 }