1 /* -*- Mode: C; tab-width: 4 -*- */
3 * ant --- Chris Langton's generalized turing machine ants (also known
4 * as Greg Turk's turmites) whose tape is the screen
7 #if !defined( lint ) && !defined( SABER )
8 static const char sccsid[] = "@(#)ant.c 4.11 98/06/18 xlockmore";
13 * Copyright (c) 1995 by David Bagley.
15 * Permission to use, copy, modify, and distribute this software and its
16 * documentation for any purpose and without fee is hereby granted,
17 * provided that the above copyright notice appear in all copies and that
18 * both that copyright notice and this permission notice appear in
19 * supporting documentation.
21 * This file is provided AS IS with no warranties of any kind. The author
22 * shall have no liability with respect to the infringement of copyrights,
23 * trade secrets or any patents by this file or any part thereof. In no
24 * event will the author be liable for any lost revenue or profits or
25 * other special, indirect and consequential damages.
28 * 10-May-97: Compatible with xscreensaver
29 * 16-Apr-97: -neighbors 3 and 8 added
30 * 01-Jan-97: Updated ant.c to handle more kinds of ants. Thanks to
31 * J Austin David <Austin.David@tlogic.com>. Check it out in
32 * java at http://havoc.gtf.gatech.edu/austin He thought up the
34 * 04-Apr-96: -neighbors 6 runtime-time option added for hexagonal ants
35 * (bees), coded from an idea of Jim Propp's in Science News,
36 * Oct 28, 1995 VOL. 148 page 287
37 * 20-Sep-95: Memory leak in ant fixed. Now random colors.
38 * 05-Sep-95: Coded from A.K. Dewdney's "Computer Recreations", Scientific
39 * American Magazine" Sep 1989 pp 180-183, Mar 1990 p 121
40 * Also used Ian Stewart's Mathematical Recreations, Scientific
41 * American Jul 1994 pp 104-107
42 * also used demon.c and life.c as a guide.
46 Species Grid Number of Neigbors
47 ------- ---- ------------------
50 Bees Triangle 3 (or 9, 12)
52 Neighbors 6 and neighbors 3 produce the same Turk ants.
56 # define PROGCLASS "Ant"
57 # define HACK_INIT init_ant
58 # define HACK_DRAW draw_ant
59 # define ant_opts xlockmore_opts
60 # define DEFAULTS "*delay: 1000 \n" \
66 "*sharpturn: False \n"
67 # include "xlockmore.h" /* in xscreensaver distribution */
69 #else /* STANDALONE */
70 # include "xlock.h" /* in xlockmore distribution */
71 # include "automata.h"
72 #endif /* STANDALONE */
75 * neighbors of 0 randomizes it between 3, 4 and 6.
76 * 8, 9 12 are available also but not recommended.
83 #endif /* !STANDALONE */
85 #define DEF_TRUCHET "False"
86 #define DEF_SHARPTURN "False"
87 #define DEF_NEIGHBORS "0"
90 static Bool sharpturn;
92 static XrmOptionDescRec opts[] =
94 {"-truchet", ".ant.truchet", XrmoptionNoArg, (caddr_t) "on"},
95 {"+truchet", ".ant.truchet", XrmoptionNoArg, (caddr_t) "off"},
96 {"-sharpturn", ".ant.sharpturn", XrmoptionNoArg, (caddr_t) "on"},
97 {"+sharpturn", ".ant.sharpturn", XrmoptionNoArg, (caddr_t) "off"},
100 {"-neighbors", ".ant.neighbors", XrmoptionSepArg, (caddr_t) 0},
101 {"+neighbors", ".ant.neighbors", XrmoptionSepArg, (caddr_t) 0}
102 #endif /* STANDALONE */
105 static argtype vars[] =
107 {(caddr_t *) & truchet, "truchet", "Truchet", DEF_TRUCHET, t_Bool},
108 {(caddr_t *) & sharpturn, "sharpturn", "SharpTurn", DEF_SHARPTURN, t_Bool},
110 {(caddr_t *) & neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int}
111 #endif /* STANDALONE */
113 static OptionStruct desc[] =
115 {"-/+truchet", "turn on/off Truchet lines"},
116 {"-/+sharpturn", "turn on/off sharp turns (6 or 12 neighbors only)"}
119 ModeSpecOpt ant_opts =
120 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
123 ModStruct ant_description =
124 {"ant", "init_ant", "draw_ant", "release_ant",
125 "refresh_ant", "init_ant", NULL, &ant_opts,
126 1000, -3, 40000, -12, 64, 1.0, "",
127 "Shows Langton's and Turk's generalized ants", 0, NULL};
131 #define ANTBITS(n,w,h)\
132 ap->pixmaps[ap->init_bits++]=\
133 XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1)
135 /* If you change the table you may have to change the following 2 constants */
138 #define REDRAWSTEP 2000 /* How much tape to draw per cycle */
139 #define MINGRIDSIZE 24
141 #define MINRANDOMSIZE 5
146 #define NUMSTIPPLES 11
147 #define STIPPLESIZE 8
149 static XPoint hexagonUnit[6] =
159 static XPoint triangleUnit[2][3] =
174 static unsigned char stipples[NUMSTIPPLES][STIPPLESIZE] =
176 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* white */
177 {0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22}, /* grey+white | stripe */
178 {0x00, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00}, /* spots */
179 {0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11}, /* lt. / stripe */
180 {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, /* | bars */
181 {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa}, /* 50% grey */
182 {0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00}, /* - bars */
183 {0xee, 0xdd, 0xbb, 0x77, 0xee, 0xdd, 0xbb, 0x77}, /* dark \ stripe */
184 {0xff, 0x99, 0x99, 0xff, 0xff, 0x99, 0x99, 0xff}, /* spots */
185 {0xaa, 0xff, 0xff, 0x55, 0xaa, 0xff, 0xff, 0x55}, /* black+grey - stripe */
186 {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} /* black */
189 #endif /* STANDALONE */
211 unsigned char ncolors, nstates;
213 int redrawing, redrawpos;
214 int truchet; /* Only for Turk modes */
215 int sharpturn; /* Only for even neighbors > 4 (i.e. 6 and 12) */
216 statestruct machine[NUMSTIPPLES * STATES];
218 unsigned char *truchet_state;
221 unsigned char colors[NUMSTIPPLES - 1];
223 Pixmap pixmaps[NUMSTIPPLES - 1];
225 XPoint hexagon[7]; /* Need more than 6 for truchet */
226 XPoint triangle[2][4]; /* Need more than 3 for truchet */
230 static char plots[] =
232 #if 1 /* Without this... this mode is misnamed... */
235 6}; /* Neighborhoods, 8 just makes a mess */
237 #define NEIGHBORKINDS (long) (sizeof plots / sizeof *plots)
239 /* Relative ant moves */
240 #define FS 0 /* Step */
241 #define TRS 1 /* Turn right, then step */
242 #define THRS 2 /* Turn hard right, then step */
243 #define TBS 3 /* Turn back, then step */
244 #define THLS 4 /* Turn hard left, then step */
245 #define TLS 5 /* Turn left, then step */
246 #define SF 6 /* Step */
247 #define STR 7 /* Step then turn right */
248 #define STHR 8 /* Step then turn hard right */
249 #define STB 9 /* Step then turn back */
250 #define STHL 10 /* Step then turn hard left */
251 #define STL 11 /* Step then turn left */
253 static antfarmstruct *antfarms = NULL;
255 /* LANGTON'S ANT (10) Chaotic after 500, Builder after 10,000 (104p) */
256 /* TURK'S 100 ANT Always chaotic?, tested past 150,000,000 */
257 /* TURK'S 101 ANT Always chaotic? */
258 /* TURK'S 110 ANT Builder at 150 (18p) */
259 /* TURK'S 1000 ANT Always chaotic? */
260 /* TURK'S 1100 SYMMETRIC ANT all even run 1's and 0's are symmetric */
261 /* other examples 1001, 110011, 110000, 1001101 */
262 /* TURK'S 1101 ANT Builder after 250,000 (388p) */
263 /* Once saw a chess horse type builder (i.e. non-45 degree builder) */
266 /* All alternating 10 appear symmetric, no proof (i.e. 10, 1010, etc) */
267 /* Even runs of 0's and 1's are also symmetric */
268 /* I have seen Hexagonal builders but they are more rare. */
270 static unsigned char tables[][3 * NUMSTIPPLES * STATES + 2] =
273 /* Here just so you can figure out notation */
274 { /* Langton's ant */
279 /* First 2 numbers are the size (ncolors, nstates) */
280 { /* LADDER BUILDER */
282 1, STR, 0, 2, STL, 0, 3, TRS, 0, 0, TLS, 0
284 { /* SPIRALING PATTERN */
289 { /* SQUARE (HEXAGON) BUILDER */
297 #define NTABLES (sizeof tables / sizeof tables[0])
300 position_of_neighbor(antfarmstruct * ap, int dir, int *pcol, int *prow)
302 int col = *pcol, row = *prow;
304 if (ap->neighbors == 6) {
307 col = (col + 1 == ap->ncols) ? 0 : col + 1;
311 col = (col + 1 == ap->ncols) ? 0 : col + 1;
312 row = (!row) ? ap->nrows - 1 : row - 1;
316 col = (!col) ? ap->ncols - 1 : col - 1;
317 row = (!row) ? ap->nrows - 1 : row - 1;
320 col = (!col) ? ap->ncols - 1 : col - 1;
324 col = (!col) ? ap->ncols - 1 : col - 1;
325 row = (row + 1 == ap->nrows) ? 0 : row + 1;
329 col = (col + 1 == ap->ncols) ? 0 : col + 1;
330 row = (row + 1 == ap->nrows) ? 0 : row + 1;
333 (void) fprintf(stderr, "wrong direction %d\n", dir);
335 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
338 col = (col + 1 == ap->ncols) ? 0 : col + 1;
341 col = (col + 1 == ap->ncols) ? 0 : col + 1;
342 row = (!row) ? ap->nrows - 1 : row - 1;
345 row = (!row) ? ap->nrows - 1 : row - 1;
348 col = (!col) ? ap->ncols - 1 : col - 1;
349 row = (!row) ? ap->nrows - 1 : row - 1;
352 col = (!col) ? ap->ncols - 1 : col - 1;
355 col = (!col) ? ap->ncols - 1 : col - 1;
356 row = (row + 1 == ap->nrows) ? 0 : row + 1;
359 row = (row + 1 == ap->nrows) ? 0 : row + 1;
362 col = (col + 1 == ap->ncols) ? 0 : col + 1;
363 row = (row + 1 == ap->nrows) ? 0 : row + 1;
366 (void) fprintf(stderr, "wrong direction %d\n", dir);
369 if ((col + row) % 2) { /* right */
372 col = (!col) ? ap->ncols - 1 : col - 1;
376 col = (!col) ? ap->ncols - 1 : col - 1;
377 row = (!row) ? ap->nrows - 1 : row - 1;
380 col = (!col) ? ap->ncols - 1 : col - 1;
398 row = (!row) ? ap->nrows - 1 : row - 1;
402 col = (col + 1 == ap->ncols) ? 0 : col + 1;
403 row = (!row) ? ap->nrows - 1 : row - 1;
406 col = (col + 1 == ap->ncols) ? 0 : col + 1;
410 col = (col + 1 == ap->ncols) ? 0 : col + 1;
411 row = (row + 1 == ap->nrows) ? 0 : row + 1;
414 row = (row + 1 == ap->nrows) ? 0 : row + 1;
418 if (row + 1 == ap->nrows)
420 else if (row + 2 == ap->nrows)
426 col = (!col) ? ap->ncols - 1 : col - 1;
427 if (row + 1 == ap->nrows)
429 else if (row + 2 == ap->nrows)
436 col = (!col) ? ap->ncols - 1 : col - 1;
437 row = (row + 1 == ap->nrows) ? 0 : row + 1;
440 (void) fprintf(stderr, "wrong direction %d\n", dir);
445 col = (col + 1 == ap->ncols) ? 0 : col + 1;
449 col = (col + 1 == ap->ncols) ? 0 : col + 1;
450 row = (row + 1 == ap->nrows) ? 0 : row + 1;
453 col = (col + 1 == ap->ncols) ? 0 : col + 1;
454 if (row + 1 == ap->nrows)
456 else if (row + 2 == ap->nrows)
463 if (row + 1 == ap->nrows)
465 else if (row + 2 == ap->nrows)
471 row = (row + 1 == ap->nrows) ? 0 : row + 1;
475 col = (!col) ? ap->ncols - 1 : col - 1;
476 row = (row + 1 == ap->nrows) ? 0 : row + 1;
479 col = (!col) ? ap->ncols - 1 : col - 1;
483 col = (!col) ? ap->ncols - 1 : col - 1;
484 row = (!row) ? ap->nrows - 1 : row - 1;
487 row = (!row) ? ap->nrows - 1 : row - 1;
499 col = (col + 1 == ap->ncols) ? 0 : col + 1;
509 col = (col + 1 == ap->ncols) ? 0 : col + 1;
510 row = (!row) ? ap->nrows - 1 : row - 1;
513 (void) fprintf(stderr, "wrong direction %d\n", dir);
522 fillcell(ModeInfo * mi, GC gc, int col, int row)
524 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
526 if (ap->neighbors == 6) {
527 int ccol = 2 * col + !(row & 1), crow = 2 * row;
529 ap->shape.hexagon[0].x = ap->xb + ccol * ap->xs;
530 ap->shape.hexagon[0].y = ap->yb + crow * ap->ys;
531 if (ap->xs == 1 && ap->ys == 1)
532 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
533 ap->shape.hexagon[0].x, ap->shape.hexagon[0].y, 1, 1);
535 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
536 ap->shape.hexagon, 6, Convex, CoordModePrevious);
537 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
538 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
539 ap->xb + ap->xs * col, ap->yb + ap->ys * row,
540 ap->xs - (ap->xs > 3), ap->ys - (ap->ys > 3));
542 int orient = (col + row) % 2; /* O left 1 right */
544 ap->shape.triangle[orient][0].x = ap->xb + col * ap->xs;
545 ap->shape.triangle[orient][0].y = ap->yb + row * ap->ys;
546 if (ap->xs <= 3 || ap->ys <= 3)
547 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
548 ((orient) ? -1 : 1) + ap->shape.triangle[orient][0].x,
549 ap->shape.triangle[orient][0].y, 1, 1);
552 ap->shape.triangle[orient][0].x += (ap->xs / 2 - 1);
554 ap->shape.triangle[orient][0].x -= (ap->xs / 2 - 1);
555 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
556 ap->shape.triangle[orient], 3, Convex, CoordModePrevious);
562 truchetcell(ModeInfo * mi, int col, int row, int truchetstate)
564 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
566 if (ap->neighbors == 6) {
568 int ccol = 2 * col + !(row & 1), crow = 2 * row;
570 int fudge = 7; /* fudge because the hexagons are not exact */
574 hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs / 2.0) - 1;
575 hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys / 2.0) - 1;
576 for (side = 0; side < 6; side++) {
578 hex.x += ap->shape.hexagon[side].x;
579 hex.y += ap->shape.hexagon[side].y;
581 if (truchetstate == side % 2)
582 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
583 hex.x, hex.y, ap->xs, ap->ys,
584 ((570 - (side * 60) + fudge) % 360) * 64, (120 - 2 * fudge) * 64);
588 /* Very crude approx of Sqrt 3, so it will not cause drawing errors. */
589 hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs * 1.6 / 2.0);
590 hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys * 1.6 / 2.0);
591 for (side = 0; side < 6; side++) {
593 hex.x += ap->shape.hexagon[side].x;
594 hex.y += ap->shape.hexagon[side].y;
596 hex2.x = hex.x + ap->shape.hexagon[side + 1].x / 2;
597 hex2.y = hex.y + ap->shape.hexagon[side + 1].y / 2;
598 if (truchetstate == side % 3)
599 /* Crude approx of 120 deg, so it will not cause drawing errors. */
600 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
602 (int) ((double) ap->xs * 1.5), (int) ((double) ap->ys * 1.5),
603 ((555 - (side * 60)) % 360) * 64, 90 * 64);
606 } else if (ap->neighbors == 4) {
608 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
609 ap->xb + ap->xs * col - ap->xs / 2+ 1,
610 ap->yb + ap->ys * row + ap->ys / 2 - 1,
611 ap->xs - 2, ap->ys - 2,
613 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
614 ap->xb + ap->xs * col + ap->xs / 2 - 1,
615 ap->yb + ap->ys * row - ap->ys / 2 + 1,
616 ap->xs - 2, ap->ys - 2,
619 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
620 ap->xb + ap->xs * col - ap->xs / 2 + 1,
621 ap->yb + ap->ys * row - ap->ys / 2 + 1,
622 ap->xs - 2, ap->ys - 2,
624 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
625 ap->xb + ap->xs * col + ap->xs / 2 - 1,
626 ap->yb + ap->ys * row + ap->ys / 2 - 1,
627 ap->xs - 2, ap->ys - 2,
630 } else if (ap->neighbors == 3) {
631 int orient = (col + row) % 2; /* O left 1 right */
633 int fudge = 7; /* fudge because the triangles are not exact */
636 tri.x = ap->xb + col * ap->xs;
637 tri.y = ap->yb + row * ap->ys;
639 tri.x += (ap->xs / 2 - 1);
641 tri.x -= (ap->xs / 2 - 1);
643 for (side = 0; side < 3; side++) {
645 tri.x += ap->shape.triangle[orient][side].x;
646 tri.y += ap->shape.triangle[orient][side].y;
648 if (truchetstate == side % 3) {
650 ang = (510 - side * 120) % 360; /* Right */
652 ang = (690 - side * 120) % 360; /* Left */
653 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
654 tri.x - ap->xs / 2, tri.y - 3 * ap->ys / 4,
655 ap->xs, 3 * ap->ys / 2,
656 (ang + fudge) * 64, (60 - 2 * fudge) * 64);
663 drawcell(ModeInfo * mi, int col, int row, unsigned char color)
665 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
669 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
671 } else if (MI_NPIXELS(mi) > 2) {
672 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
673 MI_PIXEL(mi, ap->colors[color - 1]));
678 gcv.stipple = ap->pixmaps[color - 1];
679 gcv.foreground = MI_WHITE_PIXEL(mi);
680 gcv.background = MI_BLACK_PIXEL(mi);
681 XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
682 GCStipple | GCForeground | GCBackground, &gcv);
685 fillcell(mi, gc, col, row);
689 drawtruchet(ModeInfo * mi, int col, int row,
690 unsigned char color, unsigned char truchetstate)
692 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
695 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
696 else if (MI_NPIXELS(mi) > 2 || color > ap->ncolors / 2)
697 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
699 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
700 truchetcell(mi, col, row, truchetstate);
704 draw_anant(ModeInfo * mi, int col, int row)
706 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
707 fillcell(mi, MI_GC(mi), col, row);
708 #if 0 /* Can not see eyes */
710 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
711 Display *display = MI_DISPLAY(mi);
712 Window window = MI_WINDOW(mi);
714 if (ap->xs > 2 && ap->ys > 2) { /* Draw Eyes */
716 XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
719 XDrawPoint(display, window, MI_GC(mi),
720 ap->xb + ap->xs - 1, ap->yb + 1);
721 XDrawPoint(display, window, MI_GC(mi),
722 ap->xb + ap->xs - 1, ap->yb + ap->ys - 2);
725 XDrawPoint(display, window, MI_GC(mi), ap->xb, ap->yb + 1);
726 XDrawPoint(display, window, MI_GC(mi), ap->xb, ap->yb + ap->ys - 2);
728 if (neighbors == 4) {
730 XDrawPoint(display, window, MI_GC(mi), ap->xb + 1, ap->yb);
731 XDrawPoint(display, window, MI_GC(mi),
732 ap->xb + ap->xs - 2, ap->yb);
735 XDrawPoint(display, window, MI_GC(mi),
736 ap->xb + 1, ap->yb + ap->ys - 1);
737 XDrawPoint(display, window, MI_GC(mi),
738 ap->xb + ap->xs - 2, ap->yb + ap->ys - 1);
753 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
754 int row, col, mrow = 0;
756 for (row = 0; row < ap->nrows; ++row) {
757 for (col = 0; col < ap->ncols; ++col) {
758 ap->old[col + mrow] = (unsigned char) NRAND((int) ap->ncolors);
759 drawcell(mi, col, row, ap->old[col + mrow]);
768 fromTableDirection(unsigned char dir, int neighbors)
774 return (ANGLES / neighbors);
776 return (ANGLES / 2 - ANGLES / neighbors);
780 return (ANGLES / 2 + ANGLES / neighbors);
782 return (ANGLES - ANGLES / neighbors);
786 return (ANGLES + ANGLES / neighbors);
788 return (3 * ANGLES / 2 - ANGLES / neighbors);
790 return (3 * ANGLES / 2);
792 return (3 * ANGLES / 2 + ANGLES / neighbors);
794 return (2 * ANGLES - ANGLES / neighbors);
796 (void) fprintf(stderr, "wrong direction %d\n", dir);
802 getTable(ModeInfo * mi, int i)
804 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
806 unsigned char *patptr;
808 patptr = &tables[i][0];
809 ap->ncolors = *patptr++;
810 ap->nstates = *patptr++;
811 total = ap->ncolors * ap->nstates;
812 if (MI_IS_VERBOSE(mi))
813 (void) fprintf(stdout,
814 "ants %d, neighbors %d, table number %d, colors %d, states %d\n",
815 ap->n, ap->neighbors, i, ap->ncolors, ap->nstates);
816 for (j = 0; j < total; j++) {
817 ap->machine[j].color = *patptr++;
818 if (ap->sharpturn && ap->neighbors > 4 && !(ap->neighbors % 2)) {
849 ap->machine[j].direction = fromTableDirection(k, ap->neighbors);
851 ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors);
853 ap->machine[j].next = *patptr++;
859 getTurk(ModeInfo * mi, int i)
861 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
862 int power2, j, number, total;
864 /* To force a number, say <i = 2;> has i + 2 (or 4) digits in binary */
865 power2 = 1 << (i + 1);
866 /* Dont want numbers which in binary are all 1's. */
867 number = NRAND(power2 - 1) + power2;
868 /* To force a particular number, say <number = 10;> */
872 total = ap->ncolors * ap->nstates;
873 for (j = 0; j < total; j++) {
874 ap->machine[j].color = (j + 1) % total;
875 if (ap->sharpturn && ap->neighbors > 4 && !(ap->neighbors % 2)) {
876 ap->machine[j].direction = (power2 & number) ?
877 fromTableDirection(THRS, ap->neighbors) :
878 fromTableDirection(THLS, ap->neighbors);
880 ap->machine[j].direction = (power2 & number) ?
881 fromTableDirection(TRS, ap->neighbors) :
882 fromTableDirection(TLS, ap->neighbors);
884 ap->machine[j].next = 0;
887 ap->truchet = (ap->truchet && ap->xs > 2 && ap->ys > 2 &&
888 (ap->neighbors == 3 || ap->neighbors == 4 || ap->neighbors == 6));
889 if (MI_IS_VERBOSE(mi))
890 (void) fprintf(stdout,
891 "ants %d, neighbors %d, Turk's number %d, colors %d\n",
892 ap->n, ap->neighbors, number, ap->ncolors);
896 init_ant(ModeInfo * mi)
898 Display *display = MI_DISPLAY(mi);
899 Window window = MI_WINDOW(mi);
900 int size = MI_SIZE(mi);
905 /* jwz sez: small sizes look like crap */
907 size = NRAND(-size)+1;
911 if (antfarms == NULL) {
912 if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi),
913 sizeof (antfarmstruct))) == NULL)
916 ap = &antfarms[MI_SCREEN(mi)];
918 if (MI_NPIXELS(mi) <= 2) {
919 if (ap->stippledGC == None) {
922 gcv.fill_style = FillOpaqueStippled;
923 ap->stippledGC = XCreateGC(display, window, GCFillStyle, &gcv);
925 if (ap->init_bits == 0) {
926 for (i = 1; i < NUMSTIPPLES; i++)
927 ANTBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
931 ap->n = MI_COUNT(mi);
932 if (ap->n < -MINANTS) {
933 /* if ap->n is random ... the size can change */
934 if (ap->ants != NULL) {
935 (void) free((void *) ap->ants);
938 ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;
939 } else if (ap->n < MINANTS)
942 ap->width = MI_WIDTH(mi);
943 ap->height = MI_HEIGHT(mi);
945 if (neighbors == 8 || neighbors == 9 || neighbors == 12)
946 ap->neighbors = neighbors; /* Discourage but not deny use... */
948 for (i = 0; i < NEIGHBORKINDS; i++) {
949 if (neighbors == plots[i]) {
950 ap->neighbors = plots[i];
953 if (i == NEIGHBORKINDS - 1) {
954 ap->neighbors = plots[NRAND(NEIGHBORKINDS)];
959 if (ap->neighbors == 6) {
966 if (size < -MINSIZE) {
967 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
968 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
969 if (ap->ys < MINRANDOMSIZE)
970 ap->ys = MIN(MINRANDOMSIZE,
971 MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
972 } else if (size < MINSIZE) {
974 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
978 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
981 nccols = MAX(ap->width / ap->xs - 2, 2);
982 ncrows = MAX(ap->height / ap->ys - 1, 2);
983 ap->ncols = nccols / 2;
984 ap->nrows = 2 * (ncrows / 4);
985 ap->xb = (ap->width - ap->xs * nccols) / 2 + ap->xs / 2;
986 ap->yb = (ap->height - ap->ys * (ncrows / 2) * 2) / 2 + ap->ys;
987 for (i = 0; i < 6; i++) {
988 ap->shape.hexagon[i].x = (ap->xs - 1) * hexagonUnit[i].x;
989 ap->shape.hexagon[i].y = ((ap->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
991 /* Avoid array bounds read of hexagonUnit */
992 ap->shape.hexagon[6].x = 0;
993 ap->shape.hexagon[6].y = 0;
994 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
995 if (size < -MINSIZE) {
996 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
997 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
998 if (ap->ys < MINRANDOMSIZE)
999 ap->ys = MIN(MINRANDOMSIZE,
1000 MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1001 } else if (size < MINSIZE) {
1003 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1007 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1010 ap->ncols = MAX(ap->width / ap->xs, 2);
1011 ap->nrows = MAX(ap->height / ap->ys, 2);
1012 ap->xb = (ap->width - ap->xs * ap->ncols) / 2;
1013 ap->yb = (ap->height - ap->ys * ap->nrows) / 2;
1021 if (size < -MINSIZE) {
1022 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1023 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1024 if (ap->ys < MINRANDOMSIZE)
1025 ap->ys = MIN(MINRANDOMSIZE,
1026 MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1027 } else if (size < MINSIZE) {
1029 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1033 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1035 ap->xs = (int) (1.52 * ap->ys);
1036 ap->ncols = (MAX(ap->width / ap->xs - 1, 2) / 2) * 2;
1037 ap->nrows = (MAX(ap->height / ap->ys - 1, 2) / 2) * 2;
1038 ap->xb = (ap->width - ap->xs * ap->ncols) / 2 + ap->xs / 2;
1039 ap->yb = (ap->height - ap->ys * ap->nrows) / 2 + ap->ys;
1040 for (orient = 0; orient < 2; orient++) {
1041 for (i = 0; i < 3; i++) {
1042 ap->shape.triangle[orient][i].x =
1043 (ap->xs - 2) * triangleUnit[orient][i].x;
1044 ap->shape.triangle[orient][i].y =
1045 (ap->ys - 2) * triangleUnit[orient][i].y;
1047 /* Avoid array bounds read of triangleUnit */
1048 ap->shape.triangle[orient][3].x = 0;
1049 ap->shape.triangle[orient][3].y = 0;
1053 XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinMiter);
1055 ap->painted = False;
1057 if (MI_IS_FULLRANDOM(mi)) {
1058 ap->truchet = (Bool) (LRAND() & 1);
1059 ap->sharpturn = (Bool) (LRAND() & 1);
1061 ap->truchet = truchet;
1062 ap->sharpturn = sharpturn;
1064 /* Exclude odd # of neighbors, stepping forward not defined */
1065 if (!NRAND(NUMSTIPPLES) && ((ap->neighbors + 1) % 2)) {
1066 getTable(mi, (int) (NRAND(NTABLES)));
1068 getTurk(mi, (int) (NRAND(NUMSTIPPLES - 1)));
1069 if (MI_NPIXELS(mi) > 2)
1070 for (i = 0; i < (int) ap->ncolors - 1; i++)
1071 ap->colors[i] = (unsigned char) (NRAND(MI_NPIXELS(mi)) +
1072 i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1));
1073 if (ap->ants == NULL)
1074 ap->ants = (antstruct *) malloc(ap->n * sizeof (antstruct));
1075 if (ap->tape != NULL)
1076 (void) free((void *) ap->tape);
1077 ap->tape = (unsigned char *)
1078 calloc(ap->ncols * ap->nrows, sizeof (unsigned char));
1080 if (ap->truchet_state != NULL)
1081 (void) free((void *) ap->truchet_state);
1082 ap->truchet_state = (unsigned char *)
1083 calloc(ap->ncols * ap->nrows, sizeof (unsigned char));
1085 col = ap->ncols / 2;
1086 row = ap->nrows / 2;
1087 dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors;
1088 /* Have them all start in the same spot, why not? */
1089 for (i = 0; i < ap->n; i++) {
1090 ap->ants[i].col = col;
1091 ap->ants[i].row = row;
1092 ap->ants[i].direction = dir;
1093 ap->ants[i].state = 0;
1095 draw_anant(mi, col, row);
1099 draw_ant(ModeInfo * mi)
1101 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
1103 statestruct *status;
1104 int i, state_pos, tape_pos;
1105 unsigned char color;
1106 short chg_dir, old_dir;
1108 MI_IS_DRAWN(mi) = True;
1111 for (i = 0; i < ap->n; i++) {
1112 anant = &ap->ants[i];
1113 tape_pos = anant->col + anant->row * ap->ncols;
1114 color = ap->tape[tape_pos]; /* read tape */
1115 state_pos = color + anant->state * ap->ncolors;
1116 status = &(ap->machine[state_pos]);
1117 drawcell(mi, anant->col, anant->row, status->color);
1118 ap->tape[tape_pos] = status->color; /* write on tape */
1120 /* Find direction of Bees or Ants. */
1121 /* Translate relative direction to actual direction */
1122 old_dir = anant->direction;
1123 chg_dir = (2 * ANGLES - status->direction) % ANGLES;
1124 anant->direction = (chg_dir + old_dir) % ANGLES;
1128 if (ap->neighbors == 6) {
1129 if (ap->sharpturn) {
1130 a = (chg_dir / 120 == 2);
1131 drawtruchet(mi, anant->col, anant->row, status->color, a);
1133 a = (old_dir / 60) % 3;
1134 b = (anant->direction / 60) % 3;
1135 a = (a + b + 1) % 3;
1136 drawtruchet(mi, anant->col, anant->row, status->color, a);
1138 } else if (ap->neighbors == 4) {
1140 b = anant->direction / 180;
1141 a = ((a && !b) || (b && !a));
1142 drawtruchet(mi, anant->col, anant->row, status->color, a);
1143 } else if (ap->neighbors == 3) {
1145 a = (2 + anant->direction / 120) % 3;
1147 a = (1 + anant->direction / 120) % 3;
1148 drawtruchet(mi, anant->col, anant->row, status->color, a);
1150 ap->truchet_state[tape_pos] = a + 1;
1152 anant->state = status->next;
1154 /* If edge than wrap it */
1155 old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir);
1156 position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row));
1157 draw_anant(mi, anant->col, anant->row);
1159 if (++ap->generation > MI_CYCLES(mi)) {
1161 erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
1165 if (ap->redrawing) {
1166 for (i = 0; i < REDRAWSTEP; i++) {
1167 if (ap->tape[ap->redrawpos] ||
1168 (ap->truchet && ap->truchet_state[ap->redrawpos])) {
1169 drawcell(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1170 ap->tape[ap->redrawpos]);
1172 drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1173 ap->tape[ap->redrawpos],
1174 ap->truchet_state[ap->redrawpos] - 1);
1176 if (++(ap->redrawpos) >= ap->ncols * ap->nrows) {
1185 release_ant(ModeInfo * mi)
1187 if (antfarms != NULL) {
1190 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1191 antfarmstruct *ap = &antfarms[screen];
1194 if (ap->stippledGC != None) {
1195 XFreeGC(MI_DISPLAY(mi), ap->stippledGC);
1197 for (shade = 0; shade < ap->init_bits; shade++)
1198 XFreePixmap(MI_DISPLAY(mi), ap->pixmaps[shade]);
1199 if (ap->tape != NULL)
1200 (void) free((void *) ap->tape);
1201 if (ap->ants != NULL)
1202 (void) free((void *) ap->ants);
1203 if (ap->truchet_state != NULL)
1204 (void) free((void *) ap->truchet_state);
1206 (void) free((void *) antfarms);
1212 refresh_ant(ModeInfo * mi)
1214 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];