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.
56 /*# define DO_STIPPLE*/
61 # define DEFAULTS "*delay: 20000 \n" \
66 "*fpsSolid: true \n" \
68 # define reshape_ant 0
69 # define ant_handle_event 0
70 # include "xlockmore.h" /* in xscreensaver distribution */
72 #else /* STANDALONE */
73 # include "xlock.h" /* in xlockmore distribution */
74 #endif /* STANDALONE */
80 * neighbors of 0 randomizes it for 3, 4, 6, 8, 12 (last 2 are less likely)
83 #define DEF_NEIGHBORS "0" /* choose random value */
84 #define DEF_TRUCHET "False"
85 #define DEF_EYES "False"
86 #define DEF_SHARPTURN "False"
91 static Bool sharpturn;
93 static XrmOptionDescRec opts[] =
95 {"-neighbors", ".ant.neighbors", XrmoptionSepArg, 0},
96 {"-truchet", ".ant.truchet", XrmoptionNoArg, "on"},
97 {"+truchet", ".ant.truchet", XrmoptionNoArg, "off"},
98 {"-eyes", ".ant.eyes", XrmoptionNoArg, "on"},
99 {"+eyes", ".ant.eyes", XrmoptionNoArg, "off"},
100 {"-sharpturn", ".ant.sharpturn", XrmoptionNoArg, "on"},
101 {"+sharpturn", ".ant.sharpturn", XrmoptionNoArg, "off"},
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},
110 static OptionStruct desc[] =
112 {"-neighbors num", "squares 4 or 8, hexagons 6, triangles 3 or 12"},
113 {"-/+truchet", "turn on/off Truchet lines"},
114 {"-/+eyes", "turn on/off eyes"},
115 {"-/+sharpturn", "turn on/off sharp turns (6, 8 or 12 neighbors only)"}
118 ENTRYPOINT ModeSpecOpt ant_opts =
119 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
122 const ModStruct ant_description =
124 "init_ant", "draw_ant", "release_ant",
125 "refresh_ant", "init_ant", (char *) 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 if ((ap->pixmaps[ap->init_bits]=\
133 XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
134 free_ant(display,ap); return;} else {ap->init_bits++;}
136 /* If you change the table you may have to change the following 2 constants */
139 #define REDRAWSTEP 2000 /* How much tape to draw per cycle */
140 #define MINGRIDSIZE 24
142 #define MINRANDOMSIZE 5
166 unsigned char ncolors, nstates;
168 int redrawing, redrawpos;
169 int truchet; /* Only for Turk modes */
172 statestruct machine[NUMSTIPPLES * STATES];
174 unsigned char *truchet_state;
177 unsigned char colors[NUMSTIPPLES - 1];
180 # endif /* DO_STIPPLE */
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 */
187 eraser_state *eraser;
191 static char plots[] =
198 #define NEIGHBORKINDS ((long) (sizeof plots / sizeof *plots))
199 #define GOODNEIGHBORKINDS 3
201 /* Relative ant moves */
202 #define FS 0 /* Step */
203 #define TRS 1 /* Turn right, then step */
204 #define THRS 2 /* Turn hard right, then step */
205 #define TBS 3 /* Turn back, then step */
206 #define THLS 4 /* Turn hard left, then step */
207 #define TLS 5 /* Turn left, then step */
208 #define SF 6 /* Step */
209 #define STR 7 /* Step then turn right */
210 #define STHR 8 /* Step then turn hard right */
211 #define STB 9 /* Step then turn back */
212 #define STHL 10 /* Step then turn hard left */
213 #define STL 11 /* Step then turn left */
215 static antfarmstruct *antfarms = (antfarmstruct *) NULL;
217 /* LANGTON'S ANT (10) Chaotic after 500, Builder after 10,000 (104p) */
218 /* TURK'S 100 ANT Always chaotic?, tested past 150,000,000 */
219 /* TURK'S 101 ANT Always chaotic? */
220 /* TURK'S 110 ANT Builder at 150 (18p) */
221 /* TURK'S 1000 ANT Always chaotic? */
222 /* TURK'S 1100 SYMMETRIC ANT all even run 1's and 0's are symmetric */
223 /* other examples 1001, 110011, 110000, 1001101 */
224 /* TURK'S 1101 ANT Builder after 250,000 (388p) */
225 /* Once saw a chess horse type builder (i.e. non-45 degree builder) */
228 /* All alternating 10 appear symmetric, no proof (i.e. 10, 1010, etc) */
229 /* Even runs of 0's and 1's are also symmetric */
230 /* I have seen Hexagonal builders but they are more rare. */
232 static unsigned char tables[][3 * NUMSTIPPLES * STATES + 2] =
235 /* Here just so you can figure out notation */
236 { /* Langton's ant */
241 /* First 2 numbers are the size (ncolors, nstates) */
242 { /* LADDER BUILDER */
244 1, STR, 0, 2, STL, 0, 3, TRS, 0, 0, TLS, 0
246 { /* SPIRALING PATTERN */
251 { /* SQUARE (HEXAGON) BUILDER */
259 #define NTABLES (sizeof tables / sizeof tables[0])
262 position_of_neighbor(antfarmstruct * ap, int dir, int *pcol, int *prow)
264 int col = *pcol, row = *prow;
266 if (ap->neighbors == 6) {
269 col = (col + 1 == ap->ncols) ? 0 : col + 1;
273 col = (col + 1 == ap->ncols) ? 0 : col + 1;
274 row = (!row) ? ap->nrows - 1 : row - 1;
278 col = (!col) ? ap->ncols - 1 : col - 1;
279 row = (!row) ? ap->nrows - 1 : row - 1;
282 col = (!col) ? ap->ncols - 1 : col - 1;
286 col = (!col) ? ap->ncols - 1 : col - 1;
287 row = (row + 1 == ap->nrows) ? 0 : row + 1;
291 col = (col + 1 == ap->ncols) ? 0 : col + 1;
292 row = (row + 1 == ap->nrows) ? 0 : row + 1;
295 (void) fprintf(stderr, "wrong direction %d\n", dir);
297 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
300 col = (col + 1 == ap->ncols) ? 0 : col + 1;
303 col = (col + 1 == ap->ncols) ? 0 : col + 1;
304 row = (!row) ? ap->nrows - 1 : row - 1;
307 row = (!row) ? ap->nrows - 1 : row - 1;
310 col = (!col) ? ap->ncols - 1 : col - 1;
311 row = (!row) ? ap->nrows - 1 : row - 1;
314 col = (!col) ? ap->ncols - 1 : col - 1;
317 col = (!col) ? ap->ncols - 1 : col - 1;
318 row = (row + 1 == ap->nrows) ? 0 : row + 1;
321 row = (row + 1 == ap->nrows) ? 0 : row + 1;
324 col = (col + 1 == ap->ncols) ? 0 : col + 1;
325 row = (row + 1 == ap->nrows) ? 0 : row + 1;
328 (void) fprintf(stderr, "wrong direction %d\n", dir);
331 if ((col + row) % 2) { /* right */
334 col = (!col) ? ap->ncols - 1 : col - 1;
338 col = (!col) ? ap->ncols - 1 : col - 1;
339 row = (!row) ? ap->nrows - 1 : row - 1;
342 col = (!col) ? ap->ncols - 1 : col - 1;
360 row = (!row) ? ap->nrows - 1 : row - 1;
364 col = (col + 1 == ap->ncols) ? 0 : col + 1;
365 row = (!row) ? ap->nrows - 1 : row - 1;
368 col = (col + 1 == ap->ncols) ? 0 : col + 1;
372 col = (col + 1 == ap->ncols) ? 0 : col + 1;
373 row = (row + 1 == ap->nrows) ? 0 : row + 1;
376 row = (row + 1 == ap->nrows) ? 0 : row + 1;
380 if (row + 1 == ap->nrows)
382 else if (row + 2 == ap->nrows)
388 col = (!col) ? ap->ncols - 1 : col - 1;
389 if (row + 1 == ap->nrows)
391 else if (row + 2 == ap->nrows)
398 col = (!col) ? ap->ncols - 1 : col - 1;
399 row = (row + 1 == ap->nrows) ? 0 : row + 1;
402 (void) fprintf(stderr, "wrong direction %d\n", dir);
407 col = (col + 1 == ap->ncols) ? 0 : col + 1;
411 col = (col + 1 == ap->ncols) ? 0 : col + 1;
412 row = (row + 1 == ap->nrows) ? 0 : row + 1;
415 col = (col + 1 == ap->ncols) ? 0 : col + 1;
416 if (row + 1 == ap->nrows)
418 else if (row + 2 == ap->nrows)
425 if (row + 1 == ap->nrows)
427 else if (row + 2 == ap->nrows)
433 row = (row + 1 == ap->nrows) ? 0 : row + 1;
437 col = (!col) ? ap->ncols - 1 : col - 1;
438 row = (row + 1 == ap->nrows) ? 0 : row + 1;
441 col = (!col) ? ap->ncols - 1 : col - 1;
445 col = (!col) ? ap->ncols - 1 : col - 1;
446 row = (!row) ? ap->nrows - 1 : row - 1;
449 row = (!row) ? ap->nrows - 1 : row - 1;
461 col = (col + 1 == ap->ncols) ? 0 : col + 1;
471 col = (col + 1 == ap->ncols) ? 0 : col + 1;
472 row = (!row) ? ap->nrows - 1 : row - 1;
475 (void) fprintf(stderr, "wrong direction %d\n", dir);
484 fillcell(ModeInfo * mi, GC gc, int col, int row)
486 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
488 if (ap->neighbors == 6) {
489 int ccol = 2 * col + !(row & 1), crow = 2 * row;
491 ap->shape.hexagon[0].x = ap->xb + ccol * ap->xs;
492 ap->shape.hexagon[0].y = ap->yb + crow * ap->ys;
493 if (ap->xs == 1 && ap->ys == 1)
494 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
495 ap->shape.hexagon[0].x, ap->shape.hexagon[0].y);
497 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
498 ap->shape.hexagon, 6, Convex, CoordModePrevious);
499 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
500 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
501 ap->xb + ap->xs * col, ap->yb + ap->ys * row,
502 ap->xs - (ap->xs > 3), ap->ys - (ap->ys > 3));
504 int orient = (col + row) % 2; /* O left 1 right */
506 ap->shape.triangle[orient][0].x = ap->xb + col * ap->xs;
507 ap->shape.triangle[orient][0].y = ap->yb + row * ap->ys;
508 if (ap->xs <= 3 || ap->ys <= 3)
509 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
510 ((orient) ? -1 : 1) + ap->shape.triangle[orient][0].x,
511 ap->shape.triangle[orient][0].y);
514 ap->shape.triangle[orient][0].x += (ap->xs / 2 - 1);
516 ap->shape.triangle[orient][0].x -= (ap->xs / 2 - 1);
517 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
518 ap->shape.triangle[orient], 3, Convex, CoordModePrevious);
524 truchetcell(ModeInfo * mi, int col, int row, int truchetstate)
526 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
528 if (ap->neighbors == 6) {
530 int ccol = 2 * col + !(row & 1), crow = 2 * row;
532 int fudge = 7; /* fudge because the hexagons are not exact */
536 hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs / 2.0) - 1;
537 hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys / 2.0) - 1;
538 for (side = 0; side < 6; side++) {
540 hex.x += ap->shape.hexagon[side].x;
541 hex.y += ap->shape.hexagon[side].y;
543 if (truchetstate == side % 2)
544 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
545 hex.x, hex.y, ap->xs, ap->ys,
546 ((570 - (side * 60) + fudge) % 360) * 64, (120 - 2 * fudge) * 64);
549 /* Very crude approx of Sqrt 3, so it will not cause drawing errors. */
550 hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs * 1.6 / 2.0) - 1;
551 hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys * 1.6 / 2.0) - 1;
552 for (side = 0; side < 6; side++) {
554 hex.x += ap->shape.hexagon[side].x;
555 hex.y += ap->shape.hexagon[side].y;
557 hex2.x = hex.x + ap->shape.hexagon[side + 1].x / 2;
558 hex2.y = hex.y + ap->shape.hexagon[side + 1].y / 2 + 1;
559 /* Lots of fudging here */
561 hex2.x += (short) (ap->xs * 0.1 + 1);
562 hex2.y += (short) (ap->ys * 0.1 - ((ap->ys > 5) ? 1 : 0));
563 } else if (side == 2) {
564 hex2.x += (short) (ap->xs * 0.1);
565 } else if (side == 4) {
566 hex2.x += (short) (ap->xs * 0.1);
567 hex2.y += (short) (ap->ys * 0.1 - 1);
568 } else if (side == 5) {
569 hex2.x += (short) (ap->xs * 0.5);
570 hex2.y += (short) (-ap->ys * 0.3 + 1);
572 if (truchetstate == side % 3)
573 /* Crude approx of 120 deg, so it will not cause drawing errors. */
574 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
576 (int) ((double) ap->xs * 1.5), (int) ((double) ap->ys * 1.5),
577 ((555 - (side * 60)) % 360) * 64, 90 * 64);
580 } else if (ap->neighbors == 4) {
582 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
583 ap->xb + ap->xs * col - ap->xs / 2 + 1,
584 ap->yb + ap->ys * row + ap->ys / 2 - 1,
585 ap->xs - 2, ap->ys - 2,
587 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
588 ap->xb + ap->xs * col + ap->xs / 2 - 1,
589 ap->yb + ap->ys * row - ap->ys / 2 + 1,
590 ap->xs - 2, ap->ys - 2,
593 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
594 ap->xb + ap->xs * col - ap->xs / 2 + 1,
595 ap->yb + ap->ys * row - ap->ys / 2 + 1,
596 ap->xs - 2, ap->ys - 2,
598 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
599 ap->xb + ap->xs * col + ap->xs / 2 - 1,
600 ap->yb + ap->ys * row + ap->ys / 2 - 1,
601 ap->xs - 2, ap->ys - 2,
604 } else if (ap->neighbors == 3) {
605 int orient = (col + row) % 2; /* O left 1 right */
607 int fudge = 7; /* fudge because the triangles are not exact */
608 double fudge2 = 1.18;
611 tri.x = ap->xb + col * ap->xs;
612 tri.y = ap->yb + row * ap->ys;
614 tri.x += (ap->xs / 2 - 1);
616 tri.x -= (ap->xs / 2 - 1);
618 for (side = 0; side < 3; side++) {
620 tri.x += ap->shape.triangle[orient][side].x;
621 tri.y += ap->shape.triangle[orient][side].y;
623 if (truchetstate == side) {
625 ang = (510 - side * 120) % 360; /* Right */
627 ang = (690 - side * 120) % 360; /* Left */
628 XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
629 (int) (tri.x - ap->xs * fudge2 / 2),
630 (int) (tri.y - 3 * ap->ys * fudge2 / 4),
631 (unsigned int) (ap->xs * fudge2),
632 (unsigned int) (3 * ap->ys * fudge2 / 2),
633 (ang + fudge) * 64, (60 - 2 * fudge) * 64);
640 drawcell(ModeInfo * mi, int col, int row, unsigned char color)
642 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
646 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
649 } else if (MI_NPIXELS(mi) <= 2) {
651 gcv.foreground = MI_WHITE_PIXEL(mi);
652 gcv.background = MI_BLACK_PIXEL(mi);
653 gcv.stipple = ap->pixmaps[color - 1];
654 XChangeGC(MI_DISPLAY(mi), ap->stippledGC,
655 GCStipple | GCForeground | GCBackground, &gcv);
657 # endif /* !DO_STIPPLE */
659 XSetForeground(MI_DISPLAY(mi), MI_GC(mi),
660 MI_PIXEL(mi, ap->colors[color - 1]));
663 fillcell(mi, gc, col, row);
667 drawtruchet(ModeInfo * mi, int col, int row,
668 unsigned char color, unsigned char truchetstate)
670 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
673 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
674 else if (MI_NPIXELS(mi) > 2 || color > ap->ncolors / 2)
675 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
677 XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
678 truchetcell(mi, col, row, truchetstate);
682 draw_anant(ModeInfo * mi, int direction, int col, int row)
684 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
685 Display *display = MI_DISPLAY(mi);
686 Window window = MI_WINDOW(mi);
688 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
689 fillcell(mi, MI_GC(mi), col, row);
690 if (ap->eyes) { /* Draw Eyes */
691 XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
692 if (ap->neighbors == 6) {
693 int ccol = 2 * col + !(row & 1), crow = 2 * row;
697 if (!(ap->xs > 3 && ap->ys > 3))
699 hex.x = ap->xb + ccol * ap->xs;
700 hex.y = ap->yb + crow * ap->ys + ap->ys / 2;
701 ang = direction * ap->neighbors / ANGLES;
702 for (side = 0; side < ap->neighbors; side++) {
704 hex.x -= ap->shape.hexagon[side].x / 2;
705 hex.y += ap->shape.hexagon[side].y / 2;
707 if (side == (ap->neighbors + ang - 2) % ap->neighbors)
708 XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y);
709 if (side == (ap->neighbors + ang - 1) % ap->neighbors)
710 XDrawPoint(display, window, MI_GC(mi), hex.x, hex.y);
712 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
713 if (!(ap->xs > 3 && ap->ys > 3))
717 XDrawPoint(display, window, MI_GC(mi),
718 ap->xb + ap->xs * (col + 1) - 3,
719 ap->yb + ap->ys * row + ap->ys / 2 - 2);
720 XDrawPoint(display, window, MI_GC(mi),
721 ap->xb + ap->xs * (col + 1) - 3,
722 ap->yb + ap->ys * row + ap->ys / 2);
725 XDrawPoint(display, window, MI_GC(mi),
726 ap->xb + ap->xs * (col + 1) - 4,
727 ap->yb + ap->ys * row + 1);
728 XDrawPoint(display, window, MI_GC(mi),
729 ap->xb + ap->xs * (col + 1) - 3,
730 ap->yb + ap->ys * row + 2);
733 XDrawPoint(display, window, MI_GC(mi),
734 ap->xb + ap->xs * col + ap->xs / 2 - 2,
735 ap->yb + ap->ys * row + 1);
736 XDrawPoint(display, window, MI_GC(mi),
737 ap->xb + ap->xs * col + ap->xs / 2,
738 ap->yb + ap->ys * row + 1);
741 XDrawPoint(display, window, MI_GC(mi),
742 ap->xb + ap->xs * col + 2,
743 ap->yb + ap->ys * row + 1);
744 XDrawPoint(display, window, MI_GC(mi),
745 ap->xb + ap->xs * col + 1,
746 ap->yb + ap->ys * row + 2);
749 XDrawPoint(display, window, MI_GC(mi),
750 ap->xb + ap->xs * col + 1,
751 ap->yb + ap->ys * row + ap->ys / 2 - 2);
752 XDrawPoint(display, window, MI_GC(mi),
753 ap->xb + ap->xs * col + 1,
754 ap->yb + ap->ys * row + ap->ys / 2);
757 XDrawPoint(display, window, MI_GC(mi),
758 ap->xb + ap->xs * col + 2,
759 ap->yb + ap->ys * (row + 1) - 3);
760 XDrawPoint(display, window, MI_GC(mi),
761 ap->xb + ap->xs * col + 1,
762 ap->yb + ap->ys * (row + 1) - 4);
765 XDrawPoint(display, window, MI_GC(mi),
766 ap->xb + ap->xs * col + ap->xs / 2 - 2,
767 ap->yb + ap->ys * (row + 1) - 3);
768 XDrawPoint(display, window, MI_GC(mi),
769 ap->xb + ap->xs * col + ap->xs / 2,
770 ap->yb + ap->ys * (row + 1) - 3);
773 XDrawPoint(display, window, MI_GC(mi),
774 ap->xb + ap->xs * (col + 1) - 4,
775 ap->yb + ap->ys * (row + 1) - 3);
776 XDrawPoint(display, window, MI_GC(mi),
777 ap->xb + ap->xs * (col + 1) - 3,
778 ap->yb + ap->ys * (row + 1) - 4);
781 (void) fprintf(stderr, "wrong eyes direction %d for ant eyes\n", direction);
784 int orient = (col + row) % 2; /* O left 1 right */
788 if (!(ap->xs > 6 && ap->ys > 6))
790 tri.x = ap->xb + col * ap->xs;
791 tri.y = ap->yb + row * ap->ys;
793 tri.x += (ap->xs / 6 - 1);
795 tri.x -= (ap->xs / 6 - 1);
796 ang = direction * ap->neighbors / ANGLES;
797 /* approx... does not work that well for even numbers */
800 ap->neighbors == 9 ||
802 ap->neighbors == 12) {
803 #ifdef UNDER_CONSTRUCTION
804 /* Not sure why this does not work */
805 ang = ((ang + ap->neighbors / 6) / (ap->neighbors / 3)) % 3;
810 for (side = 0; side < 3; side++) {
812 tri.x += ap->shape.triangle[orient][side].x / 3;
813 tri.y += ap->shape.triangle[orient][side].y / 3;
815 /* Either you have the eyes in back or one eye in front */
818 XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
820 if (side == (ang + 2) % 3)
821 XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
822 if (side == (ang + 1) % 3)
823 XDrawPoint(display, window, MI_GC(mi), tri.x, tri.y);
835 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
836 int row, col, mrow = 0;
838 for (row = 0; row < ap->nrows; ++row) {
839 for (col = 0; col < ap->ncols; ++col) {
840 ap->old[col + mrow] = (unsigned char) NRAND((int) ap->ncolors);
841 drawcell(mi, col, row, ap->old[col + mrow]);
850 fromTableDirection(unsigned char dir, int local_neighbors)
852 /* Crafted to work for odd number of neighbors */
857 return (ANGLES / local_neighbors);
859 return (2 * ANGLES / local_neighbors);
861 return ((local_neighbors / 2) * ANGLES / local_neighbors);
863 return (ANGLES - 2 * ANGLES / local_neighbors);
865 return (ANGLES - ANGLES / local_neighbors);
869 return (ANGLES + ANGLES / local_neighbors);
871 return (ANGLES + 2 * ANGLES / local_neighbors);
873 return (ANGLES + (local_neighbors / 2) * ANGLES / local_neighbors);
875 return (2 * ANGLES - 2 * ANGLES / local_neighbors);
877 return (2 * ANGLES - ANGLES / local_neighbors);
879 (void) fprintf(stderr, "wrong direction %d from table\n", dir);
885 getTable(ModeInfo * mi, int i)
887 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
889 unsigned char *patptr;
891 patptr = &tables[i][0];
892 ap->ncolors = *patptr++;
893 ap->nstates = *patptr++;
894 total = ap->ncolors * ap->nstates;
895 if (MI_IS_VERBOSE(mi))
896 (void) fprintf(stdout,
897 "ants %d, neighbors %d, table number %d, colors %d, states %d\n",
898 ap->n, ap->neighbors, i, ap->ncolors, ap->nstates);
899 for (j = 0; j < total; j++) {
900 ap->machine[j].color = *patptr++;
901 if (ap->sharpturn && ap->neighbors > 4) {
932 ap->machine[j].direction = fromTableDirection(k, ap->neighbors);
934 ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors);
936 ap->machine[j].next = *patptr++;
942 getTurk(ModeInfo * mi, int i)
944 antfarmstruct *ap = &antfarms[MI_SCREEN(mi)];
945 int power2, j, number, total;
947 /* To force a number, say <i = 2;> has i + 2 (or 4) binary digits */
948 power2 = 1 << (i + 1);
949 /* Do not want numbers which in binary are all 1's. */
950 number = NRAND(power2 - 1) + power2;
951 /* To force a particular number, say <number = 10;> */
955 total = ap->ncolors * ap->nstates;
956 for (j = 0; j < total; j++) {
957 ap->machine[j].color = (j + 1) % total;
958 if (ap->sharpturn && ap->neighbors > 4) {
959 ap->machine[j].direction = (power2 & number) ?
960 fromTableDirection(THRS, ap->neighbors) :
961 fromTableDirection(THLS, ap->neighbors);
963 ap->machine[j].direction = (power2 & number) ?
964 fromTableDirection(TRS, ap->neighbors) :
965 fromTableDirection(TLS, ap->neighbors);
967 ap->machine[j].next = 0;
970 ap->truchet = (ap->truchet && ap->xs > 2 && ap->ys > 2 &&
971 (ap->neighbors == 3 || ap->neighbors == 4 || ap->neighbors == 6));
972 if (MI_IS_VERBOSE(mi))
973 (void) fprintf(stdout,
974 "ants %d, neighbors %d, Turk's number %d, colors %d\n",
975 ap->n, ap->neighbors, number, ap->ncolors);
979 free_ant(Display *display, antfarmstruct *ap)
984 if (ap->stippledGC != None) {
985 XFreeGC(display, ap->stippledGC);
986 ap->stippledGC = None;
988 #endif /* DO_STIPPLE */
989 for (shade = 0; shade < ap->init_bits; shade++) {
990 XFreePixmap(display, ap->pixmaps[shade]);
993 if (ap->tape != NULL) {
994 (void) free((void *) ap->tape);
995 ap->tape = (unsigned char *) NULL;
997 if (ap->ants != NULL) {
998 (void) free((void *) ap->ants);
999 ap->ants = (antstruct *) NULL;
1001 if (ap->truchet_state != NULL) {
1002 (void) free((void *) ap->truchet_state);
1003 ap->truchet_state = (unsigned char *) NULL;
1008 init_ant(ModeInfo * mi)
1010 Display *display = MI_DISPLAY(mi);
1011 int size = MI_SIZE(mi);
1016 if (antfarms == NULL) {
1017 if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi),
1018 sizeof (antfarmstruct))) == NULL)
1021 ap = &antfarms[MI_SCREEN(mi)];
1025 if (MI_NPIXELS(mi) <= 2) {
1026 Window window = MI_WINDOW(mi);
1027 if (ap->stippledGC == None) {
1030 gcv.fill_style = FillOpaqueStippled;
1031 if ((ap->stippledGC = XCreateGC(display, window,
1034 free_ant(display, ap);
1038 if (ap->init_bits == 0) {
1039 for (i = 1; i < NUMSTIPPLES; i++) {
1040 ANTBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
1044 #endif /* DO_STIPPLE */
1046 ap->n = MI_COUNT(mi);
1047 if (ap->n < -MINANTS) {
1048 /* if ap->n is random ... the size can change */
1049 if (ap->ants != NULL) {
1050 (void) free((void *) ap->ants);
1051 ap->ants = (antstruct *) NULL;
1053 ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS;
1054 } else if (ap->n < MINANTS)
1057 ap->width = MI_WIDTH(mi);
1058 ap->height = MI_HEIGHT(mi);
1060 for (i = 0; i < NEIGHBORKINDS; i++) {
1061 if (neighbors == plots[i]) {
1062 ap->neighbors = plots[i];
1065 if (i == NEIGHBORKINDS - 1) {
1067 /* Make above 6 rare */
1068 ap->neighbors = plots[NRAND(NEIGHBORKINDS)];
1070 ap->neighbors = plots[NRAND(GOODNEIGHBORKINDS)];
1076 if (ap->neighbors == 6) {
1083 if (size < -MINSIZE) {
1084 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1085 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1086 if (ap->ys < MINRANDOMSIZE)
1087 ap->ys = MIN(MINRANDOMSIZE,
1088 MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1089 } else if (size < MINSIZE) {
1091 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1095 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1098 nccols = MAX(ap->width / ap->xs - 2, 2);
1099 ncrows = MAX(ap->height / ap->ys - 1, 4);
1100 ap->ncols = nccols / 2;
1101 ap->nrows = 2 * (ncrows / 4);
1102 ap->xb = (ap->width - ap->xs * nccols) / 2 + ap->xs / 2;
1103 ap->yb = (ap->height - ap->ys * (ncrows / 2) * 2) / 2 + ap->ys - 2;
1104 for (i = 0; i < 6; i++) {
1105 ap->shape.hexagon[i].x = (ap->xs - 1) * hexagonUnit[i].x;
1106 ap->shape.hexagon[i].y = ((ap->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
1108 /* Avoid array bounds read of hexagonUnit */
1109 ap->shape.hexagon[6].x = 0;
1110 ap->shape.hexagon[6].y = 0;
1111 } else if (ap->neighbors == 4 || ap->neighbors == 8) {
1112 if (size < -MINSIZE) {
1113 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1114 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1115 if (ap->ys < MINRANDOMSIZE)
1116 ap->ys = MIN(MINRANDOMSIZE,
1117 MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1118 } else if (size < MINSIZE) {
1120 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1124 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1127 ap->ncols = MAX(ap->width / ap->xs, 2);
1128 ap->nrows = MAX(ap->height / ap->ys, 2);
1129 ap->xb = (ap->width - ap->xs * ap->ncols) / 2;
1130 ap->yb = (ap->height - ap->ys * ap->nrows) / 2;
1138 if (size < -MINSIZE) {
1139 ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1140 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1141 if (ap->ys < MINRANDOMSIZE)
1142 ap->ys = MIN(MINRANDOMSIZE,
1143 MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE));
1144 } else if (size < MINSIZE) {
1146 ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE);
1150 ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) /
1152 ap->xs = (int) (1.52 * ap->ys);
1153 ap->ncols = (MAX(ap->width / ap->xs - 1, 2) / 2) * 2;
1154 ap->nrows = (MAX(ap->height / ap->ys - 1, 2) / 2) * 2;
1155 ap->xb = (ap->width - ap->xs * ap->ncols) / 2 + ap->xs / 2;
1156 ap->yb = (ap->height - ap->ys * ap->nrows) / 2 + ap->ys;
1157 for (orient = 0; orient < 2; orient++) {
1158 for (i = 0; i < 3; i++) {
1159 ap->shape.triangle[orient][i].x =
1160 (ap->xs - 2) * triangleUnit[orient][i].x;
1161 ap->shape.triangle[orient][i].y =
1162 (ap->ys - 2) * triangleUnit[orient][i].y;
1164 /* Avoid array bounds read of triangleUnit */
1165 ap->shape.triangle[orient][3].x = 0;
1166 ap->shape.triangle[orient][3].y = 0;
1170 XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinMiter);
1172 ap->painted = False;
1174 if (MI_IS_FULLRANDOM(mi)) {
1175 ap->truchet = (Bool) (LRAND() & 1);
1176 ap->eyes = (Bool) (LRAND() & 1);
1177 ap->sharpturn = (Bool) (LRAND() & 1);
1179 ap->truchet = truchet;
1181 ap->sharpturn = sharpturn;
1183 if (!NRAND(NUMSTIPPLES)) {
1184 getTable(mi, (int) (NRAND(NTABLES)));
1186 getTurk(mi, (int) (NRAND(NUMSTIPPLES - 1)));
1187 if (MI_NPIXELS(mi) > 2)
1188 for (i = 0; i < (int) ap->ncolors - 1; i++)
1189 ap->colors[i] = (unsigned char) (NRAND(MI_NPIXELS(mi)) +
1190 i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1));
1191 if (ap->ants == NULL) {
1192 if ((ap->ants = (antstruct *) malloc(ap->n * sizeof (antstruct))) ==
1194 free_ant(display, ap);
1198 if (ap->tape != NULL)
1199 (void) free((void *) ap->tape);
1200 if ((ap->tape = (unsigned char *) calloc(ap->ncols * ap->nrows,
1201 sizeof (unsigned char))) == NULL) {
1202 free_ant(display, ap);
1205 if (ap->truchet_state != NULL)
1206 (void) free((void *) ap->truchet_state);
1207 if ((ap->truchet_state = (unsigned char *) calloc(ap->ncols * ap->nrows,
1208 sizeof (unsigned char))) == NULL) {
1209 free_ant(display, ap);
1213 row = ap->nrows / 2;
1214 col = ap->ncols / 2;
1215 if (col > 0 && ((ap->neighbors % 2) || ap->neighbors == 12) && (LRAND() & 1))
1217 dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors;
1220 if (ap->neighbors == 9 && !((col + row) & 1))
1221 dir = (dir + ANGLES - ANGLES / (ap->neighbors * 2)) % ANGLES;
1223 /* Have them all start in the same spot, why not? */
1224 for (i = 0; i < ap->n; i++) {
1225 ap->ants[i].col = col;
1226 ap->ants[i].row = row;
1227 ap->ants[i].direction = dir;
1228 ap->ants[i].state = 0;
1230 draw_anant(mi, dir, col, row);
1234 draw_ant(ModeInfo * mi)
1237 statestruct *status;
1238 int i, state_pos, tape_pos;
1239 unsigned char color;
1240 short chg_dir, old_dir;
1243 if (antfarms == NULL)
1245 ap = &antfarms[MI_SCREEN(mi)];
1246 if (ap->ants == NULL)
1251 ap->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), ap->eraser);
1256 MI_IS_DRAWN(mi) = True;
1258 for (i = 0; i < ap->n; i++) {
1259 anant = &ap->ants[i];
1260 tape_pos = anant->col + anant->row * ap->ncols;
1261 color = ap->tape[tape_pos]; /* read tape */
1262 state_pos = color + anant->state * ap->ncolors;
1263 status = &(ap->machine[state_pos]);
1264 drawcell(mi, anant->col, anant->row, status->color);
1265 ap->tape[tape_pos] = status->color; /* write on tape */
1267 /* Find direction of Bees or Ants. */
1268 /* Translate relative direction to actual direction */
1269 old_dir = anant->direction;
1270 chg_dir = (2 * ANGLES - status->direction) % ANGLES;
1271 anant->direction = (chg_dir + old_dir) % ANGLES;
1275 if (ap->neighbors == 6) {
1276 if (ap->sharpturn) {
1277 a = (((ANGLES + anant->direction - old_dir) % ANGLES) == 240);
1278 /* should be some way of getting rid of the init_dir dependency... */
1279 b = !(ap->init_dir % 120);
1280 a = ((a && !b) || (b && !a));
1281 drawtruchet(mi, anant->col, anant->row, status->color, a);
1283 a = (old_dir / 60) % 3;
1284 b = (anant->direction / 60) % 3;
1285 a = (a + b + 1) % 3;
1286 drawtruchet(mi, anant->col, anant->row, status->color, a);
1288 } else if (ap->neighbors == 4) {
1290 b = anant->direction / 180;
1291 a = ((a && !b) || (b && !a));
1292 drawtruchet(mi, anant->col, anant->row, status->color, a);
1293 } else if (ap->neighbors == 3) {
1295 a = (2 + anant->direction / 120) % 3;
1297 a = (1 + anant->direction / 120) % 3;
1298 drawtruchet(mi, anant->col, anant->row, status->color, a);
1300 ap->truchet_state[tape_pos] = a + 1;
1302 anant->state = status->next;
1304 /* Allow step first and turn */
1305 old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir);
1307 (void) printf("old_dir %d, col %d, row %d", old_dir, anant->col, anant->row);
1309 position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row));
1311 (void) printf(", ncol %d, nrow %d\n", anant->col, anant->row);
1313 draw_anant(mi, anant->direction, anant->col, anant->row);
1315 if (++ap->generation > MI_CYCLES(mi)) {
1317 ap->eraser = erase_window (MI_DISPLAY(mi), MI_WINDOW(mi), ap->eraser);
1321 if (ap->redrawing) {
1322 for (i = 0; i < REDRAWSTEP; i++) {
1323 if (ap->tape[ap->redrawpos] ||
1324 (ap->truchet && ap->truchet_state[ap->redrawpos])) {
1325 drawcell(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1326 ap->tape[ap->redrawpos]);
1328 drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols,
1329 ap->tape[ap->redrawpos],
1330 ap->truchet_state[ap->redrawpos] - 1);
1332 if (++(ap->redrawpos) >= ap->ncols * ap->nrows) {
1341 release_ant(ModeInfo * mi)
1343 if (antfarms != NULL) {
1346 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1347 free_ant(MI_DISPLAY(mi), &antfarms[screen]);
1348 (void) free((void *) antfarms);
1349 antfarms = (antfarmstruct *) NULL;
1354 refresh_ant(ModeInfo * mi)
1358 if (antfarms == NULL)
1360 ap = &antfarms[MI_SCREEN(mi)];
1369 XSCREENSAVER_MODULE ("Ant", ant)
1371 #endif /* MODE_ant */