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