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 5.00 2000/11/01 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 * 01-Nov-2000: Allocation checks
29 * 10-May-1997: Compatible with xscreensaver
30 * 16-Apr-1997: -neighbors 3 and 8 added
31 * 01-Jan-1997: Updated ant.c to handle more kinds of ants. Thanks to
32 * J Austin David <Austin.David@tlogic.com>. Check it out in
33 * java at http://havoc.gtf.gatech.edu/austin He thought up the
35 * 04-Apr-1996: -neighbors 6 runtime-time option added for hexagonal ants
36 * (bees), coded from an idea of Jim Propp's in Science News,
37 * Oct 28, 1995 VOL. 148 page 287
38 * 20-Sep-1995: Memory leak in ant fixed. Now random colors.
39 * 05-Sep-1995: Coded from A.K. Dewdney's "Computer Recreations", Scientific
40 * American Magazine" Sep 1989 pp 180-183, Mar 1990 p 121
41 * Also used Ian Stewart's Mathematical Recreations, Scientific
42 * American Jul 1994 pp 104-107
43 * also used demon.c and life.c as a guide.
47 Species Grid Number of Neighbors
48 ------- ---- ------------------
51 Bees Triangle 3 (or 9, 12)
53 Neighbors 6 and neighbors 3 produce the same Turk ants.
58 #define PROGCLASS "Ant"
59 #define HACK_INIT init_ant
60 #define HACK_DRAW draw_ant
61 #define ant_opts xlockmore_opts
62 #define DEFAULTS "*delay: 1000 \n" \
68 "*sharpturn: False \n"
69 #include "xlockmore.h" /* in xscreensaver distribution */
71 #else /* STANDALONE */
72 #include "xlock.h" /* in xlockmore distribution */
73 #endif /* STANDALONE */
79 * neighbors of 0 randomizes it for 3, 4, 6, 8, 12 (last 2 are less likely)
82 #define DEF_NEIGHBORS "0" /* choose random value */
83 #define DEF_TRUCHET "False"
84 #define DEF_EYES "False"
85 #define DEF_SHARPTURN "False"
90 static Bool sharpturn;
92 static XrmOptionDescRec opts[] =
94 {(char *) "-neighbors", (char *) ".ant.neighbors", XrmoptionSepArg, (caddr_t) NULL},
95 {(char *) "-truchet", (char *) ".ant.truchet", XrmoptionNoArg, (caddr_t) "on"},
96 {(char *) "+truchet", (char *) ".ant.truchet", XrmoptionNoArg, (caddr_t) "off"},
97 {(char *) "-eyes", (char *) ".ant.eyes", XrmoptionNoArg, (caddr_t) "on"},
98 {(char *) "+eyes", (char *) ".ant.eyes", XrmoptionNoArg, (caddr_t) "off"},
99 {(char *) "-sharpturn", (char *) ".ant.sharpturn", XrmoptionNoArg, (caddr_t) "on"},
100 {(char *) "+sharpturn", (char *) ".ant.sharpturn", XrmoptionNoArg, (caddr_t) "off"},
101 {"-neighbors", ".ant.neighbors", XrmoptionSepArg, (caddr_t) 0},
102 {"+neighbors", ".ant.neighbors", XrmoptionSepArg, (caddr_t) 0}
104 static argtype vars[] =
106 {(caddr_t *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
107 {(caddr_t *) & truchet, (char *) "truchet", (char *) "Truchet", (char *) DEF_TRUCHET, t_Bool},
108 {(caddr_t *) & eyes, (char *) "eyes", (char *) "Eyes", (char *) DEF_EYES, t_Bool},
109 {(caddr_t *) & sharpturn, (char *) "sharpturn", (char *) "SharpTurn", (char *) DEF_SHARPTURN, t_Bool},
110 {(caddr_t *) & neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int}
112 static OptionStruct desc[] =
114 {(char *) "-neighbors num", (char *) "squares 4 or 8, hexagons 6, triangles 3 or 12"},
115 {(char *) "-/+truchet", (char *) "turn on/off Truchet lines"},
116 {(char *) "-/+eyes", (char *) "turn on/off eyes"},
117 {(char *) "-/+sharpturn", (char *) "turn on/off sharp turns (6, 8 or 12 neighbors only)"}
120 ModeSpecOpt ant_opts =
121 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
124 const ModStruct ant_description =
126 "init_ant", "draw_ant", "release_ant",
127 "refresh_ant", "init_ant", (char *) NULL, &ant_opts,
128 1000, -3, 40000, -12, 64, 1.0, "",
129 "Shows Langton's and Turk's generalized ants", 0, NULL};
133 #define ANTBITS(n,w,h)\
134 if ((ap->pixmaps[ap->init_bits]=\
135 XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
136 free_ant(display,ap); return;} else {ap->init_bits++;}
138 /* If you change the table you may have to change the following 2 constants */
141 #define REDRAWSTEP 2000 /* How much tape to draw per cycle */
142 #define MINGRIDSIZE 24
144 #define MINRANDOMSIZE 5
168 unsigned char ncolors, nstates;
170 int redrawing, redrawpos;
171 int truchet; /* Only for Turk modes */
174 statestruct machine[NUMSTIPPLES * STATES];
176 unsigned char *truchet_state;
179 unsigned char colors[NUMSTIPPLES - 1];
181 Pixmap pixmaps[NUMSTIPPLES - 1];
183 XPoint hexagon[7]; /* Need more than 6 for truchet */
184 XPoint triangle[2][4]; /* Need more than 3 for truchet */
188 static char plots[] =
195 #define NEIGHBORKINDS ((long) (sizeof plots / sizeof *plots))
196 #define GOODNEIGHBORKINDS 3
198 /* Relative ant moves */
199 #define FS 0 /* Step */
200 #define TRS 1 /* Turn right, then step */
201 #define THRS 2 /* Turn hard right, then step */
202 #define TBS 3 /* Turn back, then step */
203 #define THLS 4 /* Turn hard left, then step */
204 #define TLS 5 /* Turn left, then step */
205 #define SF 6 /* Step */
206 #define STR 7 /* Step then turn right */
207 #define STHR 8 /* Step then turn hard right */
208 #define STB 9 /* Step then turn back */
209 #define STHL 10 /* Step then turn hard left */
210 #define STL 11 /* Step then turn left */
212 static antfarmstruct *antfarms = (antfarmstruct *) NULL;
214 /* LANGTON'S ANT (10) Chaotic after 500, Builder after 10,000 (104p) */
215 /* TURK'S 100 ANT Always chaotic?, tested past 150,000,000 */
216 /* TURK'S 101 ANT Always chaotic? */
217 /* TURK'S 110 ANT Builder at 150 (18p) */
218 /* TURK'S 1000 ANT Always chaotic? */
219 /* TURK'S 1100 SYMMETRIC ANT all even run 1's and 0's are symmetric */
220 /* other examples 1001, 110011, 110000, 1001101 */
221 /* TURK'S 1101 ANT Builder after 250,000 (388p) */
222 /* Once saw a chess horse type builder (i.e. non-45 degree builder) */
225 /* All alternating 10 appear symmetric, no proof (i.e. 10, 1010, etc) */
226 /* Even runs of 0's and 1's are also symmetric */
227 /* I have seen Hexagonal builders but they are more rare. */
229 static unsigned char tables[][3 * NUMSTIPPLES * STATES + 2] =
232 /* Here just so you can figure out notation */
233 { /* Langton's ant */
238 /* First 2 numbers are the size (ncolors, nstates) */
239 { /* LADDER BUILDER */
241 1, STR, 0, 2, STL, 0, 3, TRS, 0, 0, TLS, 0
243 { /* SPIRALING PATTERN */
248 { /* SQUARE (HEXAGON) BUILDER */
256 #define NTABLES (sizeof tables / sizeof tables[0])
259 position_of_neighbor(antfarmstruct * ap, int dir, int *pcol, int *prow)
261 int col = *pcol, row = *prow;
263 if (ap->neighbors == 6) {
266 col = (col + 1 == ap->ncols) ? 0 : col + 1;
270 col = (col + 1 == ap->ncols) ? 0 : col + 1;
271 row = (!row) ? ap->nrows - 1 : row - 1;
275 col = (!col) ? ap->ncols - 1 : col - 1;
276 row = (!row) ? ap->nrows - 1 : row - 1;
279 col = (!col) ? ap->ncols - 1 : col - 1;
283 col = (!col) ? ap->ncols - 1 : col - 1;
284 row = (row + 1 == ap->nrows) ? 0 : row + 1;
288 col = (col + 1 == ap->ncols) ? 0 : col + 1;
289 row = (row + 1 == ap->nrows) ? 0 : row + 1;
292 (void) fprintf(stderr, "wrong direction %d\n", dir);
294 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
297 col = (col + 1 == ap->ncols) ? 0 : col + 1;
300 col = (col + 1 == ap->ncols) ? 0 : col + 1;
301 row = (!row) ? ap->nrows - 1 : row - 1;
304 row = (!row) ? ap->nrows - 1 : row - 1;
307 col = (!col) ? ap->ncols - 1 : col - 1;
308 row = (!row) ? ap->nrows - 1 : row - 1;
311 col = (!col) ? ap->ncols - 1 : col - 1;
314 col = (!col) ? ap->ncols - 1 : col - 1;
315 row = (row + 1 == ap->nrows) ? 0 : row + 1;
318 row = (row + 1 == ap->nrows) ? 0 : row + 1;
321 col = (col + 1 == ap->ncols) ? 0 : col + 1;
322 row = (row + 1 == ap->nrows) ? 0 : row + 1;
325 (void) fprintf(stderr, "wrong direction %d\n", dir);
328 if ((col + row) % 2) { /* right */
331 col = (!col) ? ap->ncols - 1 : col - 1;
335 col = (!col) ? ap->ncols - 1 : col - 1;
336 row = (!row) ? ap->nrows - 1 : row - 1;
339 col = (!col) ? ap->ncols - 1 : col - 1;
357 row = (!row) ? ap->nrows - 1 : row - 1;
361 col = (col + 1 == ap->ncols) ? 0 : col + 1;
362 row = (!row) ? ap->nrows - 1 : row - 1;
365 col = (col + 1 == ap->ncols) ? 0 : col + 1;
369 col = (col + 1 == ap->ncols) ? 0 : col + 1;
370 row = (row + 1 == ap->nrows) ? 0 : row + 1;
373 row = (row + 1 == ap->nrows) ? 0 : row + 1;
377 if (row + 1 == ap->nrows)
379 else if (row + 2 == ap->nrows)
385 col = (!col) ? ap->ncols - 1 : col - 1;
386 if (row + 1 == ap->nrows)
388 else if (row + 2 == ap->nrows)
395 col = (!col) ? ap->ncols - 1 : col - 1;
396 row = (row + 1 == ap->nrows) ? 0 : row + 1;
399 (void) fprintf(stderr, "wrong direction %d\n", dir);
404 col = (col + 1 == ap->ncols) ? 0 : col + 1;
408 col = (col + 1 == ap->ncols) ? 0 : col + 1;
409 row = (row + 1 == ap->nrows) ? 0 : row + 1;
412 col = (col + 1 == ap->ncols) ? 0 : col + 1;
413 if (row + 1 == ap->nrows)
415 else if (row + 2 == ap->nrows)
422 if (row + 1 == ap->nrows)
424 else if (row + 2 == ap->nrows)
430 row = (row + 1 == ap->nrows) ? 0 : row + 1;
434 col = (!col) ? ap->ncols - 1 : col - 1;
435 row = (row + 1 == ap->nrows) ? 0 : row + 1;
438 col = (!col) ? ap->ncols - 1 : col - 1;
442 col = (!col) ? ap->ncols - 1 : col - 1;
443 row = (!row) ? ap->nrows - 1 : row - 1;
446 row = (!row) ? ap->nrows - 1 : row - 1;
458 col = (col + 1 == ap->ncols) ? 0 : col + 1;
468 col = (col + 1 == ap->ncols) ? 0 : col + 1;
469 row = (!row) ? ap->nrows - 1 : row - 1;
472 (void) fprintf(stderr, "wrong direction %d\n", dir);
481 fillcell(ModeInfo * mi, GC gc, int col, int row)
483 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
485 if (ap->neighbors == 6) {
486 int ccol = 2 * col + !(row & 1), crow = 2 * row;
488 ap->shape.hexagon[0].x = ap->xb + ccol * ap->xs;
489 ap->shape.hexagon[0].y = ap->yb + crow * ap->ys;
490 if (ap->xs == 1 && ap->ys == 1)
491 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
492 ap->shape.hexagon[0].x, ap->shape.hexagon[0].y);
494 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
495 ap->shape.hexagon, 6, Convex, CoordModePrevious);
496 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
497 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
498 ap->xb + ap->xs * col, ap->yb + ap->ys * row,
499 ap->xs - (ap->xs > 3), ap->ys - (ap->ys > 3));
501 int orient = (col + row) % 2; /* O left 1 right */
503 ap->shape.triangle[orient][0].x = ap->xb + col * ap->xs;
504 ap->shape.triangle[orient][0].y = ap->yb + row * ap->ys;
505 if (ap->xs <= 3 || ap->ys <= 3)
506 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
507 ((orient) ? -1 : 1) + ap->shape.triangle[orient][0].x,
508 ap->shape.triangle[orient][0].y);
511 ap->shape.triangle[orient][0].x += (ap->xs / 2 - 1);
513 ap->shape.triangle[orient][0].x -= (ap->xs / 2 - 1);
514 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
515 ap->shape.triangle[orient], 3, Convex, CoordModePrevious);
521 truchetcell(ModeInfo * mi, int col, int row, int truchetstate)
523 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
525 if (ap->neighbors == 6) {
527 int ccol = 2 * col + !(row & 1), crow = 2 * row;
529 int fudge = 7; /* fudge because the hexagons are not exact */
533 hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs / 2.0) - 1;
534 hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys / 2.0) - 1;
535 for (side = 0; side < 6; side++) {
537 hex.x += ap->shape.hexagon[side].x;
538 hex.y += ap->shape.hexagon[side].y;
540 if (truchetstate == side % 2)
541 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
542 hex.x, hex.y, ap->xs, ap->ys,
543 ((570 - (side * 60) + fudge) % 360) * 64, (120 - 2 * fudge) * 64);
546 /* Very crude approx of Sqrt 3, so it will not cause drawing errors. */
547 hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs * 1.6 / 2.0) - 1;
548 hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys * 1.6 / 2.0) - 1;
549 for (side = 0; side < 6; side++) {
551 hex.x += ap->shape.hexagon[side].x;
552 hex.y += ap->shape.hexagon[side].y;
554 hex2.x = hex.x + ap->shape.hexagon[side + 1].x / 2;
555 hex2.y = hex.y + ap->shape.hexagon[side + 1].y / 2 + 1;
556 /* Lots of fudging here */
558 hex2.x += (short) (ap->xs * 0.1 + 1);
559 hex2.y += (short) (ap->ys * 0.1 - ((ap->ys > 5) ? 1 : 0));
560 } else if (side == 2) {
561 hex2.x += (short) (ap->xs * 0.1);
562 } else if (side == 4) {
563 hex2.x += (short) (ap->xs * 0.1);
564 hex2.y += (short) (ap->ys * 0.1 - 1);
565 } else if (side == 5) {
566 hex2.x += (short) (ap->xs * 0.5);
567 hex2.y += (short) (-ap->ys * 0.3 + 1);
569 if (truchetstate == side % 3)
570 /* Crude approx of 120 deg, so it will not cause drawing errors. */
571 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
573 (int) ((double) ap->xs * 1.5), (int) ((double) ap->ys * 1.5),
574 ((555 - (side * 60)) % 360) * 64, 90 * 64);
577 } else if (ap->neighbors == 4) {
579 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
580 ap->xb + ap->xs * col - ap->xs / 2 + 1,
581 ap->yb + ap->ys * row + ap->ys / 2 - 1,
582 ap->xs - 2, ap->ys - 2,
584 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
585 ap->xb + ap->xs * col + ap->xs / 2 - 1,
586 ap->yb + ap->ys * row - ap->ys / 2 + 1,
587 ap->xs - 2, ap->ys - 2,
590 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
591 ap->xb + ap->xs * col - ap->xs / 2 + 1,
592 ap->yb + ap->ys * row - ap->ys / 2 + 1,
593 ap->xs - 2, ap->ys - 2,
595 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
596 ap->xb + ap->xs * col + ap->xs / 2 - 1,
597 ap->yb + ap->ys * row + ap->ys / 2 - 1,
598 ap->xs - 2, ap->ys - 2,
601 } else if (ap->neighbors == 3) {
602 int orient = (col + row) % 2; /* O left 1 right */
604 int fudge = 7; /* fudge because the triangles are not exact */
605 double fudge2 = 1.18;
608 tri.x = ap->xb + col * ap->xs;
609 tri.y = ap->yb + row * ap->ys;
611 tri.x += (ap->xs / 2 - 1);
613 tri.x -= (ap->xs / 2 - 1);
615 for (side = 0; side < 3; side++) {
617 tri.x += ap->shape.triangle[orient][side].x;
618 tri.y += ap->shape.triangle[orient][side].y;
620 if (truchetstate == side) {
622 ang = (510 - side * 120) % 360; /* Right */
624 ang = (690 - side * 120) % 360; /* Left */
625 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
626 (int) (tri.x - ap->xs * fudge2 / 2),
627 (int) (tri.y - 3 * ap->ys * fudge2 / 4),
628 (unsigned int) (ap->xs * fudge2),
629 (unsigned int) (3 * ap->ys * fudge2 / 2),
630 (ang + fudge) * 64, (60 - 2 * fudge) * 64);
637 drawcell(ModeInfo * mi, int col, int row, unsigned char color)
639 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
643 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
645 } else if (MI_NPIXELS(mi) > 2) {
646 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
647 MI_PIXEL(mi, ap->colors[color - 1]));
652 gcv.stipple = ap->pixmaps[color - 1];
653 gcv.foreground = MI_WHITE_PIXEL(mi);
654 gcv.background = MI_BLACK_PIXEL(mi);
655 XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
656 GCStipple | GCForeground | GCBackground, &gcv);
659 fillcell(mi, gc, col, row);
663 drawtruchet(ModeInfo * mi, int col, int row,
664 unsigned char color, unsigned char truchetstate)
666 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
669 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
670 else if (MI_NPIXELS(mi) > 2 || color > ap->ncolors / 2)
671 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
673 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
674 truchetcell(mi, col, row, truchetstate);
678 draw_anant(ModeInfo * mi, int direction, int col, int row)
680 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
681 Display *display = MI_DISPLAY(mi);
682 Window window = MI_WINDOW(mi);
684 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
685 fillcell(mi, MI_GC(mi), col, row);
686 if (ap->eyes) { /* Draw Eyes */
687 XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
688 if (ap->neighbors == 6) {
689 int ccol = 2 * col + !(row & 1), crow = 2 * row;
693 if (!(ap->xs > 3 && ap->ys > 3))
695 hex.x = ap->xb + ccol * ap->xs;
696 hex.y = ap->yb + crow * ap->ys + ap->ys / 2;
697 ang = direction * ap->neighbors / ANGLES;
698 for (side = 0; side < ap->neighbors; side++) {
700 hex.x -= ap->shape.hexagon[side].x / 2;
701 hex.y += ap->shape.hexagon[side].y / 2;
703 if (side == (ap->neighbors + ang - 2) % ap->neighbors)
704 XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y);
705 if (side == (ap->neighbors + ang - 1) % ap->neighbors)
706 XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y);
708 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
709 if (!(ap->xs > 3 && ap->ys > 3))
713 XDrawPoint(display, window, MI_GC(mi),
714 ap->xb + ap->xs * (col + 1) - 3,
715 ap->yb + ap->ys * row + ap->ys / 2 - 2);
716 XDrawPoint(display, window, MI_GC(mi),
717 ap->xb + ap->xs * (col + 1) - 3,
718 ap->yb + ap->ys * row + ap->ys / 2);
721 XDrawPoint(display, window, MI_GC(mi),
722 ap->xb + ap->xs * (col + 1) - 4,
723 ap->yb + ap->ys * row + 1);
724 XDrawPoint(display, window, MI_GC(mi),
725 ap->xb + ap->xs * (col + 1) - 3,
726 ap->yb + ap->ys * row + 2);
729 XDrawPoint(display, window, MI_GC(mi),
730 ap->xb + ap->xs * col + ap->xs / 2 - 2,
731 ap->yb + ap->ys * row + 1);
732 XDrawPoint(display, window, MI_GC(mi),
733 ap->xb + ap->xs * col + ap->xs / 2,
734 ap->yb + ap->ys * row + 1);
737 XDrawPoint(display, window, MI_GC(mi),
738 ap->xb + ap->xs * col + 2,
739 ap->yb + ap->ys * row + 1);
740 XDrawPoint(display, window, MI_GC(mi),
741 ap->xb + ap->xs * col + 1,
742 ap->yb + ap->ys * row + 2);
745 XDrawPoint(display, window, MI_GC(mi),
746 ap->xb + ap->xs * col + 1,
747 ap->yb + ap->ys * row + ap->ys / 2 - 2);
748 XDrawPoint(display, window, MI_GC(mi),
749 ap->xb + ap->xs * col + 1,
750 ap->yb + ap->ys * row + ap->ys / 2);
753 XDrawPoint(display, window, MI_GC(mi),
754 ap->xb + ap->xs * col + 2,
755 ap->yb + ap->ys * (row + 1) - 3);
756 XDrawPoint(display, window, MI_GC(mi),
757 ap->xb + ap->xs * col + 1,
758 ap->yb + ap->ys * (row + 1) - 4);
761 XDrawPoint(display, window, MI_GC(mi),
762 ap->xb + ap->xs * col + ap->xs / 2 - 2,
763 ap->yb + ap->ys * (row + 1) - 3);
764 XDrawPoint(display, window, MI_GC(mi),
765 ap->xb + ap->xs * col + ap->xs / 2,
766 ap->yb + ap->ys * (row + 1) - 3);
769 XDrawPoint(display, window, MI_GC(mi),
770 ap->xb + ap->xs * (col + 1) - 4,
771 ap->yb + ap->ys * (row + 1) - 3);
772 XDrawPoint(display, window, MI_GC(mi),
773 ap->xb + ap->xs * (col + 1) - 3,
774 ap->yb + ap->ys * (row + 1) - 4);
777 (void) fprintf(stderr, "wrong eyes direction %d for ant eyes\n", direction);
780 int orient = (col + row) % 2; /* O left 1 right */
784 if (!(ap->xs > 6 && ap->ys > 6))
786 tri.x = ap->xb + col * ap->xs;
787 tri.y = ap->yb + row * ap->ys;
789 tri.x += (ap->xs / 6 - 1);
791 tri.x -= (ap->xs / 6 - 1);
792 ang = direction * ap->neighbors / ANGLES;
793 /* approx... does not work that well for even numbers */
796 ap->neighbors == 9 ||
798 ap->neighbors == 12) {
799 #ifdef UNDER_CONSTRUCTION
800 /* Not sure why this does not work */
801 ang = ((ang + ap->neighbors / 6) / (ap->neighbors / 3)) % 3;
806 for (side = 0; side < 3; side++) {
808 tri.x += ap->shape.triangle[orient][side].x / 3;
809 tri.y += ap->shape.triangle[orient][side].y / 3;
811 /* Either you have the eyes in back or one eye in front */
814 XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
816 if (side == (ang + 2) % 3)
817 XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
818 if (side == (ang + 1) % 3)
819 XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
831 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
832 int row, col, mrow = 0;
834 for (row = 0; row < ap->nrows; ++row) {
835 for (col = 0; col < ap->ncols; ++col) {
836 ap->old[col + mrow] = (unsigned char) NRAND((int) ap->ncolors);
837 drawcell(mi, col, row, ap->old[col + mrow]);
846 fromTableDirection(unsigned char dir, int local_neighbors)
848 /* Crafted to work for odd number of neighbors */
853 return (ANGLES / local_neighbors);
855 return (2 * ANGLES / local_neighbors);
857 return ((local_neighbors / 2) * ANGLES / local_neighbors);
859 return (ANGLES - 2 * ANGLES / local_neighbors);
861 return (ANGLES - ANGLES / local_neighbors);
865 return (ANGLES + ANGLES / local_neighbors);
867 return (ANGLES + 2 * ANGLES / local_neighbors);
869 return (ANGLES + (local_neighbors / 2) * ANGLES / local_neighbors);
871 return (2 * ANGLES - 2 * ANGLES / local_neighbors);
873 return (2 * ANGLES - ANGLES / local_neighbors);
875 (void) fprintf(stderr, "wrong direction %d from table\n", dir);
881 getTable(ModeInfo * mi, int i)
883 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
885 unsigned char *patptr;
887 patptr = &tables[i][0];
888 ap->ncolors = *patptr++;
889 ap->nstates = *patptr++;
890 total = ap->ncolors * ap->nstates;
891 if (MI_IS_VERBOSE(mi))
892 (void) fprintf(stdout,
893 "ants %d, neighbors %d, table number %d, colors %d, states %d\n",
894 ap->n, ap->neighbors, i, ap->ncolors, ap->nstates);
895 for (j = 0; j < total; j++) {
896 ap->machine[j].color = *patptr++;
897 if (ap->sharpturn && ap->neighbors > 4) {
928 ap->machine[j].direction = fromTableDirection(k, ap->neighbors);
930 ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors);
932 ap->machine[j].next = *patptr++;
938 getTurk(ModeInfo * mi, int i)
940 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
941 int power2, j, number, total;
943 /* To force a number, say <i = 2;> has i + 2 (or 4) binary digits */
944 power2 = 1 << (i + 1);
945 /* Do not want numbers which in binary are all 1's. */
946 number = NRAND(power2 - 1) + power2;
947 /* To force a particular number, say <number = 10;> */
951 total = ap->ncolors * ap->nstates;
952 for (j = 0; j < total; j++) {
953 ap->machine[j].color = (j + 1) % total;
954 if (ap->sharpturn && ap->neighbors > 4) {
955 ap->machine[j].direction = (power2 & number) ?
956 fromTableDirection(THRS, ap->neighbors) :
957 fromTableDirection(THLS, ap->neighbors);
959 ap->machine[j].direction = (power2 & number) ?
960 fromTableDirection(TRS, ap->neighbors) :
961 fromTableDirection(TLS, ap->neighbors);
963 ap->machine[j].next = 0;
966 ap->truchet = (ap->truchet && ap->xs > 2 && ap->ys > 2 &&
967 (ap->neighbors == 3 || ap->neighbors == 4 || ap->neighbors == 6));
968 if (MI_IS_VERBOSE(mi))
969 (void) fprintf(stdout,
970 "ants %d, neighbors %d, Turk's number %d, colors %d\n",
971 ap->n, ap->neighbors, number, ap->ncolors);
975 free_ant(Display *display, antfarmstruct *ap)
979 if (ap->stippledGC != None) {
980 XFreeGC(display, ap->stippledGC);
981 ap->stippledGC = None;
983 for (shade = 0; shade < ap->init_bits; shade++) {
984 XFreePixmap(display, ap->pixmaps[shade]);
987 if (ap->tape != NULL) {
988 (void) free((void *) ap->tape);
989 ap->tape = (unsigned char *) NULL;
991 if (ap->ants != NULL) {
992 (void) free((void *) ap->ants);
993 ap->ants = (antstruct *) NULL;
995 if (ap->truchet_state != NULL) {
996 (void) free((void *) ap->truchet_state);
997 ap->truchet_state = (unsigned char *) NULL;
1002 init_ant(ModeInfo * mi)
1004 Display *display = MI_DISPLAY(mi);
1005 Window window = MI_WINDOW(mi);
1006 int size = MI_SIZE(mi);
1011 if (antfarms == NULL) {
1012 if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi),
1013 sizeof (antfarmstruct))) == NULL)
1016 ap = &antfarms[MI_SCREEN(mi)];
1019 if (MI_NPIXELS(mi) <= 2) {
1020 if (ap->stippledGC == None) {
1023 gcv.fill_style = FillOpaqueStippled;
1024 if ((ap->stippledGC = XCreateGC(display, window, GCFillStyle,
1026 free_ant(display, ap);
1030 if (ap->init_bits == 0) {
1031 for (i = 1; i < NUMSTIPPLES; i++) {
1032 ANTBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
1037 ap->n = MI_COUNT(mi);
1038 if (ap->n < -MINANTS) {
1039 /* if ap->n is random ... the size can change */
1040 if (ap->ants != NULL) {
1041 (void) free((void *) ap->ants);
1042 ap->ants = (antstruct *) NULL;
1044 ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;
1045 } else if (ap->n < MINANTS)
1048 ap->width = MI_WIDTH(mi);
1049 ap->height = MI_HEIGHT(mi);
1051 for (i = 0; i < NEIGHBORKINDS; i++) {
1052 if (neighbors == plots[i]) {
1053 ap->neighbors = plots[i];
1056 if (i == NEIGHBORKINDS - 1) {
1058 /* Make above 6 rare */
1059 ap->neighbors = plots[NRAND(NEIGHBORKINDS)];
1061 ap->neighbors = plots[NRAND(GOODNEIGHBORKINDS)];
1067 if (ap->neighbors == 6) {
1074 if (size < -MINSIZE) {
1075 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1076 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1077 if (ap->ys < MINRANDOMSIZE)
1078 ap->ys = MIN(MINRANDOMSIZE,
1079 MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1080 } else if (size < MINSIZE) {
1082 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1086 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1089 nccols = MAX(ap->width / ap->xs - 2, 2);
1090 ncrows = MAX(ap->height / ap->ys - 1, 4);
1091 ap->ncols = nccols / 2;
1092 ap->nrows = 2 * (ncrows / 4);
1093 ap->xb = (ap->width - ap->xs * nccols) / 2 + ap->xs / 2;
1094 ap->yb = (ap->height - ap->ys * (ncrows / 2) * 2) / 2 + ap->ys - 2;
1095 for (i = 0; i < 6; i++) {
1096 ap->shape.hexagon[i].x = (ap->xs - 1) * hexagonUnit[i].x;
1097 ap->shape.hexagon[i].y = ((ap->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
1099 /* Avoid array bounds read of hexagonUnit */
1100 ap->shape.hexagon[6].x = 0;
1101 ap->shape.hexagon[6].y = 0;
1102 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
1103 if (size < -MINSIZE) {
1104 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1105 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1106 if (ap->ys < MINRANDOMSIZE)
1107 ap->ys = MIN(MINRANDOMSIZE,
1108 MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1109 } else if (size < MINSIZE) {
1111 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1115 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1118 ap->ncols = MAX(ap->width / ap->xs, 2);
1119 ap->nrows = MAX(ap->height / ap->ys, 2);
1120 ap->xb = (ap->width - ap->xs * ap->ncols) / 2;
1121 ap->yb = (ap->height - ap->ys * ap->nrows) / 2;
1129 if (size < -MINSIZE) {
1130 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1131 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1132 if (ap->ys < MINRANDOMSIZE)
1133 ap->ys = MIN(MINRANDOMSIZE,
1134 MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1135 } else if (size < MINSIZE) {
1137 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1141 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1143 ap->xs = (int) (1.52 * ap->ys);
1144 ap->ncols = (MAX(ap->width / ap->xs - 1, 2) / 2) * 2;
1145 ap->nrows = (MAX(ap->height / ap->ys - 1, 2) / 2) * 2;
1146 ap->xb = (ap->width - ap->xs * ap->ncols) / 2 + ap->xs / 2;
1147 ap->yb = (ap->height - ap->ys * ap->nrows) / 2 + ap->ys;
1148 for (orient = 0; orient < 2; orient++) {
1149 for (i = 0; i < 3; i++) {
1150 ap->shape.triangle[orient][i].x =
1151 (ap->xs - 2) * triangleUnit[orient][i].x;
1152 ap->shape.triangle[orient][i].y =
1153 (ap->ys - 2) * triangleUnit[orient][i].y;
1155 /* Avoid array bounds read of triangleUnit */
1156 ap->shape.triangle[orient][3].x = 0;
1157 ap->shape.triangle[orient][3].y = 0;
1161 XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinMiter);
1163 ap->painted = False;
1165 if (MI_IS_FULLRANDOM(mi)) {
1166 ap->truchet = (Bool) (LRAND() & 1);
1167 ap->eyes = (Bool) (LRAND() & 1);
1168 ap->sharpturn = (Bool) (LRAND() & 1);
1170 ap->truchet = truchet;
1172 ap->sharpturn = sharpturn;
1174 if (!NRAND(NUMSTIPPLES)) {
1175 getTable(mi, (int) (NRAND(NTABLES)));
1177 getTurk(mi, (int) (NRAND(NUMSTIPPLES - 1)));
1178 if (MI_NPIXELS(mi) > 2)
1179 for (i = 0; i < (int) ap->ncolors - 1; i++)
1180 ap->colors[i] = (unsigned char) (NRAND(MI_NPIXELS(mi)) +
1181 i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1));
1182 if (ap->ants == NULL) {
1183 if ((ap->ants = (antstruct *) malloc(ap->n * sizeof (antstruct))) ==
1185 free_ant(display, ap);
1189 if (ap->tape != NULL)
1190 (void) free((void *) ap->tape);
1191 if ((ap->tape = (unsigned char *) calloc(ap->ncols * ap->nrows,
1192 sizeof (unsigned char))) == NULL) {
1193 free_ant(display, ap);
1196 if (ap->truchet_state != NULL)
1197 (void) free((void *) ap->truchet_state);
1198 if ((ap->truchet_state = (unsigned char *) calloc(ap->ncols * ap->nrows,
1199 sizeof (unsigned char))) == NULL) {
1200 free_ant(display, ap);
1204 row = ap->nrows / 2;
1205 col = ap->ncols / 2;
1206 if (col > 0 && ((ap->neighbors % 2) || ap->neighbors == 12) && (LRAND() & 1))
1208 dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors;
1211 if (ap->neighbors == 9 && !((col + row) & 1))
1212 dir = (dir + ANGLES - ANGLES / (ap->neighbors * 2)) % ANGLES;
1214 /* Have them all start in the same spot, why not? */
1215 for (i = 0; i < ap->n; i++) {
1216 ap->ants[i].col = col;
1217 ap->ants[i].row = row;
1218 ap->ants[i].direction = dir;
1219 ap->ants[i].state = 0;
1221 draw_anant(mi, dir, col, row);
1225 draw_ant(ModeInfo * mi)
1228 statestruct *status;
1229 int i, state_pos, tape_pos;
1230 unsigned char color;
1231 short chg_dir, old_dir;
1234 if (antfarms == NULL)
1236 ap = &antfarms[MI_SCREEN(mi)];
1237 if (ap->ants == NULL)
1240 MI_IS_DRAWN(mi) = True;
1242 for (i = 0; i < ap->n; i++) {
1243 anant = &ap->ants[i];
1244 tape_pos = anant->col + anant->row * ap->ncols;
1245 color = ap->tape[tape_pos]; /* read tape */
1246 state_pos = color + anant->state * ap->ncolors;
1247 status = &(ap->machine[state_pos]);
1248 drawcell(mi, anant->col, anant->row, status->color);
1249 ap->tape[tape_pos] = status->color; /* write on tape */
1251 /* Find direction of Bees or Ants. */
1252 /* Translate relative direction to actual direction */
1253 old_dir = anant->direction;
1254 chg_dir = (2 * ANGLES - status->direction) % ANGLES;
1255 anant->direction = (chg_dir + old_dir) % ANGLES;
1259 if (ap->neighbors == 6) {
1260 if (ap->sharpturn) {
1261 a = (((ANGLES + anant->direction - old_dir) % ANGLES) == 240);
1262 /* should be some way of getting rid of the init_dir dependency... */
1263 b = !(ap->init_dir % 120);
1264 a = ((a && !b) || (b && !a));
1265 drawtruchet(mi, anant->col, anant->row, status->color, a);
1267 a = (old_dir / 60) % 3;
1268 b = (anant->direction / 60) % 3;
1269 a = (a + b + 1) % 3;
1270 drawtruchet(mi, anant->col, anant->row, status->color, a);
1272 } else if (ap->neighbors == 4) {
1274 b = anant->direction / 180;
1275 a = ((a && !b) || (b && !a));
1276 drawtruchet(mi, anant->col, anant->row, status->color, a);
1277 } else if (ap->neighbors == 3) {
1279 a = (2 + anant->direction / 120) % 3;
1281 a = (1 + anant->direction / 120) % 3;
1282 drawtruchet(mi, anant->col, anant->row, status->color, a);
1284 ap->truchet_state[tape_pos] = a + 1;
1286 anant->state = status->next;
1288 /* Allow step first and turn */
1289 old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir);
1291 (void) printf("old_dir %d, col %d, row %d", old_dir, anant->col, anant->row);
1293 position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row));
1295 (void) printf(", ncol %d, nrow %d\n", anant->col, anant->row);
1297 draw_anant(mi, anant->direction, anant->col, anant->row);
1299 if (++ap->generation > MI_CYCLES(mi)) {
1301 erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
1305 if (ap->redrawing) {
1306 for (i = 0; i < REDRAWSTEP; i++) {
1307 if (ap->tape[ap->redrawpos] ||
1308 (ap->truchet && ap->truchet_state[ap->redrawpos])) {
1309 drawcell(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1310 ap->tape[ap->redrawpos]);
1312 drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1313 ap->tape[ap->redrawpos],
1314 ap->truchet_state[ap->redrawpos] - 1);
1316 if (++(ap->redrawpos) >= ap->ncols * ap->nrows) {
1325 release_ant(ModeInfo * mi)
1327 if (antfarms != NULL) {
1330 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1331 free_ant(MI_DISPLAY(mi), &antfarms[screen]);
1332 (void) free((void *) antfarms);
1333 antfarms = (antfarmstruct *) NULL;
1338 refresh_ant(ModeInfo * mi)
1342 if (antfarms == NULL)
1344 ap = &antfarms[MI_SCREEN(mi)];
1353 #endif /* MODE_ant */