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
8 static const char sccsid[] = "@(#)ant.c 5.00 2000/11/01 xlockmore";
12 * Copyright (c) 1995 by David Bagley.
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.
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.
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
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.
46 Species Grid Number of Neighbors
47 ------- ---- ------------------
50 Bees Triangle 3 (or 9, 12)
52 Neighbors 6 and neighbors 3 produce the same Turk ants.
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" \
67 "*sharpturn: False \n"
68 #include "xlockmore.h" /* in xscreensaver distribution */
70 #else /* STANDALONE */
71 #include "xlock.h" /* in xlockmore distribution */
72 #endif /* STANDALONE */
78 * neighbors of 0 randomizes it for 3, 4, 6, 8, 12 (last 2 are less likely)
81 #define DEF_NEIGHBORS "0" /* choose random value */
82 #define DEF_TRUCHET "False"
83 #define DEF_EYES "False"
84 #define DEF_SHARPTURN "False"
89 static Bool sharpturn;
91 static XrmOptionDescRec opts[] =
93 {"-neighbors", ".ant.neighbors", XrmoptionSepArg, NULL},
94 {"-truchet", ".ant.truchet", XrmoptionNoArg, "on"},
95 {"+truchet", ".ant.truchet", XrmoptionNoArg, "off"},
96 {"-eyes", ".ant.eyes", XrmoptionNoArg, "on"},
97 {"+eyes", ".ant.eyes", XrmoptionNoArg, "off"},
98 {"-sharpturn", ".ant.sharpturn", XrmoptionNoArg, "on"},
99 {"+sharpturn", ".ant.sharpturn", XrmoptionNoArg, "off"},
100 {"-neighbors", ".ant.neighbors", XrmoptionSepArg, 0},
101 {"+neighbors", ".ant.neighbors", XrmoptionSepArg, 0}
103 static argtype vars[] =
105 {&neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int},
106 {&truchet, "truchet", "Truchet", DEF_TRUCHET, t_Bool},
107 {&eyes, "eyes", "Eyes", DEF_EYES, t_Bool},
108 {&sharpturn, "sharpturn", "SharpTurn", DEF_SHARPTURN, t_Bool},
109 {&neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int}
111 static OptionStruct desc[] =
113 {"-neighbors num", "squares 4 or 8, hexagons 6, triangles 3 or 12"},
114 {"-/+truchet", "turn on/off Truchet lines"},
115 {"-/+eyes", "turn on/off eyes"},
116 {"-/+sharpturn", "turn on/off sharp turns (6, 8 or 12 neighbors only)"}
119 ModeSpecOpt ant_opts =
120 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
123 const ModStruct ant_description =
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};
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++;}
137 /* If you change the table you may have to change the following 2 constants */
140 #define REDRAWSTEP 2000 /* How much tape to draw per cycle */
141 #define MINGRIDSIZE 24
143 #define MINRANDOMSIZE 5
167 unsigned char ncolors, nstates;
169 int redrawing, redrawpos;
170 int truchet; /* Only for Turk modes */
173 statestruct machine[NUMSTIPPLES * STATES];
175 unsigned char *truchet_state;
178 unsigned char colors[NUMSTIPPLES - 1];
180 Pixmap pixmaps[NUMSTIPPLES - 1];
182 XPoint hexagon[7]; /* Need more than 6 for truchet */
183 XPoint triangle[2][4]; /* Need more than 3 for truchet */
187 static char plots[] =
194 #define NEIGHBORKINDS ((long) (sizeof plots / sizeof *plots))
195 #define GOODNEIGHBORKINDS 3
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 */
211 static antfarmstruct *antfarms = (antfarmstruct *) NULL;
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) */
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. */
228 static unsigned char tables[][3 * NUMSTIPPLES * STATES + 2] =
231 /* Here just so you can figure out notation */
232 { /* Langton's ant */
237 /* First 2 numbers are the size (ncolors, nstates) */
238 { /* LADDER BUILDER */
240 1, STR, 0, 2, STL, 0, 3, TRS, 0, 0, TLS, 0
242 { /* SPIRALING PATTERN */
247 { /* SQUARE (HEXAGON) BUILDER */
255 #define NTABLES (sizeof tables / sizeof tables[0])
258 position_of_neighbor(antfarmstruct * ap, int dir, int *pcol, int *prow)
260 int col = *pcol, row = *prow;
262 if (ap->neighbors == 6) {
265 col = (col + 1 == ap->ncols) ? 0 : col + 1;
269 col = (col + 1 == ap->ncols) ? 0 : col + 1;
270 row = (!row) ? ap->nrows - 1 : row - 1;
274 col = (!col) ? ap->ncols - 1 : col - 1;
275 row = (!row) ? ap->nrows - 1 : row - 1;
278 col = (!col) ? ap->ncols - 1 : col - 1;
282 col = (!col) ? ap->ncols - 1 : col - 1;
283 row = (row + 1 == ap->nrows) ? 0 : row + 1;
287 col = (col + 1 == ap->ncols) ? 0 : col + 1;
288 row = (row + 1 == ap->nrows) ? 0 : row + 1;
291 (void) fprintf(stderr, "wrong direction %d\n", dir);
293 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
296 col = (col + 1 == ap->ncols) ? 0 : col + 1;
299 col = (col + 1 == ap->ncols) ? 0 : col + 1;
300 row = (!row) ? ap->nrows - 1 : row - 1;
303 row = (!row) ? ap->nrows - 1 : row - 1;
306 col = (!col) ? ap->ncols - 1 : col - 1;
307 row = (!row) ? ap->nrows - 1 : row - 1;
310 col = (!col) ? ap->ncols - 1 : col - 1;
313 col = (!col) ? ap->ncols - 1 : col - 1;
314 row = (row + 1 == ap->nrows) ? 0 : row + 1;
317 row = (row + 1 == ap->nrows) ? 0 : row + 1;
320 col = (col + 1 == ap->ncols) ? 0 : col + 1;
321 row = (row + 1 == ap->nrows) ? 0 : row + 1;
324 (void) fprintf(stderr, "wrong direction %d\n", dir);
327 if ((col + row) % 2) { /* right */
330 col = (!col) ? ap->ncols - 1 : col - 1;
334 col = (!col) ? ap->ncols - 1 : col - 1;
335 row = (!row) ? ap->nrows - 1 : row - 1;
338 col = (!col) ? ap->ncols - 1 : col - 1;
356 row = (!row) ? ap->nrows - 1 : row - 1;
360 col = (col + 1 == ap->ncols) ? 0 : col + 1;
361 row = (!row) ? ap->nrows - 1 : row - 1;
364 col = (col + 1 == ap->ncols) ? 0 : col + 1;
368 col = (col + 1 == ap->ncols) ? 0 : col + 1;
369 row = (row + 1 == ap->nrows) ? 0 : row + 1;
372 row = (row + 1 == ap->nrows) ? 0 : row + 1;
376 if (row + 1 == ap->nrows)
378 else if (row + 2 == ap->nrows)
384 col = (!col) ? ap->ncols - 1 : col - 1;
385 if (row + 1 == ap->nrows)
387 else if (row + 2 == ap->nrows)
394 col = (!col) ? ap->ncols - 1 : col - 1;
395 row = (row + 1 == ap->nrows) ? 0 : row + 1;
398 (void) fprintf(stderr, "wrong direction %d\n", dir);
403 col = (col + 1 == ap->ncols) ? 0 : col + 1;
407 col = (col + 1 == ap->ncols) ? 0 : col + 1;
408 row = (row + 1 == ap->nrows) ? 0 : row + 1;
411 col = (col + 1 == ap->ncols) ? 0 : col + 1;
412 if (row + 1 == ap->nrows)
414 else if (row + 2 == ap->nrows)
421 if (row + 1 == ap->nrows)
423 else if (row + 2 == ap->nrows)
429 row = (row + 1 == ap->nrows) ? 0 : row + 1;
433 col = (!col) ? ap->ncols - 1 : col - 1;
434 row = (row + 1 == ap->nrows) ? 0 : row + 1;
437 col = (!col) ? ap->ncols - 1 : col - 1;
441 col = (!col) ? ap->ncols - 1 : col - 1;
442 row = (!row) ? ap->nrows - 1 : row - 1;
445 row = (!row) ? ap->nrows - 1 : row - 1;
457 col = (col + 1 == ap->ncols) ? 0 : col + 1;
467 col = (col + 1 == ap->ncols) ? 0 : col + 1;
468 row = (!row) ? ap->nrows - 1 : row - 1;
471 (void) fprintf(stderr, "wrong direction %d\n", dir);
480 fillcell(ModeInfo * mi, GC gc, int col, int row)
482 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
484 if (ap->neighbors == 6) {
485 int ccol = 2 * col + !(row & 1), crow = 2 * row;
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);
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));
500 int orient = (col + row) % 2; /* O left 1 right */
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);
510 ap->shape.triangle[orient][0].x += (ap->xs / 2 - 1);
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);
520 truchetcell(ModeInfo * mi, int col, int row, int truchetstate)
522 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
524 if (ap->neighbors == 6) {
526 int ccol = 2 * col + !(row & 1), crow = 2 * row;
528 int fudge = 7; /* fudge because the hexagons are not exact */
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++) {
536 hex.x += ap->shape.hexagon[side].x;
537 hex.y += ap->shape.hexagon[side].y;
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);
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++) {
550 hex.x += ap->shape.hexagon[side].x;
551 hex.y += ap->shape.hexagon[side].y;
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 */
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);
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),
572 (int) ((double) ap->xs * 1.5), (int) ((double) ap->ys * 1.5),
573 ((555 - (side * 60)) % 360) * 64, 90 * 64);
576 } else if (ap->neighbors == 4) {
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,
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,
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,
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,
600 } else if (ap->neighbors == 3) {
601 int orient = (col + row) % 2; /* O left 1 right */
603 int fudge = 7; /* fudge because the triangles are not exact */
604 double fudge2 = 1.18;
607 tri.x = ap->xb + col * ap->xs;
608 tri.y = ap->yb + row * ap->ys;
610 tri.x += (ap->xs / 2 - 1);
612 tri.x -= (ap->xs / 2 - 1);
614 for (side = 0; side < 3; side++) {
616 tri.x += ap->shape.triangle[orient][side].x;
617 tri.y += ap->shape.triangle[orient][side].y;
619 if (truchetstate == side) {
621 ang = (510 - side * 120) % 360; /* Right */
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);
636 drawcell(ModeInfo * mi, int col, int row, unsigned char color)
638 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
642 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
644 } else if (MI_NPIXELS(mi) > 2) {
645 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
646 MI_PIXEL(mi, ap->colors[color - 1]));
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);
658 fillcell(mi, gc, col, row);
662 drawtruchet(ModeInfo * mi, int col, int row,
663 unsigned char color, unsigned char truchetstate)
665 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
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));
672 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
673 truchetcell(mi, col, row, truchetstate);
677 draw_anant(ModeInfo * mi, int direction, int col, int row)
679 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
680 Display *display = MI_DISPLAY(mi);
681 Window window = MI_WINDOW(mi);
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;
692 if (!(ap->xs > 3 && ap->ys > 3))
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++) {
699 hex.x -= ap->shape.hexagon[side].x / 2;
700 hex.y += ap->shape.hexagon[side].y / 2;
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);
707 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
708 if (!(ap->xs > 3 && ap->ys > 3))
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);
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);
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);
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);
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);
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);
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);
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);
776 (void) fprintf(stderr, "wrong eyes direction %d for ant eyes\n", direction);
779 int orient = (col + row) % 2; /* O left 1 right */
783 if (!(ap->xs > 6 && ap->ys > 6))
785 tri.x = ap->xb + col * ap->xs;
786 tri.y = ap->yb + row * ap->ys;
788 tri.x += (ap->xs / 6 - 1);
790 tri.x -= (ap->xs / 6 - 1);
791 ang = direction * ap->neighbors / ANGLES;
792 /* approx... does not work that well for even numbers */
795 ap->neighbors == 9 ||
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;
805 for (side = 0; side < 3; side++) {
807 tri.x += ap->shape.triangle[orient][side].x / 3;
808 tri.y += ap->shape.triangle[orient][side].y / 3;
810 /* Either you have the eyes in back or one eye in front */
813 XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
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);
830 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
831 int row, col, mrow = 0;
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]);
845 fromTableDirection(unsigned char dir, int local_neighbors)
847 /* Crafted to work for odd number of neighbors */
852 return (ANGLES / local_neighbors);
854 return (2 * ANGLES / local_neighbors);
856 return ((local_neighbors / 2) * ANGLES / local_neighbors);
858 return (ANGLES - 2 * ANGLES / local_neighbors);
860 return (ANGLES - ANGLES / local_neighbors);
864 return (ANGLES + ANGLES / local_neighbors);
866 return (ANGLES + 2 * ANGLES / local_neighbors);
868 return (ANGLES + (local_neighbors / 2) * ANGLES / local_neighbors);
870 return (2 * ANGLES - 2 * ANGLES / local_neighbors);
872 return (2 * ANGLES - ANGLES / local_neighbors);
874 (void) fprintf(stderr, "wrong direction %d from table\n", dir);
880 getTable(ModeInfo * mi, int i)
882 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
884 unsigned char *patptr;
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) {
927 ap->machine[j].direction = fromTableDirection(k, ap->neighbors);
929 ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors);
931 ap->machine[j].next = *patptr++;
937 getTurk(ModeInfo * mi, int i)
939 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
940 int power2, j, number, total;
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;> */
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);
958 ap->machine[j].direction = (power2 & number) ?
959 fromTableDirection(TRS, ap->neighbors) :
960 fromTableDirection(TLS, ap->neighbors);
962 ap->machine[j].next = 0;
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);
974 free_ant(Display *display, antfarmstruct *ap)
978 if (ap->stippledGC != None) {
979 XFreeGC(display, ap->stippledGC);
980 ap->stippledGC = None;
982 for (shade = 0; shade < ap->init_bits; shade++) {
983 XFreePixmap(display, ap->pixmaps[shade]);
986 if (ap->tape != NULL) {
987 (void) free((void *) ap->tape);
988 ap->tape = (unsigned char *) NULL;
990 if (ap->ants != NULL) {
991 (void) free((void *) ap->ants);
992 ap->ants = (antstruct *) NULL;
994 if (ap->truchet_state != NULL) {
995 (void) free((void *) ap->truchet_state);
996 ap->truchet_state = (unsigned char *) NULL;
1001 init_ant(ModeInfo * mi)
1003 Display *display = MI_DISPLAY(mi);
1004 Window window = MI_WINDOW(mi);
1005 int size = MI_SIZE(mi);
1010 if (antfarms == NULL) {
1011 if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi),
1012 sizeof (antfarmstruct))) == NULL)
1015 ap = &antfarms[MI_SCREEN(mi)];
1018 if (MI_NPIXELS(mi) <= 2) {
1019 if (ap->stippledGC == None) {
1022 gcv.fill_style = FillOpaqueStippled;
1023 if ((ap->stippledGC = XCreateGC(display, window, GCFillStyle,
1025 free_ant(display, ap);
1029 if (ap->init_bits == 0) {
1030 for (i = 1; i < NUMSTIPPLES; i++) {
1031 ANTBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
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;
1043 ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;
1044 } else if (ap->n < MINANTS)
1047 ap->width = MI_WIDTH(mi);
1048 ap->height = MI_HEIGHT(mi);
1050 for (i = 0; i < NEIGHBORKINDS; i++) {
1051 if (neighbors == plots[i]) {
1052 ap->neighbors = plots[i];
1055 if (i == NEIGHBORKINDS - 1) {
1057 /* Make above 6 rare */
1058 ap->neighbors = plots[NRAND(NEIGHBORKINDS)];
1060 ap->neighbors = plots[NRAND(GOODNEIGHBORKINDS)];
1066 if (ap->neighbors == 6) {
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) {
1081 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1085 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
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;
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) {
1110 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1114 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
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;
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) {
1136 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1140 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
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;
1154 /* Avoid array bounds read of triangleUnit */
1155 ap->shape.triangle[orient][3].x = 0;
1156 ap->shape.triangle[orient][3].y = 0;
1160 XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinMiter);
1162 ap->painted = False;
1164 if (MI_IS_FULLRANDOM(mi)) {
1165 ap->truchet = (Bool) (LRAND() & 1);
1166 ap->eyes = (Bool) (LRAND() & 1);
1167 ap->sharpturn = (Bool) (LRAND() & 1);
1169 ap->truchet = truchet;
1171 ap->sharpturn = sharpturn;
1173 if (!NRAND(NUMSTIPPLES)) {
1174 getTable(mi, (int) (NRAND(NTABLES)));
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))) ==
1184 free_ant(display, ap);
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);
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);
1203 row = ap->nrows / 2;
1204 col = ap->ncols / 2;
1205 if (col > 0 && ((ap->neighbors % 2) || ap->neighbors == 12) && (LRAND() & 1))
1207 dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors;
1210 if (ap->neighbors == 9 && !((col + row) & 1))
1211 dir = (dir + ANGLES - ANGLES / (ap->neighbors * 2)) % ANGLES;
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;
1220 draw_anant(mi, dir, col, row);
1224 draw_ant(ModeInfo * mi)
1227 statestruct *status;
1228 int i, state_pos, tape_pos;
1229 unsigned char color;
1230 short chg_dir, old_dir;
1233 if (antfarms == NULL)
1235 ap = &antfarms[MI_SCREEN(mi)];
1236 if (ap->ants == NULL)
1239 MI_IS_DRAWN(mi) = 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 */
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;
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);
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);
1271 } else if (ap->neighbors == 4) {
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) {
1278 a = (2 + anant->direction / 120) % 3;
1280 a = (1 + anant->direction / 120) % 3;
1281 drawtruchet(mi, anant->col, anant->row, status->color, a);
1283 ap->truchet_state[tape_pos] = a + 1;
1285 anant->state = status->next;
1287 /* Allow step first and turn */
1288 old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir);
1290 (void) printf("old_dir %d, col %d, row %d", old_dir, anant->col, anant->row);
1292 position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row));
1294 (void) printf(", ncol %d, nrow %d\n", anant->col, anant->row);
1296 draw_anant(mi, anant->direction, anant->col, anant->row);
1298 if (++ap->generation > MI_CYCLES(mi)) {
1300 erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
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]);
1311 drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1312 ap->tape[ap->redrawpos],
1313 ap->truchet_state[ap->redrawpos] - 1);
1315 if (++(ap->redrawpos) >= ap->ncols * ap->nrows) {
1324 release_ant(ModeInfo * mi)
1326 if (antfarms != NULL) {
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;
1337 refresh_ant(ModeInfo * mi)
1341 if (antfarms == NULL)
1343 ap = &antfarms[MI_SCREEN(mi)];
1352 #endif /* MODE_ant */