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.04 97/07/28 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 (9? or 12) <- 9 and 12 are not implemented
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" \
65 "*eraseSpeed: 400 \n" \
67 # include "xlockmore.h" /* in xscreensaver distribution */
69 #else /* STANDALONE */
70 # include "xlock.h" /* in xlockmore distribution */
72 #endif /* STANDALONE */
74 #define DEF_TRUCHET "False"
80 #endif /* !STANDALONE */
84 static XrmOptionDescRec opts[] =
86 {"-truchet", ".ant.truchet", XrmoptionNoArg, (caddr_t) "on"},
87 {"+truchet", ".ant.truchet", XrmoptionNoArg, (caddr_t) "off"},
90 {"-neighbors", ".ant.neighbors", XrmoptionNoArg, (caddr_t) "on"},
91 {"+neighbors", ".ant.neighbors", XrmoptionNoArg, (caddr_t) "off"}
92 #endif /* STANDALONE */
95 static argtype vars[] =
97 {(caddr_t *) & truchet, "truchet", "Truchet", DEF_TRUCHET, t_Bool},
99 {(caddr_t *) & neighbors, "neighbors", "Neighbors", 0, t_Bool}
100 #endif /* STANDALONE */
102 static OptionStruct desc[] =
104 {"-/+truchet", "turn on/off Truchet lines"}
107 ModeSpecOpt ant_opts =
108 {2, opts, 1, vars, desc};
111 #define ANTBITS(n,w,h)\
112 ap->pixmaps[ap->init_bits++]=\
113 XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1)
115 /* If you change the table you may have to change the following 2 constants */
119 #define PATTERNSIZE 8
120 #define REDRAWSTEP 2000 /* How much tape to draw per cycle */
121 #define MINGRIDSIZE 24
124 #define NEIGHBORKINDS 3
127 static XPoint hexagonUnit[6] =
137 static XPoint triangleUnit[2][3] =
151 #endif /* STANDALONE */
154 static unsigned char patterns[COLORS - 1][PATTERNSIZE] =
156 {0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22}, /* grey+white | stripe */
157 {0x00, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x00}, /* spots */
158 {0x89, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11}, /* lt. / stripe */
159 {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, /* | bars */
160 {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa}, /* 50% grey */
161 {0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00}, /* - bars */
162 {0xee, 0xdd, 0xbb, 0x77, 0xee, 0xdd, 0xbb, 0x76}, /* dark \ stripe */
163 {0xff, 0x99, 0x99, 0xff, 0xff, 0x99, 0x99, 0xff}, /* spots */
164 {0xaa, 0xff, 0xff, 0x55, 0xaa, 0xff, 0xff, 0x55}, /* black+grey - stripe */
165 {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} /* black */
188 unsigned char ncolors, nstates;
190 int redrawing, redrawpos;
191 int truchet; /* Only for Turk modes */
192 statestruct machine[COLORS * STATES];
194 unsigned char *truchet_state;
196 unsigned char colors[COLORS - 1];
198 Pixmap pixmaps[COLORS - 1];
199 XPoint hexagonList[7];
200 XPoint triangleList[2][4];
203 static int initVal[NEIGHBORKINDS] =
204 {3, 4, 6}; /* Neighborhoods, 8 just makes a mess */
207 /* Relative ant moves */
208 #define FS 0 /* Step */
209 #define TRS 1 /* Turn right, then step */
210 #define THRS 2 /* Turn hard right, then step */
211 #define TBS 3 /* Turn back, then step */
212 #define THLS 4 /* Turn hard left, then step */
213 #define TLS 5 /* Turn left, then step */
214 #define SF 6 /* Step */
215 #define STR 7 /* Step then turn right */
216 #define STHR 8 /* Step then turn hard right */
217 #define STB 9 /* Step then turn back */
218 #define STHL 10 /* Step then turn hard left */
219 #define STL 11 /* Step then turn left */
221 static antfarmstruct *antfarms = NULL;
223 /* LANGTON'S ANT (10) Chaotic after 500, Builder after 10,000 (104p) */
224 /* TURK'S 100 ANT Always chaotic?, tested past 150,000,000 */
225 /* TURK'S 101 ANT Always chaotic? */
226 /* TURK'S 110 ANT Builder at 150 (18p) */
227 /* TURK'S 1000 ANT Always chaotic? */
228 /* TURK'S 1100 SYMMETRIC ANT all even run 1's and 0's are symmetric */
229 /* other examples 1001, 110011, 110000, 1001101 */
230 /* TURK'S 1101 ANT Builder after 250,000 (388p) */
231 /* Once saw a chess horse type builder (i.e. non-45 degree builder) */
234 /* All alternating 10 appear symmetric, no proof (i.e. 10, 1010, etc) */
235 /* Even runs of 0's and 1's are also symmetric */
236 /* I have seen Hexagonal builders but they are more rare. */
238 static unsigned char tables[][3 * COLORS * STATES + 2] =
241 /* Here just so you can figure out notation */
242 { /* Langton's ant */
247 /* First 2 numbers are the size (ncolors, nstates) */
248 { /* LADDER BUILDER */
250 1, STR, 0, 2, STL, 0, 3, TRS, 0, 0, TLS, 0
252 { /* SPIRALING PATTERN */
257 { /* SQUARE (HEXAGON) BUILDER */
265 #define NTABLES (sizeof tables / sizeof tables[0])
268 position_of_neighbor(antfarmstruct * ap, int dir, int *pcol, int *prow)
270 int col = *pcol, row = *prow;
272 if (ap->neighbors == 6) {
275 col = (col + 1 == ap->ncols) ? 0 : col + 1;
279 col = (col + 1 == ap->ncols) ? 0 : col + 1;
280 row = (!row) ? ap->nrows - 1 : row - 1;
284 col = (!col) ? ap->ncols - 1 : col - 1;
285 row = (!row) ? ap->nrows - 1 : row - 1;
288 col = (!col) ? ap->ncols - 1 : col - 1;
292 col = (!col) ? ap->ncols - 1 : col - 1;
293 row = (row + 1 == ap->nrows) ? 0 : row + 1;
297 col = (col + 1 == ap->ncols) ? 0 : col + 1;
298 row = (row + 1 == ap->nrows) ? 0 : row + 1;
301 (void) fprintf(stderr, "wrong direction %d\n", dir);
303 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
306 col = (col + 1 == ap->ncols) ? 0 : col + 1;
309 col = (col + 1 == ap->ncols) ? 0 : col + 1;
310 row = (!row) ? ap->nrows - 1 : row - 1;
313 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;
323 col = (!col) ? ap->ncols - 1 : col - 1;
324 row = (row + 1 == ap->nrows) ? 0 : row + 1;
327 row = (row + 1 == ap->nrows) ? 0 : row + 1;
330 col = (col + 1 == ap->ncols) ? 0 : col + 1;
331 row = (row + 1 == ap->nrows) ? 0 : row + 1;
334 (void) fprintf(stderr, "wrong direction %d\n", dir);
337 if ((col + row) % 2) { /* right */
340 col = (!col) ? ap->ncols - 1 : col - 1;
344 col = (!col) ? ap->ncols - 1 : col - 1;
345 row = (!row) ? ap->nrows - 1 : row - 1;
348 col = (!col) ? ap->ncols - 1 : col - 1;
366 row = (!row) ? ap->nrows - 1 : row - 1;
370 col = (col + 1 == ap->ncols) ? 0 : col + 1;
371 row = (!row) ? ap->nrows - 1 : row - 1;
374 col = (col + 1 == ap->ncols) ? 0 : col + 1;
378 col = (col + 1 == ap->ncols) ? 0 : col + 1;
379 row = (row + 1 == ap->nrows) ? 0 : row + 1;
382 row = (row + 1 == ap->nrows) ? 0 : row + 1;
386 if (row + 1 == ap->nrows)
388 else if (row + 2 == ap->nrows)
394 col = (!col) ? ap->ncols - 1 : col - 1;
395 if (row + 1 == ap->nrows)
397 else if (row + 2 == ap->nrows)
404 col = (!col) ? ap->ncols - 1 : col - 1;
405 row = (row + 1 == ap->nrows) ? 0 : row + 1;
408 (void) fprintf(stderr, "wrong direction %d\n", dir);
413 col = (col + 1 == ap->ncols) ? 0 : col + 1;
417 col = (col + 1 == ap->ncols) ? 0 : col + 1;
418 row = (row + 1 == ap->nrows) ? 0 : row + 1;
421 col = (col + 1 == ap->ncols) ? 0 : col + 1;
422 if (row + 1 == ap->nrows)
424 else if (row + 2 == ap->nrows)
431 if (row + 1 == ap->nrows)
433 else if (row + 2 == ap->nrows)
439 row = (row + 1 == ap->nrows) ? 0 : row + 1;
443 col = (!col) ? ap->ncols - 1 : col - 1;
444 row = (row + 1 == ap->nrows) ? 0 : row + 1;
447 col = (!col) ? ap->ncols - 1 : col - 1;
451 col = (!col) ? ap->ncols - 1 : col - 1;
452 row = (!row) ? ap->nrows - 1 : row - 1;
455 row = (!row) ? ap->nrows - 1 : row - 1;
467 col = (col + 1 == ap->ncols) ? 0 : col + 1;
477 col = (col + 1 == ap->ncols) ? 0 : col + 1;
478 row = (!row) ? ap->nrows - 1 : row - 1;
481 (void) fprintf(stderr, "wrong direction %d\n", dir);
490 fillcell(ModeInfo * mi, GC gc, int col, int row)
492 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
494 if (ap->neighbors == 6) {
495 int ccol = 2 * col + !(row & 1), crow = 2 * row;
497 ap->hexagonList[0].x = ap->xb + ccol * ap->xs;
498 ap->hexagonList[0].y = ap->yb + crow * ap->ys;
499 if (ap->xs == 1 && ap->ys == 1)
500 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
501 ap->hexagonList[0].x, ap->hexagonList[0].y, 1, 1);
503 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
504 ap->hexagonList, 6, Convex, CoordModePrevious);
506 #if 0 /* jwz sez: this looks like crap */
507 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
508 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
509 ap->xb + ap->xs * col, ap->yb + ap->ys * row, ap->xs, ap->ys);
513 int orient = (col + row) % 2; /* O left 1 right */
515 ap->triangleList[orient][0].x = ap->xb + col * ap->xs;
516 ap->triangleList[orient][0].y = ap->yb + row * ap->ys;
517 if (ap->xs <= 3 || ap->ys <= 3)
518 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
519 ((orient) ? -1 : 1) + ap->triangleList[orient][0].x,
520 ap->triangleList[orient][0].y, 1, 1);
523 ap->triangleList[orient][0].x += (ap->xs / 2 - 1);
525 ap->triangleList[orient][0].x -= (ap->xs / 2 - 1);
526 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
527 ap->triangleList[orient], 3, Convex, CoordModePrevious);
533 truchetcell(ModeInfo * mi, int col, int row, int truchetstate)
535 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
537 if (ap->neighbors == 6) {
538 int ccol = 2 * col + !(row & 1), crow = 2 * row;
542 /* Very crude approx of Sqrt 3, so it will not cause drawing errors. */
543 hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs * 1.6 / 2.0);
544 hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys * 1.6 / 2.0);
545 for (side = 0; side < 6; side++) {
547 hex.x += ap->hexagonList[side].x;
548 hex.y += ap->hexagonList[side].y;
550 hex2.x = hex.x + ap->hexagonList[side + 1].x / 2;
551 hex2.y = hex.y + ap->hexagonList[side + 1].y / 2;
552 if (truchetstate == side % 3)
553 /* Crude approx of 120 deg, so it will not cause drawing errors. */
554 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
556 (int) ((double) ap->xs * 1.5), (int) ((double) ap->ys * 1.5),
557 ((555 - (side * 60)) % 360) * 64, 90 * 64);
559 } else if (ap->neighbors == 4) {
561 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
562 ap->xb + ap->xs * col - ap->xs / 2,
563 ap->yb + ap->ys * row + ap->ys / 2,
566 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
567 ap->xb + ap->xs * col + ap->xs / 2,
568 ap->yb + ap->ys * row - ap->ys / 2,
572 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
573 ap->xb + ap->xs * col - ap->xs / 2,
574 ap->yb + ap->ys * row - ap->ys / 2,
577 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
578 ap->xb + ap->xs * col + ap->xs / 2,
579 ap->yb + ap->ys * row + ap->ys / 2,
583 } else if (ap->neighbors == 3) {
584 int orient = (col + row) % 2; /* O left 1 right */
588 tri.x = ap->xb + col * ap->xs;
589 tri.y = ap->yb + row * ap->ys;
591 tri.x += (ap->xs / 2 - 2);
593 tri.x -= (ap->xs / 2 + 2);
595 for (side = 0; side < 3; side++) {
597 tri.x += ap->triangleList[orient][side].x;
598 tri.y += ap->triangleList[orient][side].y;
600 if (truchetstate == side % 3) {
602 ang = (518 - side * 120) % 360; /* Right */
604 ang = (690 - side * 120) % 360; /* Left */
605 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
606 tri.x - ap->xs / 2, tri.y - 3 * ap->ys / 4,
607 ap->xs, 3 * ap->ys / 2,
615 drawcell(ModeInfo * mi, int col, int row, unsigned char color)
617 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
621 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
623 } else if (MI_NPIXELS(mi) > 2) {
624 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
625 MI_PIXEL(mi, ap->colors[color - 1]));
630 gcv.stipple = ap->pixmaps[color - 1];
631 gcv.foreground = MI_WIN_WHITE_PIXEL(mi);
632 gcv.background = MI_WIN_BLACK_PIXEL(mi);
633 XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
634 GCStipple | GCForeground | GCBackground, &gcv);
637 fillcell(mi, gc, col, row);
641 drawtruchet(ModeInfo * mi, int col, int row,
642 unsigned char color, unsigned char truchetstate)
644 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
647 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
648 else if (MI_NPIXELS(mi) > 2 || color > ap->ncolors / 2)
649 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
651 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
652 truchetcell(mi, col, row, truchetstate);
656 draw_anant(ModeInfo * mi, int col, int row)
658 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_WHITE_PIXEL(mi));
659 fillcell(mi, MI_GC(mi), col, row);
660 #if 0 /* Can not see eyes */
662 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
663 Display *display = MI_DISPLAY(mi);
664 Window window = MI_WINDOW(mi);
666 if (ap->xs > 2 && ap->ys > 2) { /* Draw Eyes */
668 XSetForeground(display, MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
671 XDrawPoint(display, window, MI_GC(mi),
672 ap->xb + ap->xs - 1, ap->yb + 1);
673 XDrawPoint(display, window, MI_GC(mi),
674 ap->xb + ap->xs - 1, ap->yb + ap->ys - 2);
677 XDrawPoint(display, window, MI_GC(mi), ap->xb, ap->yb + 1);
678 XDrawPoint(display, window, MI_GC(mi), ap->xb, ap->yb + ap->ys - 2);
680 if (neighbors == 4) {
682 XDrawPoint(display, window, MI_GC(mi), ap->xb + 1, ap->yb);
683 XDrawPoint(display, window, MI_GC(mi),
684 ap->xb + ap->xs - 2, ap->yb);
687 XDrawPoint(display, window, MI_GC(mi),
688 ap->xb + 1, ap->yb + ap->ys - 1);
689 XDrawPoint(display, window, MI_GC(mi),
690 ap->xb + ap->xs - 2, ap->yb + ap->ys - 1);
705 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
706 int row, col, mrow = 0;
708 for (row = 0; row < ap->nrows; ++row) {
709 for (col = 0; col < ap->ncols; ++col) {
710 ap->old[col + mrow] = (unsigned char) NRAND((int) ap->ncolors);
711 drawcell(mi, col, row, ap->old[col + mrow]);
720 fromTableDirection(unsigned char dir, int neighbors)
726 return (ANGLES / neighbors);
728 return (ANGLES / (2 * neighbors));
732 return (ANGLES - ANGLES / (2 * neighbors));
734 return (ANGLES - ANGLES / neighbors);
738 return (ANGLES + ANGLES / neighbors);
740 return (ANGLES + ANGLES / (2 * neighbors));
742 return (3 * ANGLES / 2);
744 return (2 * ANGLES - ANGLES / (2 * neighbors));
746 return (2 * ANGLES - ANGLES / neighbors);
748 (void) fprintf(stderr, "wrong direction %d\n", dir);
754 getTable(ModeInfo * mi, int i)
756 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
758 unsigned char *patptr;
760 patptr = &tables[i][0];
761 ap->ncolors = *patptr++;
762 ap->nstates = *patptr++;
763 total = ap->ncolors * ap->nstates;
764 if (MI_WIN_IS_VERBOSE(mi))
765 (void) fprintf(stdout,
766 "neighbors %d, table number %d, colors %d, states %d\n",
767 ap->neighbors, i, ap->ncolors, ap->nstates);
768 for (j = 0; j < total; j++) {
769 ap->machine[j].color = *patptr++;
770 ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors);
771 ap->machine[j].next = *patptr++;
777 getTurk(ModeInfo * mi, int i)
779 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
780 int power2, j, number, total;
782 /* To force a number, say <i = 2;> has i + 2 (or 4) digits in binary */
783 power2 = 1 << (i + 1);
784 /* Dont want numbers which in binary are all 1's. */
785 number = NRAND(power2 - 1) + power2;
786 /* To force a particular number, say <number = 10;> */
790 total = ap->ncolors * ap->nstates;
791 for (j = 0; j < total; j++) {
792 ap->machine[j].color = (j + 1) % total;
793 ap->machine[j].direction = (power2 & number) ?
794 fromTableDirection(TRS, ap->neighbors) :
795 fromTableDirection(TLS, ap->neighbors);
796 ap->machine[j].next = 0;
799 if (ap->neighbors != 3 && ap->neighbors != 4 && ap->neighbors != 6)
803 if (MI_WIN_IS_VERBOSE(mi))
804 (void) fprintf(stdout, "neighbors %d, Turk's number %d, colors %d\n",
805 ap->neighbors, number, ap->ncolors);
809 init_ant(ModeInfo * mi)
811 Display *display = MI_DISPLAY(mi);
812 Window window = MI_WINDOW(mi);
813 int size = MI_SIZE(mi);
816 int col, row, i, dir;
818 /* jwz sez: small sizes look like crap */
820 size = NRAND(-size)+1;
824 if (antfarms == NULL) {
825 if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi),
826 sizeof (antfarmstruct))) == NULL)
829 ap = &antfarms[MI_SCREEN(mi)];
831 if (MI_NPIXELS(mi) <= 2) {
832 if (ap->stippledGC == None) {
833 gcv.fill_style = FillOpaqueStippled;
834 ap->stippledGC = XCreateGC(display, window, GCFillStyle, &gcv);
836 if (ap->init_bits == 0) {
837 for (i = 0; i < COLORS - 1; i++)
838 ANTBITS(patterns[i], PATTERNSIZE, PATTERNSIZE);
842 ap->n = MI_BATCHCOUNT(mi);
843 if (ap->n < -MINANTS) {
844 /* if ap->n is random ... the size can change */
845 if (ap->ants != NULL) {
846 (void) free((void *) ap->ants);
849 ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;
850 } else if (ap->n < MINANTS)
853 ap->width = MI_WIN_WIDTH(mi);
854 ap->height = MI_WIN_HEIGHT(mi);
856 if (neighbors == 8 || neighbors == 9 || neighbors == 12)
857 ap->neighbors = neighbors; /* Discourage but not deny use... */
859 for (i = 0; i < NEIGHBORKINDS; i++) {
860 if (neighbors == initVal[i]) {
861 ap->neighbors = initVal[i];
864 if (i == NEIGHBORKINDS - 1) {
865 ap->neighbors = initVal[NRAND(NEIGHBORKINDS)];
870 if (ap->neighbors == 6) {
878 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
879 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
880 else if (size < MINSIZE) {
882 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
886 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
889 nccols = MAX(ap->width / ap->xs - 2, 2);
890 ncrows = MAX(ap->height / ap->ys - 1, 2);
891 ap->ncols = nccols / 2;
892 ap->nrows = 2 * (ncrows / 4);
893 ap->xb = (ap->width - ap->xs * nccols) / 2 + ap->xs / 2;
894 ap->yb = (ap->height - ap->ys * (ncrows / 2) * 2) / 2 + ap->ys;
895 for (i = 0; i < 7; i++) {
896 ap->hexagonList[i].x = (ap->xs - 1) * hexagonUnit[i].x;
897 ap->hexagonList[i].y = ((ap->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
899 } else if (ap->neighbors == 4 && ap->neighbors == 8) {
901 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
902 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
903 else if (size < MINSIZE) {
905 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
909 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
912 ap->ncols = MAX(ap->width / ap->xs, 2);
913 ap->nrows = MAX(ap->height / ap->ys, 2);
914 ap->xb = (ap->width - ap->xs * ap->ncols) / 2;
915 ap->yb = (ap->height - ap->ys * ap->nrows) / 2;
924 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
925 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
926 else if (size < MINSIZE) {
928 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
932 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
934 ap->xs = (int) (1.52 * ap->ys);
935 ap->ncols = (MAX(ap->width / ap->xs - 1, 2) / 2) * 2;
936 ap->nrows = (MAX(ap->height / ap->ys - 1, 2) / 2) * 2;
937 ap->xb = (ap->width - ap->xs * ap->ncols) / 2 + ap->xs / 2;
938 ap->yb = (ap->height - ap->ys * ap->nrows) / 2 + ap->ys;
939 for (orient = 0; orient < 2; orient++) {
940 for (i = 0; i < 4; i++) {
941 ap->triangleList[orient][i].x =
942 (ap->xs - 2) * triangleUnit[orient][i].x;
943 ap->triangleList[orient][i].y =
944 (ap->ys - 2) * triangleUnit[orient][i].y;
948 XClearWindow(display, MI_WINDOW(mi));
950 /* Exclude odd # of neighbors, stepping forward not defined */
951 if (!NRAND(COLORS) && ((ap->neighbors + 1) % 2)) {
952 getTable(mi, (int) (NRAND(NTABLES)));
954 getTurk(mi, (int) (NRAND(COLORS - 1)));
955 if (MI_NPIXELS(mi) > 2)
956 for (i = 0; i < (int) ap->ncolors - 1; i++)
957 ap->colors[i] = (NRAND(MI_NPIXELS(mi)) +
958 i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1));
959 if (ap->ants == NULL)
960 ap->ants = (antstruct *) malloc(ap->n * sizeof (antstruct));
961 if (ap->tape != NULL)
962 (void) free((void *) ap->tape);
963 ap->tape = (unsigned char *)
964 calloc(ap->ncols * ap->nrows, sizeof (unsigned char));
966 if (ap->truchet_state != NULL)
967 (void) free((void *) ap->truchet_state);
968 ap->truchet_state = (unsigned char *)
969 calloc(ap->ncols * ap->nrows, sizeof (unsigned char));
973 dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors;
974 /* Have them all start in the same spot, why not? */
975 for (i = 0; i < ap->n; i++) {
976 ap->ants[i].col = col;
977 ap->ants[i].row = row;
978 ap->ants[i].direction = dir;
979 ap->ants[i].state = 0;
981 draw_anant(mi, col, row);
985 draw_ant(ModeInfo * mi)
987 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
990 int i, state_pos, tape_pos;
992 short chg_dir, old_dir;
994 for (i = 0; i < ap->n; i++) {
995 anant = &ap->ants[i];
996 tape_pos = anant->col + anant->row * ap->ncols;
997 color = ap->tape[tape_pos]; /* read tape */
998 state_pos = color + anant->state * ap->ncolors;
999 status = &(ap->machine[state_pos]);
1000 drawcell(mi, anant->col, anant->row, status->color);
1001 ap->tape[tape_pos] = status->color; /* write on tape */
1003 /* Find direction of Bees or Ants. */
1004 /* Translate relative direction to actual direction */
1005 old_dir = anant->direction;
1006 chg_dir = (2 * ANGLES - status->direction) % ANGLES;
1007 anant->direction = (chg_dir + old_dir) % ANGLES;
1011 if (ap->neighbors == 6) {
1012 a = (old_dir / 60) % 3;
1013 b = (anant->direction / 60) % 3;
1014 a = (a + b + 1) % 3;
1015 drawtruchet(mi, anant->col, anant->row, status->color, a);
1016 } else if (ap->neighbors == 4) {
1018 b = anant->direction / 180;
1019 a = ((a && !b) || (b && !a));
1020 drawtruchet(mi, anant->col, anant->row, status->color, a);
1021 } else if (ap->neighbors == 3) {
1023 a = (2 + anant->direction / 120) % 3;
1025 a = (1 + anant->direction / 120) % 3;
1026 drawtruchet(mi, anant->col, anant->row, status->color, a);
1028 ap->truchet_state[tape_pos] = a + 1;
1030 anant->state = status->next;
1032 /* If edge than wrap it */
1033 old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir);
1034 position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row));
1035 draw_anant(mi, anant->col, anant->row);
1037 if (++ap->generation > MI_CYCLES(mi)) {
1039 erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
1043 if (ap->redrawing) {
1044 for (i = 0; i < REDRAWSTEP; i++) {
1045 if (ap->tape[ap->redrawpos] ||
1046 (ap->truchet && ap->truchet_state[ap->redrawpos])) {
1047 drawcell(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1048 ap->tape[ap->redrawpos]);
1050 drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1051 ap->tape[ap->redrawpos],
1052 ap->truchet_state[ap->redrawpos] - 1);
1054 if (++(ap->redrawpos) >= ap->ncols * ap->nrows) {
1063 release_ant(ModeInfo * mi)
1065 if (antfarms != NULL) {
1068 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1069 antfarmstruct *ap = &antfarms[screen];
1072 if (ap->stippledGC != None) {
1073 XFreeGC(MI_DISPLAY(mi), ap->stippledGC);
1075 for (shade = 0; shade < ap->init_bits; shade++)
1076 XFreePixmap(MI_DISPLAY(mi), ap->pixmaps[shade]);
1077 if (ap->tape != NULL)
1078 (void) free((void *) ap->tape);
1079 if (ap->ants != NULL)
1080 (void) free((void *) ap->ants);
1081 if (ap->truchet_state != NULL)
1082 (void) free((void *) ap->truchet_state);
1084 (void) free((void *) antfarms);
1090 refresh_ant(ModeInfo * mi)
1092 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];