http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[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 0
8 static const char sccsid[] = "@(#)ant.c 5.00 2000/11/01 xlockmore";
9 #endif
10
11 /*-
12  * Copyright (c) 1995 by David Bagley.
13  *
14  * Permission to use, copy, modify, and distribute this software and its
15  * documentation for any purpose and without fee is hereby granted,
16  * provided that the above copyright notice appear in all copies and that
17  * both that copyright notice and this permission notice appear in
18  * supporting documentation.
19  *
20  * This file is provided AS IS with no warranties of any kind.  The author
21  * shall have no liability with respect to the infringement of copyrights,
22  * trade secrets or any patents by this file or any part thereof.  In no
23  * event will the author be liable for any lost revenue or profits or
24  * other special, indirect and consequential damages.
25  *
26  * Revision History:
27  * 01-Nov-2000: Allocation checks
28  * 10-May-1997: Compatible with xscreensaver
29  * 16-Apr-1997: -neighbors 3 and 8 added
30  * 01-Jan-1997: 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-1996: -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-1995: Memory leak in ant fixed.  Now random colors.
38  * 05-Sep-1995: 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 Neighbors
47   ------- ----     ------------------
48   Ants    Square   4 (or 8)
49   Bees    Hexagon  6
50   Bees    Triangle 3 (or 9, 12)
51
52   Neighbors 6 and neighbors 3 produce the same Turk ants.
53 */
54
55 #ifndef HAVE_COCOA
56 # define DO_STIPPLE
57 #endif
58
59 #ifdef STANDALONE
60 # define MODE_ant
61 # define DEFAULTS       "*delay:   1000  \n" \
62                                         "*count:   -3    \n" \
63                                         "*cycles:  40000 \n" \
64                                         "*size:    -12   \n" \
65                                         "*ncolors: 64    \n"
66 # define reshape_ant 0
67 # define ant_handle_event 0
68 # include "xlockmore.h"         /* in xscreensaver distribution */
69 # include "erase.h"
70 #else /* STANDALONE */
71 # include "xlock.h"             /* in xlockmore distribution */
72 #endif /* STANDALONE */
73 #include "automata.h"
74
75 #ifdef MODE_ant
76
77 /*-
78  * neighbors of 0 randomizes it for 3, 4, 6, 8, 12 (last 2 are less likely)
79  */
80
81 #define DEF_NEIGHBORS  "0"      /* choose random value */
82 #define DEF_TRUCHET  "False"
83 #define DEF_EYES  "False"
84 #define DEF_SHARPTURN  "False"
85
86 static int  neighbors;
87 static Bool truchet;
88 static Bool eyes;
89 static Bool sharpturn;
90
91 static XrmOptionDescRec opts[] =
92 {
93         {"-neighbors", ".ant.neighbors", XrmoptionSepArg, 0},
94         {"-truchet", ".ant.truchet", XrmoptionNoArg, "on"},
95         {"+truchet", ".ant.truchet", XrmoptionNoArg, "off"},
96         {"-eyes", ".ant.eyes", XrmoptionNoArg, "on"},
97         {"+eyes", ".ant.eyes", XrmoptionNoArg, "off"},
98         {"-sharpturn", ".ant.sharpturn", XrmoptionNoArg, "on"},
99         {"+sharpturn", ".ant.sharpturn", XrmoptionNoArg, "off"},
100 };
101 static argtype vars[] =
102 {
103         {&neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int},
104         {&truchet,   "truchet",   "Truchet",   DEF_TRUCHET,   t_Bool},
105         {&eyes,      "eyes",      "Eyes",      DEF_EYES,      t_Bool},
106     {&sharpturn, "sharpturn", "SharpTurn", DEF_SHARPTURN, t_Bool},
107 };
108 static OptionStruct desc[] =
109 {
110         {"-neighbors num", "squares 4 or 8, hexagons 6, triangles 3 or 12"},
111         {"-/+truchet", "turn on/off Truchet lines"},
112         {"-/+eyes", "turn on/off eyes"},
113         {"-/+sharpturn", "turn on/off sharp turns (6, 8 or 12 neighbors only)"}
114 };
115
116 ENTRYPOINT ModeSpecOpt ant_opts =
117 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
118
119 #ifdef USE_MODULES
120 const ModStruct ant_description =
121 {"ant",
122  "init_ant", "draw_ant", "release_ant",
123  "refresh_ant", "init_ant", (char *) NULL, &ant_opts,
124  1000, -3, 40000, -12, 64, 1.0, "",
125  "Shows Langton's and Turk's generalized ants", 0, NULL};
126
127 #endif
128
129 #define ANTBITS(n,w,h)\
130   if ((ap->pixmaps[ap->init_bits]=\
131   XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
132   free_ant(display,ap); return;} else {ap->init_bits++;}
133
134 /* If you change the table you may have to change the following 2 constants */
135 #define STATES 2
136 #define MINANTS 1
137 #define REDRAWSTEP 2000         /* How much tape to draw per cycle */
138 #define MINGRIDSIZE 24
139 #define MINSIZE 1
140 #define MINRANDOMSIZE 5
141 #define ANGLES 360
142
143 typedef struct {
144         unsigned char color;
145         short       direction;
146         unsigned char next;
147 } statestruct;
148
149 typedef struct {
150         int         col, row;
151         short       direction;
152         unsigned char state;
153 } antstruct;
154
155 typedef struct {
156         Bool        painted;
157         int         neighbors;
158         int         generation;
159         int         xs, ys;
160         int         xb, yb;
161         int         init_dir;
162         int         nrows, ncols;
163         int         width, height;
164         unsigned char ncolors, nstates;
165         int         n;
166         int         redrawing, redrawpos;
167         int         truchet;    /* Only for Turk modes */
168         int         eyes;
169         int         sharpturn;
170         statestruct machine[NUMSTIPPLES * STATES];
171         unsigned char *tape;
172         unsigned char *truchet_state;
173         antstruct  *ants;
174         int         init_bits;
175         unsigned char colors[NUMSTIPPLES - 1];
176         GC          stippledGC;
177         Pixmap      pixmaps[NUMSTIPPLES - 1];
178         union {
179                 XPoint      hexagon[7];         /* Need more than 6 for truchet */
180                 XPoint      triangle[2][4];     /* Need more than 3 for truchet */
181         } shape;
182 #ifdef STANDALONE
183   eraser_state *eraser;
184 #endif
185 } antfarmstruct;
186
187 static char plots[] =
188 {3, 4, 6, 8,
189 #ifdef NUMBER_9
190  9,
191 #endif
192  12};
193
194 #define NEIGHBORKINDS ((long) (sizeof plots / sizeof *plots))
195 #define GOODNEIGHBORKINDS 3
196
197 /* Relative ant moves */
198 #define FS 0                    /* Step */
199 #define TRS 1                   /* Turn right, then step */
200 #define THRS 2                  /* Turn hard right, then step */
201 #define TBS 3                   /* Turn back, then step */
202 #define THLS 4                  /* Turn hard left, then step */
203 #define TLS 5                   /* Turn left, then step */
204 #define SF 6                    /* Step */
205 #define STR 7                   /* Step then turn right */
206 #define STHR 8                  /* Step then turn hard right */
207 #define STB 9                   /* Step then turn back */
208 #define STHL 10                 /* Step then turn hard left */
209 #define STL 11                  /* Step then turn left */
210
211 static antfarmstruct *antfarms = (antfarmstruct *) NULL;
212
213 /* LANGTON'S ANT (10) Chaotic after 500, Builder after 10,000 (104p) */
214 /* TURK'S 100 ANT Always chaotic?, tested past 150,000,000 */
215 /* TURK'S 101 ANT Always chaotic? */
216 /* TURK'S 110 ANT Builder at 150 (18p) */
217 /* TURK'S 1000 ANT Always chaotic? */
218 /* TURK'S 1100 SYMMETRIC ANT  all even run 1's and 0's are symmetric */
219 /* other examples 1001, 110011, 110000, 1001101 */
220 /* TURK'S 1101 ANT Builder after 250,000 (388p) */
221 /* Once saw a chess horse type builder (i.e. non-45 degree builder) */
222
223 /* BEE ONLY */
224 /* All alternating 10 appear symmetric, no proof (i.e. 10, 1010, etc) */
225 /* Even runs of 0's and 1's are also symmetric */
226 /* I have seen Hexagonal builders but they are more rare. */
227
228 static unsigned char tables[][3 * NUMSTIPPLES * STATES + 2] =
229 {
230 #if 0
231   /* Here just so you can figure out notation */
232         {                       /* Langton's ant */
233                 2, 1,
234                 1, TLS, 0, 0, TRS, 0
235         },
236 #else
237   /* First 2 numbers are the size (ncolors, nstates) */
238         {                       /* LADDER BUILDER */
239                 4, 1,
240                 1, STR, 0, 2, STL, 0, 3, TRS, 0, 0, TLS, 0
241         },
242         {                       /* SPIRALING PATTERN */
243                 2, 2,
244                 1, TLS, 0, 0, FS, 1,
245                 1, TRS, 0, 1, TRS, 0
246         },
247         {                       /* SQUARE (HEXAGON) BUILDER */
248                 2, 2,
249                 1, TLS, 0, 0, FS, 1,
250                 0, TRS, 0, 1, TRS, 0
251         },
252 #endif
253 };
254
255 #define NTABLES   (sizeof tables / sizeof tables[0])
256
257 static void
258 position_of_neighbor(antfarmstruct * ap, int dir, int *pcol, int *prow)
259 {
260         int         col = *pcol, row = *prow;
261
262         if (ap->neighbors == 6) {
263                 switch (dir) {
264                         case 0:
265                                 col = (col + 1 == ap->ncols) ? 0 : col + 1;
266                                 break;
267                         case 60:
268                                 if (!(row & 1))
269                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
270                                 row = (!row) ? ap->nrows - 1 : row - 1;
271                                 break;
272                         case 120:
273                                 if (row & 1)
274                                         col = (!col) ? ap->ncols - 1 : col - 1;
275                                 row = (!row) ? ap->nrows - 1 : row - 1;
276                                 break;
277                         case 180:
278                                 col = (!col) ? ap->ncols - 1 : col - 1;
279                                 break;
280                         case 240:
281                                 if (row & 1)
282                                         col = (!col) ? ap->ncols - 1 : col - 1;
283                                 row = (row + 1 == ap->nrows) ? 0 : row + 1;
284                                 break;
285                         case 300:
286                                 if (!(row & 1))
287                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
288                                 row = (row + 1 == ap->nrows) ? 0 : row + 1;
289                                 break;
290                         default:
291                                 (void) fprintf(stderr, "wrong direction %d\n", dir);
292                 }
293         } else if (ap->neighbors == 4 || ap->neighbors == 8) {
294                 switch (dir) {
295                         case 0:
296                                 col = (col + 1 == ap->ncols) ? 0 : col + 1;
297                                 break;
298                         case 45:
299                                 col = (col + 1 == ap->ncols) ? 0 : col + 1;
300                                 row = (!row) ? ap->nrows - 1 : row - 1;
301                                 break;
302                         case 90:
303                                 row = (!row) ? ap->nrows - 1 : row - 1;
304                                 break;
305                         case 135:
306                                 col = (!col) ? ap->ncols - 1 : col - 1;
307                                 row = (!row) ? ap->nrows - 1 : row - 1;
308                                 break;
309                         case 180:
310                                 col = (!col) ? ap->ncols - 1 : col - 1;
311                                 break;
312                         case 225:
313                                 col = (!col) ? ap->ncols - 1 : col - 1;
314                                 row = (row + 1 == ap->nrows) ? 0 : row + 1;
315                                 break;
316                         case 270:
317                                 row = (row + 1 == ap->nrows) ? 0 : row + 1;
318                                 break;
319                         case 315:
320                                 col = (col + 1 == ap->ncols) ? 0 : col + 1;
321                                 row = (row + 1 == ap->nrows) ? 0 : row + 1;
322                                 break;
323                         default:
324                                 (void) fprintf(stderr, "wrong direction %d\n", dir);
325                 }
326         } else {                /* TRI */
327                 if ((col + row) % 2) {  /* right */
328                         switch (dir) {
329                                 case 0:
330                                         col = (!col) ? ap->ncols - 1 : col - 1;
331                                         break;
332                                 case 30:
333                                 case 40:
334                                         col = (!col) ? ap->ncols - 1 : col - 1;
335                                         row = (!row) ? ap->nrows - 1 : row - 1;
336                                         break;
337                                 case 60:
338                                         col = (!col) ? ap->ncols - 1 : col - 1;
339                                         if (!row)
340                                                 row = ap->nrows - 2;
341                                         else if (!(row - 1))
342                                                 row = ap->nrows - 1;
343                                         else
344                                                 row = row - 2;
345                                         break;
346                                 case 80:
347                                 case 90:
348                                         if (!row)
349                                                 row = ap->nrows - 2;
350                                         else if (!(row - 1))
351                                                 row = ap->nrows - 1;
352                                         else
353                                                 row = row - 2;
354                                         break;
355                                 case 120:
356                                         row = (!row) ? ap->nrows - 1 : row - 1;
357                                         break;
358                                 case 150:
359                                 case 160:
360                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
361                                         row = (!row) ? ap->nrows - 1 : row - 1;
362                                         break;
363                                 case 180:
364                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
365                                         break;
366                                 case 200:
367                                 case 210:
368                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
369                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
370                                         break;
371                                 case 240:
372                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
373                                         break;
374                                 case 270:
375                                 case 280:
376                                         if (row + 1 == ap->nrows)
377                                                 row = 1;
378                                         else if (row + 2 == ap->nrows)
379                                                 row = 0;
380                                         else
381                                                 row = row + 2;
382                                         break;
383                                 case 300:
384                                         col = (!col) ? ap->ncols - 1 : col - 1;
385                                         if (row + 1 == ap->nrows)
386                                                 row = 1;
387                                         else if (row + 2 == ap->nrows)
388                                                 row = 0;
389                                         else
390                                                 row = row + 2;
391                                         break;
392                                 case 320:
393                                 case 330:
394                                         col = (!col) ? ap->ncols - 1 : col - 1;
395                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
396                                         break;
397                                 default:
398                                         (void) fprintf(stderr, "wrong direction %d\n", dir);
399                         }
400                 } else {        /* left */
401                         switch (dir) {
402                                 case 0:
403                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
404                                         break;
405                                 case 30:
406                                 case 40:
407                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
408                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
409                                         break;
410                                 case 60:
411                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
412                                         if (row + 1 == ap->nrows)
413                                                 row = 1;
414                                         else if (row + 2 == ap->nrows)
415                                                 row = 0;
416                                         else
417                                                 row = row + 2;
418                                         break;
419                                 case 80:
420                                 case 90:
421                                         if (row + 1 == ap->nrows)
422                                                 row = 1;
423                                         else if (row + 2 == ap->nrows)
424                                                 row = 0;
425                                         else
426                                                 row = row + 2;
427                                         break;
428                                 case 120:
429                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
430                                         break;
431                                 case 150:
432                                 case 160:
433                                         col = (!col) ? ap->ncols - 1 : col - 1;
434                                         row = (row + 1 == ap->nrows) ? 0 : row + 1;
435                                         break;
436                                 case 180:
437                                         col = (!col) ? ap->ncols - 1 : col - 1;
438                                         break;
439                                 case 200:
440                                 case 210:
441                                         col = (!col) ? ap->ncols - 1 : col - 1;
442                                         row = (!row) ? ap->nrows - 1 : row - 1;
443                                         break;
444                                 case 240:
445                                         row = (!row) ? ap->nrows - 1 : row - 1;
446                                         break;
447                                 case 270:
448                                 case 280:
449                                         if (!row)
450                                                 row = ap->nrows - 2;
451                                         else if (row == 1)
452                                                 row = ap->nrows - 1;
453                                         else
454                                                 row = row - 2;
455                                         break;
456                                 case 300:
457                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
458                                         if (!row)
459                                                 row = ap->nrows - 2;
460                                         else if (row == 1)
461                                                 row = ap->nrows - 1;
462                                         else
463                                                 row = row - 2;
464                                         break;
465                                 case 320:
466                                 case 330:
467                                         col = (col + 1 == ap->ncols) ? 0 : col + 1;
468                                         row = (!row) ? ap->nrows - 1 : row - 1;
469                                         break;
470                                 default:
471                                         (void) fprintf(stderr, "wrong direction %d\n", dir);
472                         }
473                 }
474         }
475         *pcol = col;
476         *prow = row;
477 }
478
479 static void
480 fillcell(ModeInfo * mi, GC gc, int col, int row)
481 {
482         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
483
484         if (ap->neighbors == 6) {
485                 int         ccol = 2 * col + !(row & 1), crow = 2 * row;
486
487                 ap->shape.hexagon[0].x = ap->xb + ccol * ap->xs;
488                 ap->shape.hexagon[0].y = ap->yb + crow * ap->ys;
489                 if (ap->xs == 1 && ap->ys == 1)
490                         XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
491                         ap->shape.hexagon[0].x, ap->shape.hexagon[0].y);
492                 else
493                         XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
494                             ap->shape.hexagon, 6, Convex, CoordModePrevious);
495         } else if (ap->neighbors == 4 || ap->neighbors == 8) {
496                 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
497                 ap->xb + ap->xs * col, ap->yb + ap->ys * row,
498                 ap->xs - (ap->xs > 3), ap->ys - (ap->ys > 3));
499         } else {                /* TRI */
500                 int         orient = (col + row) % 2;   /* O left 1 right */
501
502                 ap->shape.triangle[orient][0].x = ap->xb + col * ap->xs;
503                 ap->shape.triangle[orient][0].y = ap->yb + row * ap->ys;
504                 if (ap->xs <= 3 || ap->ys <= 3)
505                         XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
506                         ((orient) ? -1 : 1) + ap->shape.triangle[orient][0].x,
507                                        ap->shape.triangle[orient][0].y);
508                 else {
509                         if (orient)
510                                 ap->shape.triangle[orient][0].x += (ap->xs / 2 - 1);
511                         else
512                                 ap->shape.triangle[orient][0].x -= (ap->xs / 2 - 1);
513                         XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
514                                      ap->shape.triangle[orient], 3, Convex, CoordModePrevious);
515                 }
516         }
517 }
518
519 static void
520 truchetcell(ModeInfo * mi, int col, int row, int truchetstate)
521 {
522         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
523
524         if (ap->neighbors == 6) {
525
526                 int         ccol = 2 * col + !(row & 1), crow = 2 * row;
527                 int         side;
528                 int         fudge = 7;  /* fudge because the hexagons are not exact */
529                 XPoint      hex, hex2;
530
531                 if (ap->sharpturn) {
532                         hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs / 2.0) - 1;
533                         hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys / 2.0) - 1;
534                         for (side = 0; side < 6; side++) {
535                                 if (side) {
536                                         hex.x += ap->shape.hexagon[side].x;
537                                         hex.y += ap->shape.hexagon[side].y;
538                                 }
539                                 if (truchetstate == side % 2)
540                                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
541                                                  hex.x, hex.y, ap->xs, ap->ys,
542                                                  ((570 - (side * 60) + fudge) % 360) * 64, (120 - 2 * fudge) * 64);
543                         }
544                 } else {
545                         /* Very crude approx of Sqrt 3, so it will not cause drawing errors. */
546                         hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs * 1.6 / 2.0) - 1;
547                         hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys * 1.6 / 2.0) - 1;
548                         for (side = 0; side < 6; side++) {
549                                 if (side) {
550                                         hex.x += ap->shape.hexagon[side].x;
551                                         hex.y += ap->shape.hexagon[side].y;
552                                 }
553                                 hex2.x = hex.x + ap->shape.hexagon[side + 1].x / 2;
554                                 hex2.y = hex.y + ap->shape.hexagon[side + 1].y / 2 + 1;
555                                 /* Lots of fudging here */
556                                 if (side == 1) {
557                                         hex2.x += (short) (ap->xs * 0.1 + 1);
558                                         hex2.y += (short) (ap->ys * 0.1 - ((ap->ys > 5) ? 1 : 0));
559                                 } else if (side == 2) {
560                                         hex2.x += (short) (ap->xs * 0.1);
561                                 } else if (side == 4) {
562                                         hex2.x += (short) (ap->xs * 0.1);
563                                         hex2.y += (short) (ap->ys * 0.1 - 1);
564                                 } else if (side == 5) {
565                                         hex2.x += (short) (ap->xs * 0.5);
566                                         hex2.y += (short) (-ap->ys * 0.3 + 1);
567                                 }
568                                 if (truchetstate == side % 3)
569                                         /* Crude approx of 120 deg, so it will not cause drawing errors. */
570                                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
571                                                  hex2.x, hex2.y,
572                                                  (int) ((double) ap->xs * 1.5), (int) ((double) ap->ys * 1.5),
573                                                  ((555 - (side * 60)) % 360) * 64, 90 * 64);
574                         }
575                 }
576         } else if (ap->neighbors == 4) {
577                 if (truchetstate) {
578                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
579                                  ap->xb + ap->xs * col - ap->xs / 2 + 1,
580                                  ap->yb + ap->ys * row + ap->ys / 2 - 1,
581                                  ap->xs - 2, ap->ys - 2,
582                                  0 * 64, 90 * 64);
583                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
584                                  ap->xb + ap->xs * col + ap->xs / 2 - 1,
585                                  ap->yb + ap->ys * row - ap->ys / 2 + 1,
586                                  ap->xs - 2, ap->ys - 2,
587                                  -90 * 64, -90 * 64);
588                 } else {
589                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
590                                  ap->xb + ap->xs * col - ap->xs / 2 + 1,
591                                  ap->yb + ap->ys * row - ap->ys / 2 + 1,
592                                  ap->xs - 2, ap->ys - 2,
593                                  0 * 64, -90 * 64);
594                         XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
595                                  ap->xb + ap->xs * col + ap->xs / 2 - 1,
596                                  ap->yb + ap->ys * row + ap->ys / 2 - 1,
597                                  ap->xs - 2, ap->ys - 2,
598                                  90 * 64, 90 * 64);
599                 }
600         } else if (ap->neighbors == 3) {
601                 int         orient = (col + row) % 2;   /* O left 1 right */
602                 int         side, ang;
603                 int         fudge = 7;  /* fudge because the triangles are not exact */
604                 double      fudge2 = 1.18;
605                 XPoint      tri;
606
607                 tri.x = ap->xb + col * ap->xs;
608                 tri.y = ap->yb + row * ap->ys;
609                 if (orient) {
610                         tri.x += (ap->xs / 2 - 1);
611                 } else {
612                         tri.x -= (ap->xs / 2 - 1);
613                 }
614                 for (side = 0; side < 3; side++) {
615                         if (side > 0) {
616                                 tri.x += ap->shape.triangle[orient][side].x;
617                                 tri.y += ap->shape.triangle[orient][side].y;
618                         }
619                         if (truchetstate == side) {
620                                 if (orient)
621                                         ang = (510 - side * 120) % 360;         /* Right */
622                                 else
623                                         ang = (690 - side * 120) % 360;         /* Left */
624                                 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
625                                   (int) (tri.x - ap->xs * fudge2 / 2),
626           (int) (tri.y - 3 * ap->ys * fudge2 / 4),
627                                   (unsigned int) (ap->xs * fudge2),
628           (unsigned int) (3 * ap->ys * fudge2 / 2),
629                                   (ang + fudge) * 64, (60 - 2 * fudge) * 64);
630                         }
631                 }
632         }
633 }
634
635 static void
636 drawcell(ModeInfo * mi, int col, int row, unsigned char color)
637 {
638         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
639         GC          gc;
640
641         if (!color) {
642                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
643                 gc = MI_GC(mi);
644         } else if (MI_NPIXELS(mi) > 2) {
645                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
646                                MI_PIXEL(mi, ap->colors[color - 1]));
647                 gc = MI_GC(mi);
648         } else {
649                 XGCValues   gcv;
650
651 #ifdef DO_STIPPLE
652           gcv.stipple = ap->pixmaps[color - 1];
653 #endif /* DO_STIPPLE */
654                 gcv.foreground = MI_WHITE_PIXEL(mi);
655                 gcv.background = MI_BLACK_PIXEL(mi);
656                 XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
657 #ifdef DO_STIPPLE
658                           GCStipple |
659 #endif /* DO_STIPPLE */
660                           GCForeground | GCBackground, &gcv);
661                 gc = ap->stippledGC;
662         }
663         fillcell(mi, gc, col, row);
664 }
665
666 static void
667 drawtruchet(ModeInfo * mi, int col, int row,
668             unsigned char color, unsigned char truchetstate)
669 {
670         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
671
672         if (!color)
673                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
674         else if (MI_NPIXELS(mi) > 2 || color > ap->ncolors / 2)
675                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
676         else
677                 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
678         truchetcell(mi, col, row, truchetstate);
679 }
680
681 static void
682 draw_anant(ModeInfo * mi, int direction, int col, int row)
683 {
684         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
685         Display    *display = MI_DISPLAY(mi);
686         Window      window = MI_WINDOW(mi);
687
688         XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
689         fillcell(mi, MI_GC(mi), col, row);
690         if (ap->eyes) {         /* Draw Eyes */
691                 XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
692                 if (ap->neighbors == 6) {
693                         int         ccol = 2 * col + !(row & 1), crow = 2 * row;
694                         int         side, ang;
695                         XPoint      hex;
696
697                         if (!(ap->xs > 3 && ap->ys > 3))
698                                 return;
699                         hex.x = ap->xb + ccol * ap->xs;
700                         hex.y = ap->yb + crow * ap->ys + ap->ys / 2;
701                         ang = direction * ap->neighbors / ANGLES;
702                         for (side = 0; side < ap->neighbors; side++) {
703                                 if (side) {
704                                         hex.x -= ap->shape.hexagon[side].x / 2;
705                                         hex.y += ap->shape.hexagon[side].y / 2;
706                                 }
707                                 if (side == (ap->neighbors + ang - 2) % ap->neighbors)
708                                         XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y);
709                                 if (side == (ap->neighbors + ang - 1) % ap->neighbors)
710                                         XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y);
711                         }
712                 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
713                         if (!(ap->xs > 3 && ap->ys > 3))
714                                 return;
715                         switch (direction) {
716                                 case 0:
717                                         XDrawPoint(display, window, MI_GC(mi),
718                                                 ap->xb + ap->xs * (col + 1) - 3,
719                                                 ap->yb + ap->ys * row + ap->ys / 2 - 2);
720                                         XDrawPoint(display, window, MI_GC(mi),
721                                                 ap->xb + ap->xs * (col + 1) - 3,
722                                                 ap->yb + ap->ys * row + ap->ys / 2);
723                                         break;
724                                 case 45:
725                                         XDrawPoint(display, window, MI_GC(mi),
726                                                 ap->xb + ap->xs * (col + 1) - 4,
727                                                 ap->yb + ap->ys * row + 1);
728                                         XDrawPoint(display, window, MI_GC(mi),
729                                                 ap->xb + ap->xs * (col + 1) - 3,
730                                                 ap->yb + ap->ys * row + 2);
731                                         break;
732                                 case 90:
733                                         XDrawPoint(display, window, MI_GC(mi),
734                                                 ap->xb + ap->xs * col + ap->xs / 2 - 2,
735                                                 ap->yb + ap->ys * row + 1);
736                                         XDrawPoint(display, window, MI_GC(mi),
737                                                 ap->xb + ap->xs * col + ap->xs / 2,
738                                                 ap->yb + ap->ys * row + 1);
739                                         break;
740                                 case 135:
741                                         XDrawPoint(display, window, MI_GC(mi),
742                                                 ap->xb + ap->xs * col + 2,
743                                                 ap->yb + ap->ys * row + 1);
744                                         XDrawPoint(display, window, MI_GC(mi),
745                                                 ap->xb + ap->xs * col + 1,
746                                                 ap->yb + ap->ys * row + 2);
747                                         break;
748                                 case 180:
749                                         XDrawPoint(display, window, MI_GC(mi),
750                                                 ap->xb + ap->xs * col + 1,
751                                                 ap->yb + ap->ys * row + ap->ys / 2 - 2);
752                                         XDrawPoint(display, window, MI_GC(mi),
753                                                 ap->xb + ap->xs * col + 1,
754                                                 ap->yb + ap->ys * row + ap->ys / 2);
755                                         break;
756                                 case 225:
757                                         XDrawPoint(display, window, MI_GC(mi),
758                                                 ap->xb + ap->xs * col + 2,
759                                                 ap->yb + ap->ys * (row + 1) - 3);
760                                         XDrawPoint(display, window, MI_GC(mi),
761                                                 ap->xb + ap->xs * col + 1,
762                                                 ap->yb + ap->ys * (row + 1) - 4);
763                                         break;
764                                 case 270:
765                                         XDrawPoint(display, window, MI_GC(mi),
766                                                 ap->xb + ap->xs * col + ap->xs / 2 - 2,
767                                                 ap->yb + ap->ys * (row + 1) - 3);
768                                         XDrawPoint(display, window, MI_GC(mi),
769                                                 ap->xb + ap->xs * col + ap->xs / 2,
770                                                 ap->yb + ap->ys * (row + 1) - 3);
771                                         break;
772                                 case 315:
773                                         XDrawPoint(display, window, MI_GC(mi),
774                                                 ap->xb + ap->xs * (col + 1) - 4,
775                                                 ap->yb + ap->ys * (row + 1) - 3);
776                                         XDrawPoint(display, window, MI_GC(mi),
777                                                 ap->xb + ap->xs * (col + 1) - 3,
778                                                 ap->yb + ap->ys * (row + 1) - 4);
779                                         break;
780                                 default:
781                                         (void) fprintf(stderr, "wrong eyes direction %d for ant eyes\n", direction);
782                         }
783                 } else {                /* TRI */
784                         int         orient = (col + row) % 2;   /* O left 1 right */
785                         int         side, ang;
786                         XPoint      tri;
787
788                         if (!(ap->xs > 6 && ap->ys > 6))
789                                 return;
790                         tri.x = ap->xb + col * ap->xs;
791                         tri.y = ap->yb + row * ap->ys;
792                         if (orient)
793                                 tri.x += (ap->xs / 6 - 1);
794                         else
795                                 tri.x -= (ap->xs / 6 - 1);
796                         ang = direction * ap->neighbors / ANGLES;
797                         /* approx... does not work that well for even numbers */
798                         if (
799 #ifdef NUMBER_9
800                         ap->neighbors == 9 ||
801 #endif
802                         ap->neighbors == 12) {
803 #ifdef UNDER_CONSTRUCTION
804                                 /* Not sure why this does not work */
805                                 ang = ((ang + ap->neighbors / 6) / (ap->neighbors / 3)) % 3;
806 #else
807                                 return;
808 #endif
809                         }
810                         for (side = 0; side < 3; side++) {
811                                 if (side) {
812                                         tri.x += ap->shape.triangle[orient][side].x / 3;
813                                         tri.y += ap->shape.triangle[orient][side].y / 3;
814                                 }
815                                 /* Either you have the eyes in back or one eye in front */
816 #if 0
817                                 if (side == ang)
818                                         XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
819 #else
820                                 if (side == (ang + 2) % 3)
821                                         XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
822                                 if (side == (ang + 1) % 3)
823                                         XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
824 #endif
825                         }
826                 }
827         }
828 }
829
830 #if 0
831 static void
832 RandomSoup(mi)
833         ModeInfo   *mi;
834 {
835         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
836         int         row, col, mrow = 0;
837
838         for (row = 0; row < ap->nrows; ++row) {
839                 for (col = 0; col < ap->ncols; ++col) {
840                         ap->old[col + mrow] = (unsigned char) NRAND((int) ap->ncolors);
841                         drawcell(mi, col, row, ap->old[col + mrow]);
842                 }
843                 mrow += ap->nrows;
844         }
845 }
846
847 #endif
848
849 static short
850 fromTableDirection(unsigned char dir, int local_neighbors)
851 {
852         /* Crafted to work for odd number of neighbors */
853         switch (dir) {
854                 case FS:
855                         return 0;
856                 case TLS:
857                         return (ANGLES / local_neighbors);
858                 case THLS:
859                         return (2 * ANGLES / local_neighbors);
860                 case TBS:
861                         return ((local_neighbors / 2) * ANGLES / local_neighbors);
862                 case THRS:
863                         return (ANGLES - 2 * ANGLES / local_neighbors);
864                 case TRS:
865                         return (ANGLES - ANGLES / local_neighbors);
866                 case SF:
867                         return ANGLES;
868                 case STL:
869                         return (ANGLES + ANGLES / local_neighbors);
870                 case STHL:
871                         return (ANGLES + 2 * ANGLES / local_neighbors);
872                 case STB:
873                         return (ANGLES + (local_neighbors / 2) * ANGLES / local_neighbors);
874                 case STHR:
875                         return (2 * ANGLES - 2 * ANGLES / local_neighbors);
876                 case STR:
877                         return (2 * ANGLES - ANGLES / local_neighbors);
878                 default:
879                         (void) fprintf(stderr, "wrong direction %d from table\n", dir);
880         }
881         return -1;
882 }
883
884 static void
885 getTable(ModeInfo * mi, int i)
886 {
887         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
888         int         j, total;
889         unsigned char *patptr;
890
891         patptr = &tables[i][0];
892         ap->ncolors = *patptr++;
893         ap->nstates = *patptr++;
894         total = ap->ncolors * ap->nstates;
895         if (MI_IS_VERBOSE(mi))
896                 (void) fprintf(stdout,
897                                "ants %d, neighbors %d, table number %d, colors %d, states %d\n",
898                           ap->n, ap->neighbors, i, ap->ncolors, ap->nstates);
899         for (j = 0; j < total; j++) {
900                 ap->machine[j].color = *patptr++;
901                 if (ap->sharpturn && ap->neighbors > 4) {
902                         int         k = *patptr++;
903
904                         switch (k) {
905                                 case TRS:
906                                         k = THRS;
907                                         break;
908                                 case THRS:
909                                         k = TRS;
910                                         break;
911                                 case THLS:
912                                         k = TLS;
913                                         break;
914                                 case TLS:
915                                         k = THLS;
916                                         break;
917                                 case STR:
918                                         k = STHR;
919                                         break;
920                                 case STHR:
921                                         k = STR;
922                                         break;
923                                 case STHL:
924                                         k = STL;
925                                         break;
926                                 case STL:
927                                         k = STHL;
928                                         break;
929                                 default:
930                                         break;
931                         }
932                         ap->machine[j].direction = fromTableDirection(k, ap->neighbors);
933                 } else {
934                         ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors);
935                 }
936                 ap->machine[j].next = *patptr++;
937         }
938         ap->truchet = False;
939 }
940
941 static void
942 getTurk(ModeInfo * mi, int i)
943 {
944         antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
945         int         power2, j, number, total;
946
947         /* To force a number, say <i = 2;> has  i + 2 (or 4) binary digits */
948         power2 = 1 << (i + 1);
949         /* Do not want numbers which in binary are all 1's. */
950         number = NRAND(power2 - 1) + power2;
951         /* To force a particular number, say <number = 10;> */
952
953         ap->ncolors = i + 2;
954         ap->nstates = 1;
955         total = ap->ncolors * ap->nstates;
956         for (j = 0; j < total; j++) {
957                 ap->machine[j].color = (j + 1) % total;
958                 if (ap->sharpturn && ap->neighbors > 4) {
959                         ap->machine[j].direction = (power2 & number) ?
960                                 fromTableDirection(THRS, ap->neighbors) :
961                                 fromTableDirection(THLS, ap->neighbors);
962                 } else {
963                         ap->machine[j].direction = (power2 & number) ?
964                                 fromTableDirection(TRS, ap->neighbors) :
965                                 fromTableDirection(TLS, ap->neighbors);
966                 }
967                 ap->machine[j].next = 0;
968                 power2 >>= 1;
969         }
970         ap->truchet = (ap->truchet && ap->xs > 2 && ap->ys > 2 &&
971            (ap->neighbors == 3 || ap->neighbors == 4 || ap->neighbors == 6));
972         if (MI_IS_VERBOSE(mi))
973                 (void) fprintf(stdout,
974                       "ants %d, neighbors %d, Turk's number %d, colors %d\n",
975                                ap->n, ap->neighbors, number, ap->ncolors);
976 }
977
978 static void
979 free_ant(Display *display, antfarmstruct *ap)
980 {
981         int         shade;
982
983         if (ap->stippledGC != None) {
984                 XFreeGC(display, ap->stippledGC);
985                 ap->stippledGC = None;
986         }
987         for (shade = 0; shade < ap->init_bits; shade++) {
988                 XFreePixmap(display, ap->pixmaps[shade]);
989         }
990         ap->init_bits = 0;
991         if (ap->tape != NULL) {
992                 (void) free((void *) ap->tape);
993                 ap->tape = (unsigned char *) NULL;
994         }
995         if (ap->ants != NULL) {
996                 (void) free((void *) ap->ants);
997                 ap->ants = (antstruct *) NULL;
998         }
999         if (ap->truchet_state != NULL) {
1000                 (void) free((void *) ap->truchet_state);
1001                 ap->truchet_state = (unsigned char *) NULL;
1002         }
1003 }
1004
1005 ENTRYPOINT void
1006 init_ant(ModeInfo * mi)
1007 {
1008         Display    *display = MI_DISPLAY(mi);
1009         int         size = MI_SIZE(mi);
1010         antfarmstruct *ap;
1011         int         col, row, dir;
1012         int         i;
1013
1014         if (antfarms == NULL) {
1015                 if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi),
1016                                             sizeof (antfarmstruct))) == NULL)
1017                         return;
1018         }
1019         ap = &antfarms[MI_SCREEN(mi)];
1020
1021         ap->redrawing = 0;
1022 #ifdef DO_STIPPLE
1023         if (MI_NPIXELS(mi) <= 2) {
1024           Window      window = MI_WINDOW(mi);
1025           if (ap->stippledGC == None) {
1026                         XGCValues   gcv;
1027
1028                         gcv.fill_style = FillOpaqueStippled;
1029                         if ((ap->stippledGC = XCreateGC(display, window,
1030                                                         GCFillStyle,
1031                                         &gcv)) == None) {
1032                                 free_ant(display, ap);
1033                                 return;
1034                         }
1035                 }
1036                 if (ap->init_bits == 0) {
1037                         for (i = 1; i < NUMSTIPPLES; i++) {
1038                                 ANTBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
1039                         }
1040                 }
1041         }
1042 #endif /* DO_STIPPLE */
1043         ap->generation = 0;
1044         ap->n = MI_COUNT(mi);
1045         if (ap->n < -MINANTS) {
1046                 /* if ap->n is random ... the size can change */
1047                 if (ap->ants != NULL) {
1048                         (void) free((void *) ap->ants);
1049                         ap->ants = (antstruct *) NULL;
1050                 }
1051                 ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;
1052         } else if (ap->n < MINANTS)
1053                 ap->n = MINANTS;
1054
1055         ap->width = MI_WIDTH(mi);
1056         ap->height = MI_HEIGHT(mi);
1057
1058         for (i = 0; i < NEIGHBORKINDS; i++) {
1059                 if (neighbors == plots[i]) {
1060                         ap->neighbors = plots[i];
1061                         break;
1062                 }
1063                 if (i == NEIGHBORKINDS - 1) {
1064                         if (!NRAND(10)) {
1065                                 /* Make above 6 rare */
1066                                 ap->neighbors = plots[NRAND(NEIGHBORKINDS)];
1067                         } else {
1068                                 ap->neighbors = plots[NRAND(GOODNEIGHBORKINDS)];
1069                         }
1070                         break;
1071                 }
1072         }
1073
1074         if (ap->neighbors == 6) {
1075                 int         nccols, ncrows;
1076
1077                 if (ap->width < 8)
1078                         ap->width = 8;
1079                 if (ap->height < 8)
1080                         ap->height = 8;
1081                 if (size < -MINSIZE) {
1082                         ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1083                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1084                         if (ap->ys < MINRANDOMSIZE)
1085                                 ap->ys = MIN(MINRANDOMSIZE,
1086                                              MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1087                 } else if (size < MINSIZE) {
1088                         if (!size)
1089                                 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1090                         else
1091                                 ap->ys = MINSIZE;
1092                 } else
1093                         ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1094                                                MINGRIDSIZE));
1095                 ap->xs = ap->ys;
1096                 nccols = MAX(ap->width / ap->xs - 2, 2);
1097                 ncrows = MAX(ap->height / ap->ys - 1, 4);
1098                 ap->ncols = nccols / 2;
1099                 ap->nrows = 2 * (ncrows / 4);
1100                 ap->xb = (ap->width - ap->xs * nccols) / 2 + ap->xs / 2;
1101                 ap->yb = (ap->height - ap->ys * (ncrows / 2) * 2) / 2 + ap->ys - 2;
1102                 for (i = 0; i < 6; i++) {
1103                         ap->shape.hexagon[i].x = (ap->xs - 1) * hexagonUnit[i].x;
1104                         ap->shape.hexagon[i].y = ((ap->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
1105                 }
1106                 /* Avoid array bounds read of hexagonUnit */
1107                 ap->shape.hexagon[6].x = 0;
1108                 ap->shape.hexagon[6].y = 0;
1109         } else if (ap->neighbors == 4 || ap->neighbors == 8) {
1110                 if (size < -MINSIZE) {
1111                         ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1112                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1113                         if (ap->ys < MINRANDOMSIZE)
1114                                 ap->ys = MIN(MINRANDOMSIZE,
1115                                              MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1116                 } else if (size < MINSIZE) {
1117                         if (!size)
1118                                 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1119                         else
1120                                 ap->ys = MINSIZE;
1121                 } else
1122                         ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1123                                                MINGRIDSIZE));
1124                 ap->xs = ap->ys;
1125                 ap->ncols = MAX(ap->width / ap->xs, 2);
1126                 ap->nrows = MAX(ap->height / ap->ys, 2);
1127                 ap->xb = (ap->width - ap->xs * ap->ncols) / 2;
1128                 ap->yb = (ap->height - ap->ys * ap->nrows) / 2;
1129         } else {                /* TRI */
1130                 int         orient;
1131
1132                 if (ap->width < 2)
1133                         ap->width = 2;
1134                 if (ap->height < 2)
1135                         ap->height = 2;
1136                 if (size < -MINSIZE) {
1137                         ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1138                                       MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1139                         if (ap->ys < MINRANDOMSIZE)
1140                                 ap->ys = MIN(MINRANDOMSIZE,
1141                                              MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1142                 } else if (size < MINSIZE) {
1143                         if (!size)
1144                                 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1145                         else
1146                                 ap->ys = MINSIZE;
1147                 } else
1148                         ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1149                                                MINGRIDSIZE));
1150                 ap->xs = (int) (1.52 * ap->ys);
1151                 ap->ncols = (MAX(ap->width / ap->xs - 1, 2) / 2) * 2;
1152                 ap->nrows = (MAX(ap->height / ap->ys - 1, 2) / 2) * 2;
1153                 ap->xb = (ap->width - ap->xs * ap->ncols) / 2 + ap->xs / 2;
1154                 ap->yb = (ap->height - ap->ys * ap->nrows) / 2 + ap->ys;
1155                 for (orient = 0; orient < 2; orient++) {
1156                         for (i = 0; i < 3; i++) {
1157                                 ap->shape.triangle[orient][i].x =
1158                                         (ap->xs - 2) * triangleUnit[orient][i].x;
1159                                 ap->shape.triangle[orient][i].y =
1160                                         (ap->ys - 2) * triangleUnit[orient][i].y;
1161                         }
1162                         /* Avoid array bounds read of triangleUnit */
1163                         ap->shape.triangle[orient][3].x = 0;
1164                         ap->shape.triangle[orient][3].y = 0;
1165                 }
1166         }
1167
1168         XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinMiter);
1169         MI_CLEARWINDOW(mi);
1170         ap->painted = False;
1171
1172         if (MI_IS_FULLRANDOM(mi)) {
1173                 ap->truchet = (Bool) (LRAND() & 1);
1174                 ap->eyes = (Bool) (LRAND() & 1);
1175                 ap->sharpturn = (Bool) (LRAND() & 1);
1176         } else {
1177                 ap->truchet = truchet;
1178                 ap->eyes = eyes;
1179                 ap->sharpturn = sharpturn;
1180         }
1181         if (!NRAND(NUMSTIPPLES)) {
1182                 getTable(mi, (int) (NRAND(NTABLES)));
1183         } else
1184                 getTurk(mi, (int) (NRAND(NUMSTIPPLES - 1)));
1185         if (MI_NPIXELS(mi) > 2)
1186                 for (i = 0; i < (int) ap->ncolors - 1; i++)
1187                         ap->colors[i] = (unsigned char) (NRAND(MI_NPIXELS(mi)) +
1188                              i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1));
1189         if (ap->ants == NULL) {
1190                 if ((ap->ants = (antstruct *) malloc(ap->n * sizeof (antstruct))) ==
1191                                 NULL) {
1192                         free_ant(display, ap);
1193                         return;
1194                 }
1195         }
1196         if (ap->tape != NULL) 
1197                 (void) free((void *) ap->tape);
1198         if ((ap->tape = (unsigned char *) calloc(ap->ncols * ap->nrows,
1199                         sizeof (unsigned char))) == NULL) {
1200                 free_ant(display, ap);
1201                 return;
1202         }
1203         if (ap->truchet_state != NULL)
1204                 (void) free((void *) ap->truchet_state);
1205         if ((ap->truchet_state = (unsigned char *) calloc(ap->ncols * ap->nrows,
1206                         sizeof (unsigned char))) == NULL) {
1207                 free_ant(display, ap);
1208                 return;
1209         }
1210
1211         row = ap->nrows / 2;
1212         col = ap->ncols / 2;
1213         if (col > 0 && ((ap->neighbors % 2) || ap->neighbors == 12) && (LRAND() & 1))
1214                 col--;
1215         dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors;
1216         ap->init_dir = dir;
1217 #ifdef NUMBER_9
1218         if (ap->neighbors == 9 && !((col + row) & 1))
1219                 dir = (dir + ANGLES - ANGLES / (ap->neighbors * 2)) % ANGLES;
1220 #endif
1221         /* Have them all start in the same spot, why not? */
1222         for (i = 0; i < ap->n; i++) {
1223                 ap->ants[i].col = col;
1224                 ap->ants[i].row = row;
1225                 ap->ants[i].direction = dir;
1226                 ap->ants[i].state = 0;
1227         }
1228         draw_anant(mi, dir, col, row);
1229 }
1230
1231 ENTRYPOINT void
1232 draw_ant(ModeInfo * mi)
1233 {
1234         antstruct  *anant;
1235         statestruct *status;
1236         int         i, state_pos, tape_pos;
1237         unsigned char color;
1238         short       chg_dir, old_dir;
1239         antfarmstruct *ap;
1240
1241         if (antfarms == NULL)
1242                 return;
1243         ap = &antfarms[MI_SCREEN(mi)];
1244         if (ap->ants == NULL)
1245                 return;
1246
1247 #ifdef STANDALONE
1248     if (ap->eraser) {
1249       ap->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), ap->eraser);
1250       return;
1251     }
1252 #endif
1253
1254         MI_IS_DRAWN(mi) = True;
1255         ap->painted = True;
1256         for (i = 0; i < ap->n; i++) {
1257                 anant = &ap->ants[i];
1258                 tape_pos = anant->col + anant->row * ap->ncols;
1259                 color = ap->tape[tape_pos];     /* read tape */
1260                 state_pos = color + anant->state * ap->ncolors;
1261                 status = &(ap->machine[state_pos]);
1262                 drawcell(mi, anant->col, anant->row, status->color);
1263                 ap->tape[tape_pos] = status->color;     /* write on tape */
1264
1265                 /* Find direction of Bees or Ants. */
1266                 /* Translate relative direction to actual direction */
1267                 old_dir = anant->direction;
1268                 chg_dir = (2 * ANGLES - status->direction) % ANGLES;
1269                 anant->direction = (chg_dir + old_dir) % ANGLES;
1270                 if (ap->truchet) {
1271                         int         a = 0, b;
1272
1273                         if (ap->neighbors == 6) {
1274                                 if (ap->sharpturn) {
1275                                         a = (((ANGLES + anant->direction - old_dir) % ANGLES) == 240);
1276         /* should be some way of getting rid of the init_dir dependency... */
1277                                         b = !(ap->init_dir % 120);
1278                                         a = ((a && !b) || (b && !a));
1279                                         drawtruchet(mi, anant->col, anant->row, status->color, a);
1280                                 } else {
1281                                         a = (old_dir / 60) % 3;
1282                                         b = (anant->direction / 60) % 3;
1283                                         a = (a + b + 1) % 3;
1284                                         drawtruchet(mi, anant->col, anant->row, status->color, a);
1285                                 }
1286                         } else if (ap->neighbors == 4) {
1287                                 a = old_dir / 180;
1288                                 b = anant->direction / 180;
1289                                 a = ((a && !b) || (b && !a));
1290                                 drawtruchet(mi, anant->col, anant->row, status->color, a);
1291                         } else if (ap->neighbors == 3) {
1292                                 if (chg_dir == 240)
1293                                         a = (2 + anant->direction / 120) % 3;
1294                                 else
1295                                         a = (1 + anant->direction / 120) % 3;
1296                                 drawtruchet(mi, anant->col, anant->row, status->color, a);
1297                         }
1298                         ap->truchet_state[tape_pos] = a + 1;
1299                 }
1300                 anant->state = status->next;
1301
1302                 /* Allow step first and turn */
1303                 old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir);
1304 #if DEBUG
1305                 (void) printf("old_dir %d, col %d, row %d", old_dir, anant->col, anant->row);
1306 #endif
1307                 position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row));
1308 #if DEBUG
1309                 (void) printf(", ncol %d, nrow %d\n", anant->col, anant->row);
1310 #endif
1311                 draw_anant(mi, anant->direction, anant->col, anant->row);
1312         }
1313         if (++ap->generation > MI_CYCLES(mi)) {
1314 #ifdef STANDALONE
1315       ap->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), ap->eraser);
1316 #endif
1317                 init_ant(mi);
1318         }
1319         if (ap->redrawing) {
1320                 for (i = 0; i < REDRAWSTEP; i++) {
1321                         if (ap->tape[ap->redrawpos] ||
1322                          (ap->truchet && ap->truchet_state[ap->redrawpos])) {
1323                                 drawcell(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1324                                          ap->tape[ap->redrawpos]);
1325                                 if (ap->truchet)
1326                                         drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1327                                                     ap->tape[ap->redrawpos],
1328                                         ap->truchet_state[ap->redrawpos] - 1);
1329                         }
1330                         if (++(ap->redrawpos) >= ap->ncols * ap->nrows) {
1331                                 ap->redrawing = 0;
1332                                 break;
1333                         }
1334                 }
1335         }
1336 }
1337
1338 ENTRYPOINT void
1339 release_ant(ModeInfo * mi)
1340 {
1341         if (antfarms != NULL) {
1342                 int         screen;
1343
1344                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1345                         free_ant(MI_DISPLAY(mi), &antfarms[screen]);
1346                 (void) free((void *) antfarms);
1347                 antfarms = (antfarmstruct *) NULL;
1348         }
1349 }
1350
1351 ENTRYPOINT void
1352 refresh_ant(ModeInfo * mi)
1353 {
1354         antfarmstruct *ap;
1355
1356         if (antfarms == NULL)
1357                 return;
1358         ap = &antfarms[MI_SCREEN(mi)];
1359
1360         if (ap->painted) {
1361                 MI_CLEARWINDOW(mi);
1362                 ap->redrawing = 1;
1363                 ap->redrawpos = 0;
1364         }
1365 }
1366
1367 XSCREENSAVER_MODULE ("Ant", ant)
1368
1369 #endif /* MODE_ant */