source: trunk/third/xscreensaver/hacks/ant.c @ 20148

Revision 20148, 38.4 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
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
8static 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#ifdef STANDALONE
56#define MODE_ant
57#define PROGCLASS "Ant"
58#define HACK_INIT init_ant
59#define HACK_DRAW draw_ant
60#define ant_opts xlockmore_opts
61#define DEFAULTS "*delay: 1000 \n" \
62 "*count: -3 \n" \
63 "*cycles: 40000 \n" \
64 "*size: -12 \n" \
65 "*ncolors: 64 \n" \
66 "*neighbors: 0 \n" \
67 "*sharpturn: False \n"
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
86static int  neighbors;
87static Bool truchet;
88static Bool eyes;
89static Bool sharpturn;
90
91static XrmOptionDescRec opts[] =
92{
93        {(char *) "-neighbors", (char *) ".ant.neighbors", XrmoptionSepArg, (caddr_t) NULL},
94        {(char *) "-truchet", (char *) ".ant.truchet", XrmoptionNoArg, (caddr_t) "on"},
95        {(char *) "+truchet", (char *) ".ant.truchet", XrmoptionNoArg, (caddr_t) "off"},
96        {(char *) "-eyes", (char *) ".ant.eyes", XrmoptionNoArg, (caddr_t) "on"},
97        {(char *) "+eyes", (char *) ".ant.eyes", XrmoptionNoArg, (caddr_t) "off"},
98        {(char *) "-sharpturn", (char *) ".ant.sharpturn", XrmoptionNoArg, (caddr_t) "on"},
99        {(char *) "+sharpturn", (char *) ".ant.sharpturn", XrmoptionNoArg, (caddr_t) "off"},
100        {"-neighbors", ".ant.neighbors", XrmoptionSepArg, (caddr_t) 0},
101        {"+neighbors", ".ant.neighbors", XrmoptionSepArg, (caddr_t) 0}
102};
103static argtype vars[] =
104{
105        {(caddr_t *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
106        {(caddr_t *) & truchet, (char *) "truchet", (char *) "Truchet", (char *) DEF_TRUCHET, t_Bool},
107        {(caddr_t *) & eyes, (char *) "eyes", (char *) "Eyes", (char *) DEF_EYES, t_Bool},
108   {(caddr_t *) & sharpturn, (char *) "sharpturn", (char *) "SharpTurn", (char *) DEF_SHARPTURN, t_Bool},
109        {(caddr_t *) & neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int}
110};
111static OptionStruct desc[] =
112{
113        {(char *) "-neighbors num", (char *) "squares 4 or 8, hexagons 6, triangles 3 or 12"},
114        {(char *) "-/+truchet", (char *) "turn on/off Truchet lines"},
115        {(char *) "-/+eyes", (char *) "turn on/off eyes"},
116        {(char *) "-/+sharpturn", (char *) "turn on/off sharp turns (6, 8 or 12 neighbors only)"}
117};
118
119ModeSpecOpt ant_opts =
120{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
121
122#ifdef USE_MODULES
123const ModStruct ant_description =
124{"ant",
125 "init_ant", "draw_ant", "release_ant",
126 "refresh_ant", "init_ant", (char *) NULL, &ant_opts,
127 1000, -3, 40000, -12, 64, 1.0, "",
128 "Shows Langton's and Turk's generalized ants", 0, NULL};
129
130#endif
131
132#define ANTBITS(n,w,h)\
133  if ((ap->pixmaps[ap->init_bits]=\
134  XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
135  free_ant(display,ap); return;} else {ap->init_bits++;}
136
137/* If you change the table you may have to change the following 2 constants */
138#define STATES 2
139#define MINANTS 1
140#define REDRAWSTEP 2000         /* How much tape to draw per cycle */
141#define MINGRIDSIZE 24
142#define MINSIZE 1
143#define MINRANDOMSIZE 5
144#define ANGLES 360
145
146typedef struct {
147        unsigned char color;
148        short       direction;
149        unsigned char next;
150} statestruct;
151
152typedef struct {
153        int         col, row;
154        short       direction;
155        unsigned char state;
156} antstruct;
157
158typedef struct {
159        Bool        painted;
160        int         neighbors;
161        int         generation;
162        int         xs, ys;
163        int         xb, yb;
164        int         init_dir;
165        int         nrows, ncols;
166        int         width, height;
167        unsigned char ncolors, nstates;
168        int         n;
169        int         redrawing, redrawpos;
170        int         truchet;    /* Only for Turk modes */
171        int         eyes;
172        int         sharpturn;
173        statestruct machine[NUMSTIPPLES * STATES];
174        unsigned char *tape;
175        unsigned char *truchet_state;
176        antstruct  *ants;
177        int         init_bits;
178        unsigned char colors[NUMSTIPPLES - 1];
179        GC          stippledGC;
180        Pixmap      pixmaps[NUMSTIPPLES - 1];
181        union {
182                XPoint      hexagon[7];         /* Need more than 6 for truchet */
183                XPoint      triangle[2][4];     /* Need more than 3 for truchet */
184        } shape;
185} antfarmstruct;
186
187static 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
211static 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
228static 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
257static void
258position_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
479static void
480fillcell(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
519static void
520truchetcell(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
635static void
636drawcell(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                gcv.stipple = ap->pixmaps[color - 1];
652                gcv.foreground = MI_WHITE_PIXEL(mi);
653                gcv.background = MI_BLACK_PIXEL(mi);
654                XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
655                          GCStipple | GCForeground | GCBackground, &gcv);
656                gc = ap->stippledGC;
657        }
658        fillcell(mi, gc, col, row);
659}
660
661static void
662drawtruchet(ModeInfo * mi, int col, int row,
663            unsigned char color, unsigned char truchetstate)
664{
665        antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
666
667        if (!color)
668                XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
669        else if (MI_NPIXELS(mi) > 2 || color > ap->ncolors / 2)
670                XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
671        else
672                XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
673        truchetcell(mi, col, row, truchetstate);
674}
675
676static void
677draw_anant(ModeInfo * mi, int direction, int col, int row)
678{
679        antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
680        Display    *display = MI_DISPLAY(mi);
681        Window      window = MI_WINDOW(mi);
682
683        XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
684        fillcell(mi, MI_GC(mi), col, row);
685        if (ap->eyes) {         /* Draw Eyes */
686                XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
687                if (ap->neighbors == 6) {
688                        int         ccol = 2 * col + !(row & 1), crow = 2 * row;
689                        int         side, ang;
690                        XPoint      hex;
691
692                        if (!(ap->xs > 3 && ap->ys > 3))
693                                return;
694                        hex.x = ap->xb + ccol * ap->xs;
695                        hex.y = ap->yb + crow * ap->ys + ap->ys / 2;
696                        ang = direction * ap->neighbors / ANGLES;
697                        for (side = 0; side < ap->neighbors; side++) {
698                                if (side) {
699                                        hex.x -= ap->shape.hexagon[side].x / 2;
700                                        hex.y += ap->shape.hexagon[side].y / 2;
701                                }
702                                if (side == (ap->neighbors + ang - 2) % ap->neighbors)
703                                        XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y);
704                                if (side == (ap->neighbors + ang - 1) % ap->neighbors)
705                                        XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y);
706                        }
707                } else if (ap->neighbors == 4 || ap->neighbors == 8) {
708                        if (!(ap->xs > 3 && ap->ys > 3))
709                                return;
710                        switch (direction) {
711                                case 0:
712                                        XDrawPoint(display, window, MI_GC(mi),
713                                                ap->xb + ap->xs * (col + 1) - 3,
714                                                ap->yb + ap->ys * row + ap->ys / 2 - 2);
715                                        XDrawPoint(display, window, MI_GC(mi),
716                                                ap->xb + ap->xs * (col + 1) - 3,
717                                                ap->yb + ap->ys * row + ap->ys / 2);
718                                        break;
719                                case 45:
720                                        XDrawPoint(display, window, MI_GC(mi),
721                                                ap->xb + ap->xs * (col + 1) - 4,
722                                                ap->yb + ap->ys * row + 1);
723                                        XDrawPoint(display, window, MI_GC(mi),
724                                                ap->xb + ap->xs * (col + 1) - 3,
725                                                ap->yb + ap->ys * row + 2);
726                                        break;
727                                case 90:
728                                        XDrawPoint(display, window, MI_GC(mi),
729                                                ap->xb + ap->xs * col + ap->xs / 2 - 2,
730                                                ap->yb + ap->ys * row + 1);
731                                        XDrawPoint(display, window, MI_GC(mi),
732                                                ap->xb + ap->xs * col + ap->xs / 2,
733                                                ap->yb + ap->ys * row + 1);
734                                        break;
735                                case 135:
736                                        XDrawPoint(display, window, MI_GC(mi),
737                                                ap->xb + ap->xs * col + 2,
738                                                ap->yb + ap->ys * row + 1);
739                                        XDrawPoint(display, window, MI_GC(mi),
740                                                ap->xb + ap->xs * col + 1,
741                                                ap->yb + ap->ys * row + 2);
742                                        break;
743                                case 180:
744                                        XDrawPoint(display, window, MI_GC(mi),
745                                                ap->xb + ap->xs * col + 1,
746                                                ap->yb + ap->ys * row + ap->ys / 2 - 2);
747                                        XDrawPoint(display, window, MI_GC(mi),
748                                                ap->xb + ap->xs * col + 1,
749                                                ap->yb + ap->ys * row + ap->ys / 2);
750                                        break;
751                                case 225:
752                                        XDrawPoint(display, window, MI_GC(mi),
753                                                ap->xb + ap->xs * col + 2,
754                                                ap->yb + ap->ys * (row + 1) - 3);
755                                        XDrawPoint(display, window, MI_GC(mi),
756                                                ap->xb + ap->xs * col + 1,
757                                                ap->yb + ap->ys * (row + 1) - 4);
758                                        break;
759                                case 270:
760                                        XDrawPoint(display, window, MI_GC(mi),
761                                                ap->xb + ap->xs * col + ap->xs / 2 - 2,
762                                                ap->yb + ap->ys * (row + 1) - 3);
763                                        XDrawPoint(display, window, MI_GC(mi),
764                                                ap->xb + ap->xs * col + ap->xs / 2,
765                                                ap->yb + ap->ys * (row + 1) - 3);
766                                        break;
767                                case 315:
768                                        XDrawPoint(display, window, MI_GC(mi),
769                                                ap->xb + ap->xs * (col + 1) - 4,
770                                                ap->yb + ap->ys * (row + 1) - 3);
771                                        XDrawPoint(display, window, MI_GC(mi),
772                                                ap->xb + ap->xs * (col + 1) - 3,
773                                                ap->yb + ap->ys * (row + 1) - 4);
774                                        break;
775                                default:
776                                        (void) fprintf(stderr, "wrong eyes direction %d for ant eyes\n", direction);
777                        }
778                } else {                /* TRI */
779                        int         orient = (col + row) % 2;   /* O left 1 right */
780                        int         side, ang;
781                        XPoint      tri;
782
783                        if (!(ap->xs > 6 && ap->ys > 6))
784                                return;
785                        tri.x = ap->xb + col * ap->xs;
786                        tri.y = ap->yb + row * ap->ys;
787                        if (orient)
788                                tri.x += (ap->xs / 6 - 1);
789                        else
790                                tri.x -= (ap->xs / 6 - 1);
791                        ang = direction * ap->neighbors / ANGLES;
792                        /* approx... does not work that well for even numbers */
793                        if (
794#ifdef NUMBER_9
795                        ap->neighbors == 9 ||
796#endif
797                        ap->neighbors == 12) {
798#ifdef UNDER_CONSTRUCTION
799                                /* Not sure why this does not work */
800                                ang = ((ang + ap->neighbors / 6) / (ap->neighbors / 3)) % 3;
801#else
802                                return;
803#endif
804                        }
805                        for (side = 0; side < 3; side++) {
806                                if (side) {
807                                        tri.x += ap->shape.triangle[orient][side].x / 3;
808                                        tri.y += ap->shape.triangle[orient][side].y / 3;
809                                }
810                                /* Either you have the eyes in back or one eye in front */
811#if 0
812                                if (side == ang)
813                                        XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
814#else
815                                if (side == (ang + 2) % 3)
816                                        XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
817                                if (side == (ang + 1) % 3)
818                                        XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
819#endif
820                        }
821                }
822        }
823}
824
825#if 0
826static void
827RandomSoup(mi)
828        ModeInfo   *mi;
829{
830        antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
831        int         row, col, mrow = 0;
832
833        for (row = 0; row < ap->nrows; ++row) {
834                for (col = 0; col < ap->ncols; ++col) {
835                        ap->old[col + mrow] = (unsigned char) NRAND((int) ap->ncolors);
836                        drawcell(mi, col, row, ap->old[col + mrow]);
837                }
838                mrow += ap->nrows;
839        }
840}
841
842#endif
843
844static short
845fromTableDirection(unsigned char dir, int local_neighbors)
846{
847        /* Crafted to work for odd number of neighbors */
848        switch (dir) {
849                case FS:
850                        return 0;
851                case TLS:
852                        return (ANGLES / local_neighbors);
853                case THLS:
854                        return (2 * ANGLES / local_neighbors);
855                case TBS:
856                        return ((local_neighbors / 2) * ANGLES / local_neighbors);
857                case THRS:
858                        return (ANGLES - 2 * ANGLES / local_neighbors);
859                case TRS:
860                        return (ANGLES - ANGLES / local_neighbors);
861                case SF:
862                        return ANGLES;
863                case STL:
864                        return (ANGLES + ANGLES / local_neighbors);
865                case STHL:
866                        return (ANGLES + 2 * ANGLES / local_neighbors);
867                case STB:
868                        return (ANGLES + (local_neighbors / 2) * ANGLES / local_neighbors);
869                case STHR:
870                        return (2 * ANGLES - 2 * ANGLES / local_neighbors);
871                case STR:
872                        return (2 * ANGLES - ANGLES / local_neighbors);
873                default:
874                        (void) fprintf(stderr, "wrong direction %d from table\n", dir);
875        }
876        return -1;
877}
878
879static void
880getTable(ModeInfo * mi, int i)
881{
882        antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
883        int         j, total;
884        unsigned char *patptr;
885
886        patptr = &tables[i][0];
887        ap->ncolors = *patptr++;
888        ap->nstates = *patptr++;
889        total = ap->ncolors * ap->nstates;
890        if (MI_IS_VERBOSE(mi))
891                (void) fprintf(stdout,
892                               "ants %d, neighbors %d, table number %d, colors %d, states %d\n",
893                          ap->n, ap->neighbors, i, ap->ncolors, ap->nstates);
894        for (j = 0; j < total; j++) {
895                ap->machine[j].color = *patptr++;
896                if (ap->sharpturn && ap->neighbors > 4) {
897                        int         k = *patptr++;
898
899                        switch (k) {
900                                case TRS:
901                                        k = THRS;
902                                        break;
903                                case THRS:
904                                        k = TRS;
905                                        break;
906                                case THLS:
907                                        k = TLS;
908                                        break;
909                                case TLS:
910                                        k = THLS;
911                                        break;
912                                case STR:
913                                        k = STHR;
914                                        break;
915                                case STHR:
916                                        k = STR;
917                                        break;
918                                case STHL:
919                                        k = STL;
920                                        break;
921                                case STL:
922                                        k = STHL;
923                                        break;
924                                default:
925                                        break;
926                        }
927                        ap->machine[j].direction = fromTableDirection(k, ap->neighbors);
928                } else {
929                        ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors);
930                }
931                ap->machine[j].next = *patptr++;
932        }
933        ap->truchet = False;
934}
935
936static void
937getTurk(ModeInfo * mi, int i)
938{
939        antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
940        int         power2, j, number, total;
941
942        /* To force a number, say <i = 2;> has  i + 2 (or 4) binary digits */
943        power2 = 1 << (i + 1);
944        /* Do not want numbers which in binary are all 1's. */
945        number = NRAND(power2 - 1) + power2;
946        /* To force a particular number, say <number = 10;> */
947
948        ap->ncolors = i + 2;
949        ap->nstates = 1;
950        total = ap->ncolors * ap->nstates;
951        for (j = 0; j < total; j++) {
952                ap->machine[j].color = (j + 1) % total;
953                if (ap->sharpturn && ap->neighbors > 4) {
954                        ap->machine[j].direction = (power2 & number) ?
955                                fromTableDirection(THRS, ap->neighbors) :
956                                fromTableDirection(THLS, ap->neighbors);
957                } else {
958                        ap->machine[j].direction = (power2 & number) ?
959                                fromTableDirection(TRS, ap->neighbors) :
960                                fromTableDirection(TLS, ap->neighbors);
961                }
962                ap->machine[j].next = 0;
963                power2 >>= 1;
964        }
965        ap->truchet = (ap->truchet && ap->xs > 2 && ap->ys > 2 &&
966           (ap->neighbors == 3 || ap->neighbors == 4 || ap->neighbors == 6));
967        if (MI_IS_VERBOSE(mi))
968                (void) fprintf(stdout,
969                      "ants %d, neighbors %d, Turk's number %d, colors %d\n",
970                               ap->n, ap->neighbors, number, ap->ncolors);
971}
972
973static void
974free_ant(Display *display, antfarmstruct *ap)
975{
976        int         shade;
977
978        if (ap->stippledGC != None) {
979                XFreeGC(display, ap->stippledGC);
980                ap->stippledGC = None;
981        }
982        for (shade = 0; shade < ap->init_bits; shade++) {
983                XFreePixmap(display, ap->pixmaps[shade]);
984        }
985        ap->init_bits = 0;
986        if (ap->tape != NULL) {
987                (void) free((void *) ap->tape);
988                ap->tape = (unsigned char *) NULL;
989        }
990        if (ap->ants != NULL) {
991                (void) free((void *) ap->ants);
992                ap->ants = (antstruct *) NULL;
993        }
994        if (ap->truchet_state != NULL) {
995                (void) free((void *) ap->truchet_state);
996                ap->truchet_state = (unsigned char *) NULL;
997        }
998}
999
1000void
1001init_ant(ModeInfo * mi)
1002{
1003        Display    *display = MI_DISPLAY(mi);
1004        Window      window = MI_WINDOW(mi);
1005        int         size = MI_SIZE(mi);
1006        antfarmstruct *ap;
1007        int         col, row, dir;
1008        int         i;
1009
1010        if (antfarms == NULL) {
1011                if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi),
1012                                            sizeof (antfarmstruct))) == NULL)
1013                        return;
1014        }
1015        ap = &antfarms[MI_SCREEN(mi)];
1016
1017        ap->redrawing = 0;
1018        if (MI_NPIXELS(mi) <= 2) {
1019                if (ap->stippledGC == None) {
1020                        XGCValues   gcv;
1021
1022                        gcv.fill_style = FillOpaqueStippled;
1023                        if ((ap->stippledGC = XCreateGC(display, window, GCFillStyle,
1024                                        &gcv)) == None) {
1025                                free_ant(display, ap);
1026                                return;
1027                        }
1028                }
1029                if (ap->init_bits == 0) {
1030                        for (i = 1; i < NUMSTIPPLES; i++) {
1031                                ANTBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
1032                        }
1033                }
1034        }
1035        ap->generation = 0;
1036        ap->n = MI_COUNT(mi);
1037        if (ap->n < -MINANTS) {
1038                /* if ap->n is random ... the size can change */
1039                if (ap->ants != NULL) {
1040                        (void) free((void *) ap->ants);
1041                        ap->ants = (antstruct *) NULL;
1042                }
1043                ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;
1044        } else if (ap->n < MINANTS)
1045                ap->n = MINANTS;
1046
1047        ap->width = MI_WIDTH(mi);
1048        ap->height = MI_HEIGHT(mi);
1049
1050        for (i = 0; i < NEIGHBORKINDS; i++) {
1051                if (neighbors == plots[i]) {
1052                        ap->neighbors = plots[i];
1053                        break;
1054                }
1055                if (i == NEIGHBORKINDS - 1) {
1056                        if (!NRAND(10)) {
1057                                /* Make above 6 rare */
1058                                ap->neighbors = plots[NRAND(NEIGHBORKINDS)];
1059                        } else {
1060                                ap->neighbors = plots[NRAND(GOODNEIGHBORKINDS)];
1061                        }
1062                        break;
1063                }
1064        }
1065
1066        if (ap->neighbors == 6) {
1067                int         nccols, ncrows;
1068
1069                if (ap->width < 8)
1070                        ap->width = 8;
1071                if (ap->height < 8)
1072                        ap->height = 8;
1073                if (size < -MINSIZE) {
1074                        ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1075                                      MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1076                        if (ap->ys < MINRANDOMSIZE)
1077                                ap->ys = MIN(MINRANDOMSIZE,
1078                                             MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1079                } else if (size < MINSIZE) {
1080                        if (!size)
1081                                ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1082                        else
1083                                ap->ys = MINSIZE;
1084                } else
1085                        ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1086                                               MINGRIDSIZE));
1087                ap->xs = ap->ys;
1088                nccols = MAX(ap->width / ap->xs - 2, 2);
1089                ncrows = MAX(ap->height / ap->ys - 1, 4);
1090                ap->ncols = nccols / 2;
1091                ap->nrows = 2 * (ncrows / 4);
1092                ap->xb = (ap->width - ap->xs * nccols) / 2 + ap->xs / 2;
1093                ap->yb = (ap->height - ap->ys * (ncrows / 2) * 2) / 2 + ap->ys - 2;
1094                for (i = 0; i < 6; i++) {
1095                        ap->shape.hexagon[i].x = (ap->xs - 1) * hexagonUnit[i].x;
1096                        ap->shape.hexagon[i].y = ((ap->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
1097                }
1098                /* Avoid array bounds read of hexagonUnit */
1099                ap->shape.hexagon[6].x = 0;
1100                ap->shape.hexagon[6].y = 0;
1101        } else if (ap->neighbors == 4 || ap->neighbors == 8) {
1102                if (size < -MINSIZE) {
1103                        ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1104                                      MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1105                        if (ap->ys < MINRANDOMSIZE)
1106                                ap->ys = MIN(MINRANDOMSIZE,
1107                                             MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1108                } else if (size < MINSIZE) {
1109                        if (!size)
1110                                ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1111                        else
1112                                ap->ys = MINSIZE;
1113                } else
1114                        ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1115                                               MINGRIDSIZE));
1116                ap->xs = ap->ys;
1117                ap->ncols = MAX(ap->width / ap->xs, 2);
1118                ap->nrows = MAX(ap->height / ap->ys, 2);
1119                ap->xb = (ap->width - ap->xs * ap->ncols) / 2;
1120                ap->yb = (ap->height - ap->ys * ap->nrows) / 2;
1121        } else {                /* TRI */
1122                int         orient;
1123
1124                if (ap->width < 2)
1125                        ap->width = 2;
1126                if (ap->height < 2)
1127                        ap->height = 2;
1128                if (size < -MINSIZE) {
1129                        ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1130                                      MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1131                        if (ap->ys < MINRANDOMSIZE)
1132                                ap->ys = MIN(MINRANDOMSIZE,
1133                                             MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1134                } else if (size < MINSIZE) {
1135                        if (!size)
1136                                ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1137                        else
1138                                ap->ys = MINSIZE;
1139                } else
1140                        ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1141                                               MINGRIDSIZE));
1142                ap->xs = (int) (1.52 * ap->ys);
1143                ap->ncols = (MAX(ap->width / ap->xs - 1, 2) / 2) * 2;
1144                ap->nrows = (MAX(ap->height / ap->ys - 1, 2) / 2) * 2;
1145                ap->xb = (ap->width - ap->xs * ap->ncols) / 2 + ap->xs / 2;
1146                ap->yb = (ap->height - ap->ys * ap->nrows) / 2 + ap->ys;
1147                for (orient = 0; orient < 2; orient++) {
1148                        for (i = 0; i < 3; i++) {
1149                                ap->shape.triangle[orient][i].x =
1150                                        (ap->xs - 2) * triangleUnit[orient][i].x;
1151                                ap->shape.triangle[orient][i].y =
1152                                        (ap->ys - 2) * triangleUnit[orient][i].y;
1153                        }
1154                        /* Avoid array bounds read of triangleUnit */
1155                        ap->shape.triangle[orient][3].x = 0;
1156                        ap->shape.triangle[orient][3].y = 0;
1157                }
1158        }
1159
1160        XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinMiter);
1161        MI_CLEARWINDOW(mi);
1162        ap->painted = False;
1163
1164        if (MI_IS_FULLRANDOM(mi)) {
1165                ap->truchet = (Bool) (LRAND() & 1);
1166                ap->eyes = (Bool) (LRAND() & 1);
1167                ap->sharpturn = (Bool) (LRAND() & 1);
1168        } else {
1169                ap->truchet = truchet;
1170                ap->eyes = eyes;
1171                ap->sharpturn = sharpturn;
1172        }
1173        if (!NRAND(NUMSTIPPLES)) {
1174                getTable(mi, (int) (NRAND(NTABLES)));
1175        } else
1176                getTurk(mi, (int) (NRAND(NUMSTIPPLES - 1)));
1177        if (MI_NPIXELS(mi) > 2)
1178                for (i = 0; i < (int) ap->ncolors - 1; i++)
1179                        ap->colors[i] = (unsigned char) (NRAND(MI_NPIXELS(mi)) +
1180                             i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1));
1181        if (ap->ants == NULL) {
1182                if ((ap->ants = (antstruct *) malloc(ap->n * sizeof (antstruct))) ==
1183                                NULL) {
1184                        free_ant(display, ap);
1185                        return;
1186                }
1187        }
1188        if (ap->tape != NULL)
1189                (void) free((void *) ap->tape);
1190        if ((ap->tape = (unsigned char *) calloc(ap->ncols * ap->nrows,
1191                        sizeof (unsigned char))) == NULL) {
1192                free_ant(display, ap);
1193                return;
1194        }
1195        if (ap->truchet_state != NULL)
1196                (void) free((void *) ap->truchet_state);
1197        if ((ap->truchet_state = (unsigned char *) calloc(ap->ncols * ap->nrows,
1198                        sizeof (unsigned char))) == NULL) {
1199                free_ant(display, ap);
1200                return;
1201        }
1202
1203        row = ap->nrows / 2;
1204        col = ap->ncols / 2;
1205        if (col > 0 && ((ap->neighbors % 2) || ap->neighbors == 12) && (LRAND() & 1))
1206                col--;
1207        dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors;
1208        ap->init_dir = dir;
1209#ifdef NUMBER_9
1210        if (ap->neighbors == 9 && !((col + row) & 1))
1211                dir = (dir + ANGLES - ANGLES / (ap->neighbors * 2)) % ANGLES;
1212#endif
1213        /* Have them all start in the same spot, why not? */
1214        for (i = 0; i < ap->n; i++) {
1215                ap->ants[i].col = col;
1216                ap->ants[i].row = row;
1217                ap->ants[i].direction = dir;
1218                ap->ants[i].state = 0;
1219        }
1220        draw_anant(mi, dir, col, row);
1221}
1222
1223void
1224draw_ant(ModeInfo * mi)
1225{
1226        antstruct  *anant;
1227        statestruct *status;
1228        int         i, state_pos, tape_pos;
1229        unsigned char color;
1230        short       chg_dir, old_dir;
1231        antfarmstruct *ap;
1232
1233        if (antfarms == NULL)
1234                return;
1235        ap = &antfarms[MI_SCREEN(mi)];
1236        if (ap->ants == NULL)
1237                return;
1238
1239        MI_IS_DRAWN(mi) = True;
1240        ap->painted = True;
1241        for (i = 0; i < ap->n; i++) {
1242                anant = &ap->ants[i];
1243                tape_pos = anant->col + anant->row * ap->ncols;
1244                color = ap->tape[tape_pos];     /* read tape */
1245                state_pos = color + anant->state * ap->ncolors;
1246                status = &(ap->machine[state_pos]);
1247                drawcell(mi, anant->col, anant->row, status->color);
1248                ap->tape[tape_pos] = status->color;     /* write on tape */
1249
1250                /* Find direction of Bees or Ants. */
1251                /* Translate relative direction to actual direction */
1252                old_dir = anant->direction;
1253                chg_dir = (2 * ANGLES - status->direction) % ANGLES;
1254                anant->direction = (chg_dir + old_dir) % ANGLES;
1255                if (ap->truchet) {
1256                        int         a = 0, b;
1257
1258                        if (ap->neighbors == 6) {
1259                                if (ap->sharpturn) {
1260                                        a = (((ANGLES + anant->direction - old_dir) % ANGLES) == 240);
1261        /* should be some way of getting rid of the init_dir dependency... */
1262                                        b = !(ap->init_dir % 120);
1263                                        a = ((a && !b) || (b && !a));
1264                                        drawtruchet(mi, anant->col, anant->row, status->color, a);
1265                                } else {
1266                                        a = (old_dir / 60) % 3;
1267                                        b = (anant->direction / 60) % 3;
1268                                        a = (a + b + 1) % 3;
1269                                        drawtruchet(mi, anant->col, anant->row, status->color, a);
1270                                }
1271                        } else if (ap->neighbors == 4) {
1272                                a = old_dir / 180;
1273                                b = anant->direction / 180;
1274                                a = ((a && !b) || (b && !a));
1275                                drawtruchet(mi, anant->col, anant->row, status->color, a);
1276                        } else if (ap->neighbors == 3) {
1277                                if (chg_dir == 240)
1278                                        a = (2 + anant->direction / 120) % 3;
1279                                else
1280                                        a = (1 + anant->direction / 120) % 3;
1281                                drawtruchet(mi, anant->col, anant->row, status->color, a);
1282                        }
1283                        ap->truchet_state[tape_pos] = a + 1;
1284                }
1285                anant->state = status->next;
1286
1287                /* Allow step first and turn */
1288                old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir);
1289#if DEBUG
1290                (void) printf("old_dir %d, col %d, row %d", old_dir, anant->col, anant->row);
1291#endif
1292                position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row));
1293#if DEBUG
1294                (void) printf(", ncol %d, nrow %d\n", anant->col, anant->row);
1295#endif
1296                draw_anant(mi, anant->direction, anant->col, anant->row);
1297        }
1298        if (++ap->generation > MI_CYCLES(mi)) {
1299#ifdef STANDALONE
1300          erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
1301#endif
1302                init_ant(mi);
1303        }
1304        if (ap->redrawing) {
1305                for (i = 0; i < REDRAWSTEP; i++) {
1306                        if (ap->tape[ap->redrawpos] ||
1307                         (ap->truchet && ap->truchet_state[ap->redrawpos])) {
1308                                drawcell(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1309                                         ap->tape[ap->redrawpos]);
1310                                if (ap->truchet)
1311                                        drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1312                                                    ap->tape[ap->redrawpos],
1313                                        ap->truchet_state[ap->redrawpos] - 1);
1314                        }
1315                        if (++(ap->redrawpos) >= ap->ncols * ap->nrows) {
1316                                ap->redrawing = 0;
1317                                break;
1318                        }
1319                }
1320        }
1321}
1322
1323void
1324release_ant(ModeInfo * mi)
1325{
1326        if (antfarms != NULL) {
1327                int         screen;
1328
1329                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1330                        free_ant(MI_DISPLAY(mi), &antfarms[screen]);
1331                (void) free((void *) antfarms);
1332                antfarms = (antfarmstruct *) NULL;
1333        }
1334}
1335
1336void
1337refresh_ant(ModeInfo * mi)
1338{
1339        antfarmstruct *ap;
1340
1341        if (antfarms == NULL)
1342                return;
1343        ap = &antfarms[MI_SCREEN(mi)];
1344
1345        if (ap->painted) {
1346                MI_CLEARWINDOW(mi);
1347                ap->redrawing = 1;
1348                ap->redrawpos = 0;
1349        }
1350}
1351
1352#endif /* MODE_ant */
Note: See TracBrowser for help on using the repository browser.