X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fant.c;fp=hacks%2Fant.c;h=db76bfd3cead828c6ab22d9d7abaf6d6a87acfc1;hb=df7adbee81405e2849728a24b498ad2117784b1f;hp=0000000000000000000000000000000000000000;hpb=41fae2ad67bc37e31c4d967bae81e4f3f50fa55a;p=xscreensaver diff --git a/hacks/ant.c b/hacks/ant.c new file mode 100644 index 00000000..db76bfd3 --- /dev/null +++ b/hacks/ant.c @@ -0,0 +1,1176 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/*- + * ant --- Chris Langton's generalized turing machine ants (also known + * as Greg Turk's turmites) whose tape is the screen + */ + +#if !defined( lint ) && !defined( SABER ) +static const char sccsid[] = "@(#)ant.c 4.11 98/06/18 xlockmore"; + +#endif + +/*- + * Copyright (c) 1995 by David Bagley. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation. + * + * This file is provided AS IS with no warranties of any kind. The author + * shall have no liability with respect to the infringement of copyrights, + * trade secrets or any patents by this file or any part thereof. In no + * event will the author be liable for any lost revenue or profits or + * other special, indirect and consequential damages. + * + * Revision History: + * 10-May-97: Compatible with xscreensaver + * 16-Apr-97: -neighbors 3 and 8 added + * 01-Jan-97: Updated ant.c to handle more kinds of ants. Thanks to + * J Austin David . Check it out in + * java at http://havoc.gtf.gatech.edu/austin He thought up the + * new Ladder ant. + * 04-Apr-96: -neighbors 6 runtime-time option added for hexagonal ants + * (bees), coded from an idea of Jim Propp's in Science News, + * Oct 28, 1995 VOL. 148 page 287 + * 20-Sep-95: Memory leak in ant fixed. Now random colors. + * 05-Sep-95: Coded from A.K. Dewdney's "Computer Recreations", Scientific + * American Magazine" Sep 1989 pp 180-183, Mar 1990 p 121 + * Also used Ian Stewart's Mathematical Recreations, Scientific + * American Jul 1994 pp 104-107 + * also used demon.c and life.c as a guide. + */ + +/*- + Species Grid Number of Neigbors + ------- ---- ------------------ + Ants Square 4 (or 8) + Bees Hexagon 6 + Bees Triangle 3 (or 9, 12) + + Neighbors 6 and neighbors 3 produce the same Turk ants. +*/ + +#ifdef STANDALONE +# define PROGCLASS "Ant" +# define HACK_INIT init_ant +# define HACK_DRAW draw_ant +# define ant_opts xlockmore_opts +# define DEFAULTS "*delay: 1000 \n" \ + "*count: -3 \n" \ + "*cycles: 40000 \n" \ + "*size: -12 \n" \ + "*ncolors: 64 \n" \ + "*neighbors: 0 \n" \ + "*sharpturn: False \n" +# include "xlockmore.h" /* in xscreensaver distribution */ +# include "erase.h" +#else /* STANDALONE */ +# include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#include "automata.h" + +/*- + * neighbors of 0 randomizes it between 3, 4 and 6. + * 8, 9 12 are available also but not recommended. + */ + +#ifdef STANDALONE +static int neighbors; +#else +extern int neighbors; +#endif /* !STANDALONE */ + +#define DEF_TRUCHET "False" +#define DEF_SHARPTURN "False" +#define DEF_NEIGHBORS "0" + +static Bool truchet; +static Bool sharpturn; + +static XrmOptionDescRec opts[] = +{ + {"-truchet", ".ant.truchet", XrmoptionNoArg, (caddr_t) "on"}, + {"+truchet", ".ant.truchet", XrmoptionNoArg, (caddr_t) "off"}, + {"-sharpturn", ".ant.sharpturn", XrmoptionNoArg, (caddr_t) "on"}, + {"+sharpturn", ".ant.sharpturn", XrmoptionNoArg, (caddr_t) "off"}, + +#ifdef STANDALONE + {"-neighbors", ".ant.neighbors", XrmoptionSepArg, (caddr_t) 0}, + {"+neighbors", ".ant.neighbors", XrmoptionSepArg, (caddr_t) 0} +#endif /* STANDALONE */ + +}; +static argtype vars[] = +{ + {(caddr_t *) & truchet, "truchet", "Truchet", DEF_TRUCHET, t_Bool}, + {(caddr_t *) & sharpturn, "sharpturn", "SharpTurn", DEF_SHARPTURN, t_Bool}, +#ifdef STANDALONE + {(caddr_t *) & neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int} +#endif /* STANDALONE */ +}; +static OptionStruct desc[] = +{ + {"-/+truchet", "turn on/off Truchet lines"}, + {"-/+sharpturn", "turn on/off sharp turns (6 or 12 neighbors only)"} +}; + +ModeSpecOpt ant_opts = +{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; + +#ifdef USE_MODULES +ModStruct ant_description = +{"ant", "init_ant", "draw_ant", "release_ant", + "refresh_ant", "init_ant", NULL, &ant_opts, + 1000, -3, 40000, -12, 64, 1.0, "", + "Shows Langton's and Turk's generalized ants", 0, NULL}; + +#endif + +#define ANTBITS(n,w,h)\ + ap->pixmaps[ap->init_bits++]=\ + XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1) + +/* If you change the table you may have to change the following 2 constants */ +#define STATES 2 +#define MINANTS 1 +#define REDRAWSTEP 2000 /* How much tape to draw per cycle */ +#define MINGRIDSIZE 24 +#define MINSIZE 1 +#define MINRANDOMSIZE 5 +#define ANGLES 360 + + +typedef struct { + unsigned char color; + short direction; + unsigned char next; +} statestruct; + +typedef struct { + int col, row; + short direction; + unsigned char state; +} antstruct; + +typedef struct { + Bool painted; + int neighbors; + int generation; + int xs, ys; + int xb, yb; + int nrows, ncols; + int width, height; + unsigned char ncolors, nstates; + int n; + int redrawing, redrawpos; + int truchet; /* Only for Turk modes */ + int sharpturn; /* Only for even neighbors > 4 (i.e. 6 and 12) */ + statestruct machine[NUMSTIPPLES * STATES]; + unsigned char *tape; + unsigned char *truchet_state; + antstruct *ants; + int init_bits; + unsigned char colors[NUMSTIPPLES - 1]; + GC stippledGC; + Pixmap pixmaps[NUMSTIPPLES - 1]; + union { + XPoint hexagon[7]; /* Need more than 6 for truchet */ + XPoint triangle[2][4]; /* Need more than 3 for truchet */ + } shape; +} antfarmstruct; + +static char plots[] = +{3, +#if 1 /* Without this... this mode is misnamed... */ + 4, +#endif + 6}; /* Neighborhoods, 8 just makes a mess */ + +#define NEIGHBORKINDS (long) (sizeof plots / sizeof *plots) + +/* Relative ant moves */ +#define FS 0 /* Step */ +#define TRS 1 /* Turn right, then step */ +#define THRS 2 /* Turn hard right, then step */ +#define TBS 3 /* Turn back, then step */ +#define THLS 4 /* Turn hard left, then step */ +#define TLS 5 /* Turn left, then step */ +#define SF 6 /* Step */ +#define STR 7 /* Step then turn right */ +#define STHR 8 /* Step then turn hard right */ +#define STB 9 /* Step then turn back */ +#define STHL 10 /* Step then turn hard left */ +#define STL 11 /* Step then turn left */ + +static antfarmstruct *antfarms = NULL; + +/* LANGTON'S ANT (10) Chaotic after 500, Builder after 10,000 (104p) */ +/* TURK'S 100 ANT Always chaotic?, tested past 150,000,000 */ +/* TURK'S 101 ANT Always chaotic? */ +/* TURK'S 110 ANT Builder at 150 (18p) */ +/* TURK'S 1000 ANT Always chaotic? */ +/* TURK'S 1100 SYMMETRIC ANT all even run 1's and 0's are symmetric */ +/* other examples 1001, 110011, 110000, 1001101 */ +/* TURK'S 1101 ANT Builder after 250,000 (388p) */ +/* Once saw a chess horse type builder (i.e. non-45 degree builder) */ + +/* BEE ONLY */ +/* All alternating 10 appear symmetric, no proof (i.e. 10, 1010, etc) */ +/* Even runs of 0's and 1's are also symmetric */ +/* I have seen Hexagonal builders but they are more rare. */ + +static unsigned char tables[][3 * NUMSTIPPLES * STATES + 2] = +{ +#if 0 + /* Here just so you can figure out notation */ + { /* Langton's ant */ + 2, 1, + 1, TLS, 0, 0, TRS, 0 + }, +#else + /* First 2 numbers are the size (ncolors, nstates) */ + { /* LADDER BUILDER */ + 4, 1, + 1, STR, 0, 2, STL, 0, 3, TRS, 0, 0, TLS, 0 + }, + { /* SPIRALING PATTERN */ + 2, 2, + 1, TLS, 0, 0, FS, 1, + 1, TRS, 0, 1, TRS, 0 + }, + { /* SQUARE (HEXAGON) BUILDER */ + 2, 2, + 1, TLS, 0, 0, FS, 1, + 0, TRS, 0, 1, TRS, 0 + }, +#endif +}; + +#define NTABLES (sizeof tables / sizeof tables[0]) + +static void +position_of_neighbor(antfarmstruct * ap, int dir, int *pcol, int *prow) +{ + int col = *pcol, row = *prow; + + if (ap->neighbors == 6) { + switch (dir) { + case 0: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + break; + case 60: + if (!(row & 1)) + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 120: + if (row & 1) + col = (!col) ? ap->ncols - 1 : col - 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 180: + col = (!col) ? ap->ncols - 1 : col - 1; + break; + case 240: + if (row & 1) + col = (!col) ? ap->ncols - 1 : col - 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 300: + if (!(row & 1)) + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + default: + (void) fprintf(stderr, "wrong direction %d\n", dir); + } + } else if (ap->neighbors == 4 || ap->neighbors == 8) { + switch (dir) { + case 0: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + break; + case 45: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 90: + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 135: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 180: + col = (!col) ? ap->ncols - 1 : col - 1; + break; + case 225: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 270: + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 315: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + default: + (void) fprintf(stderr, "wrong direction %d\n", dir); + } + } else { /* TRI */ + if ((col + row) % 2) { /* right */ + switch (dir) { + case 0: + col = (!col) ? ap->ncols - 1 : col - 1; + break; + case 30: + case 40: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 60: + col = (!col) ? ap->ncols - 1 : col - 1; + if (!row) + row = ap->nrows - 2; + else if (!(row - 1)) + row = ap->nrows - 1; + else + row = row - 2; + break; + case 80: + case 90: + if (!row) + row = ap->nrows - 2; + else if (!(row - 1)) + row = ap->nrows - 1; + else + row = row - 2; + break; + case 120: + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 150: + case 160: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 180: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + break; + case 200: + case 210: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 240: + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 270: + case 280: + if (row + 1 == ap->nrows) + row = 1; + else if (row + 2 == ap->nrows) + row = 0; + else + row = row + 2; + break; + case 300: + col = (!col) ? ap->ncols - 1 : col - 1; + if (row + 1 == ap->nrows) + row = 1; + else if (row + 2 == ap->nrows) + row = 0; + else + row = row + 2; + break; + case 320: + case 330: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + default: + (void) fprintf(stderr, "wrong direction %d\n", dir); + } + } else { /* left */ + switch (dir) { + case 0: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + break; + case 30: + case 40: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 60: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + if (row + 1 == ap->nrows) + row = 1; + else if (row + 2 == ap->nrows) + row = 0; + else + row = row + 2; + break; + case 80: + case 90: + if (row + 1 == ap->nrows) + row = 1; + else if (row + 2 == ap->nrows) + row = 0; + else + row = row + 2; + break; + case 120: + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 150: + case 160: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (row + 1 == ap->nrows) ? 0 : row + 1; + break; + case 180: + col = (!col) ? ap->ncols - 1 : col - 1; + break; + case 200: + case 210: + col = (!col) ? ap->ncols - 1 : col - 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 240: + row = (!row) ? ap->nrows - 1 : row - 1; + break; + case 270: + case 280: + if (!row) + row = ap->nrows - 2; + else if (row == 1) + row = ap->nrows - 1; + else + row = row - 2; + break; + case 300: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + if (!row) + row = ap->nrows - 2; + else if (row == 1) + row = ap->nrows - 1; + else + row = row - 2; + break; + case 320: + case 330: + col = (col + 1 == ap->ncols) ? 0 : col + 1; + row = (!row) ? ap->nrows - 1 : row - 1; + break; + default: + (void) fprintf(stderr, "wrong direction %d\n", dir); + } + } + } + *pcol = col; + *prow = row; +} + +static void +fillcell(ModeInfo * mi, GC gc, int col, int row) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + + if (ap->neighbors == 6) { + int ccol = 2 * col + !(row & 1), crow = 2 * row; + + ap->shape.hexagon[0].x = ap->xb + ccol * ap->xs; + ap->shape.hexagon[0].y = ap->yb + crow * ap->ys; + if (ap->xs == 1 && ap->ys == 1) + XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ap->shape.hexagon[0].x, ap->shape.hexagon[0].y, 1, 1); + else + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ap->shape.hexagon, 6, Convex, CoordModePrevious); + } else if (ap->neighbors == 4 || ap->neighbors == 8) { + XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ap->xb + ap->xs * col, ap->yb + ap->ys * row, + ap->xs - (ap->xs > 3), ap->ys - (ap->ys > 3)); + } else { /* TRI */ + int orient = (col + row) % 2; /* O left 1 right */ + + ap->shape.triangle[orient][0].x = ap->xb + col * ap->xs; + ap->shape.triangle[orient][0].y = ap->yb + row * ap->ys; + if (ap->xs <= 3 || ap->ys <= 3) + XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ((orient) ? -1 : 1) + ap->shape.triangle[orient][0].x, + ap->shape.triangle[orient][0].y, 1, 1); + else { + if (orient) + ap->shape.triangle[orient][0].x += (ap->xs / 2 - 1); + else + ap->shape.triangle[orient][0].x -= (ap->xs / 2 - 1); + XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + ap->shape.triangle[orient], 3, Convex, CoordModePrevious); + } + } +} + +static void +truchetcell(ModeInfo * mi, int col, int row, int truchetstate) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + + if (ap->neighbors == 6) { + + int ccol = 2 * col + !(row & 1), crow = 2 * row; + int side; + int fudge = 7; /* fudge because the hexagons are not exact */ + XPoint hex, hex2; + + if (ap->sharpturn) { + hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs / 2.0) - 1; + hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys / 2.0) - 1; + for (side = 0; side < 6; side++) { + if (side > 0) { + hex.x += ap->shape.hexagon[side].x; + hex.y += ap->shape.hexagon[side].y; + } + if (truchetstate == side % 2) + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + hex.x, hex.y, ap->xs, ap->ys, + ((570 - (side * 60) + fudge) % 360) * 64, (120 - 2 * fudge) * 64); + } + } else { + + /* Very crude approx of Sqrt 3, so it will not cause drawing errors. */ + hex.x = ap->xb + ccol * ap->xs - (int) ((double) ap->xs * 1.6 / 2.0); + hex.y = ap->yb + crow * ap->ys - (int) ((double) ap->ys * 1.6 / 2.0); + for (side = 0; side < 6; side++) { + if (side > 0) { + hex.x += ap->shape.hexagon[side].x; + hex.y += ap->shape.hexagon[side].y; + } + hex2.x = hex.x + ap->shape.hexagon[side + 1].x / 2; + hex2.y = hex.y + ap->shape.hexagon[side + 1].y / 2; + if (truchetstate == side % 3) + /* Crude approx of 120 deg, so it will not cause drawing errors. */ + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + hex2.x, hex2.y, + (int) ((double) ap->xs * 1.5), (int) ((double) ap->ys * 1.5), + ((555 - (side * 60)) % 360) * 64, 90 * 64); + } + } + } else if (ap->neighbors == 4) { + if (truchetstate) { + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ap->xb + ap->xs * col - ap->xs / 2+ 1, + ap->yb + ap->ys * row + ap->ys / 2 - 1, + ap->xs - 2, ap->ys - 2, + 0 * 64, 90 * 64); + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ap->xb + ap->xs * col + ap->xs / 2 - 1, + ap->yb + ap->ys * row - ap->ys / 2 + 1, + ap->xs - 2, ap->ys - 2, + -90 * 64, -90 * 64); + } else { + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ap->xb + ap->xs * col - ap->xs / 2 + 1, + ap->yb + ap->ys * row - ap->ys / 2 + 1, + ap->xs - 2, ap->ys - 2, + 0 * 64, -90 * 64); + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + ap->xb + ap->xs * col + ap->xs / 2 - 1, + ap->yb + ap->ys * row + ap->ys / 2 - 1, + ap->xs - 2, ap->ys - 2, + 90 * 64, 90 * 64); + } + } else if (ap->neighbors == 3) { + int orient = (col + row) % 2; /* O left 1 right */ + int side, ang; + int fudge = 7; /* fudge because the triangles are not exact */ + XPoint tri; + + tri.x = ap->xb + col * ap->xs; + tri.y = ap->yb + row * ap->ys; + if (orient) { + tri.x += (ap->xs / 2 - 1); + } else { + tri.x -= (ap->xs / 2 - 1); + } + for (side = 0; side < 3; side++) { + if (side > 0) { + tri.x += ap->shape.triangle[orient][side].x; + tri.y += ap->shape.triangle[orient][side].y; + } + if (truchetstate == side % 3) { + if (orient) + ang = (510 - side * 120) % 360; /* Right */ + else + ang = (690 - side * 120) % 360; /* Left */ + XDrawArc(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), + tri.x - ap->xs / 2, tri.y - 3 * ap->ys / 4, + ap->xs, 3 * ap->ys / 2, + (ang + fudge) * 64, (60 - 2 * fudge) * 64); + } + } + } +} + +static void +drawcell(ModeInfo * mi, int col, int row, unsigned char color) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + GC gc; + + if (!color) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + gc = MI_GC(mi); + } else if (MI_NPIXELS(mi) > 2) { + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), + MI_PIXEL(mi, ap->colors[color - 1])); + gc = MI_GC(mi); + } else { + XGCValues gcv; + + gcv.stipple = ap->pixmaps[color - 1]; + gcv.foreground = MI_WHITE_PIXEL(mi); + gcv.background = MI_BLACK_PIXEL(mi); + XChangeGC(MI_DISPLAY(mi), ap->stippledGC, + GCStipple | GCForeground | GCBackground, &gcv); + gc = ap->stippledGC; + } + fillcell(mi, gc, col, row); +} + +static void +drawtruchet(ModeInfo * mi, int col, int row, + unsigned char color, unsigned char truchetstate) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + + if (!color) + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + else if (MI_NPIXELS(mi) > 2 || color > ap->ncolors / 2) + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi)); + else + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + truchetcell(mi, col, row, truchetstate); +} + +static void +draw_anant(ModeInfo * mi, int col, int row) +{ + XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi)); + fillcell(mi, MI_GC(mi), col, row); +#if 0 /* Can not see eyes */ + { + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + + if (ap->xs > 2 && ap->ys > 2) { /* Draw Eyes */ + + XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi)); + switch (direction) { + case 0: + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs - 1, ap->yb + 1); + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs - 1, ap->yb + ap->ys - 2); + break; + case 180: + XDrawPoint(display, window, MI_GC(mi), ap->xb, ap->yb + 1); + XDrawPoint(display, window, MI_GC(mi), ap->xb, ap->yb + ap->ys - 2); + break; + if (neighbors == 4) { + case 90: + XDrawPoint(display, window, MI_GC(mi), ap->xb + 1, ap->yb); + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs - 2, ap->yb); + break; + case 270: + XDrawPoint(display, window, MI_GC(mi), + ap->xb + 1, ap->yb + ap->ys - 1); + XDrawPoint(display, window, MI_GC(mi), + ap->xb + ap->xs - 2, ap->yb + ap->ys - 1); + break; + } /* else BEE */ + default: + } + } + } +#endif +} + +#if 0 +static void +RandomSoup(mi) + ModeInfo *mi; +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + int row, col, mrow = 0; + + for (row = 0; row < ap->nrows; ++row) { + for (col = 0; col < ap->ncols; ++col) { + ap->old[col + mrow] = (unsigned char) NRAND((int) ap->ncolors); + drawcell(mi, col, row, ap->old[col + mrow]); + } + mrow += ap->nrows; + } +} + +#endif + +static short +fromTableDirection(unsigned char dir, int neighbors) +{ + switch (dir) { + case FS: + return 0; + case TRS: + return (ANGLES / neighbors); + case THRS: + return (ANGLES / 2 - ANGLES / neighbors); + case TBS: + return (ANGLES / 2); + case THLS: + return (ANGLES / 2 + ANGLES / neighbors); + case TLS: + return (ANGLES - ANGLES / neighbors); + case SF: + return ANGLES; + case STR: + return (ANGLES + ANGLES / neighbors); + case STHR: + return (3 * ANGLES / 2 - ANGLES / neighbors); + case STB: + return (3 * ANGLES / 2); + case STHL: + return (3 * ANGLES / 2 + ANGLES / neighbors); + case STL: + return (2 * ANGLES - ANGLES / neighbors); + default: + (void) fprintf(stderr, "wrong direction %d\n", dir); + } + return -1; +} + +static void +getTable(ModeInfo * mi, int i) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + int j, total; + unsigned char *patptr; + + patptr = &tables[i][0]; + ap->ncolors = *patptr++; + ap->nstates = *patptr++; + total = ap->ncolors * ap->nstates; + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, + "ants %d, neighbors %d, table number %d, colors %d, states %d\n", + ap->n, ap->neighbors, i, ap->ncolors, ap->nstates); + for (j = 0; j < total; j++) { + ap->machine[j].color = *patptr++; + if (ap->sharpturn && ap->neighbors > 4 && !(ap->neighbors % 2)) { + int k = *patptr++; + + switch (k) { + case TRS: + k = THRS; + break; + case THRS: + k = TRS; + break; + case THLS: + k = TLS; + break; + case TLS: + k = THLS; + break; + case STR: + k = STHR; + break; + case STHR: + k = STR; + break; + case STHL: + k = STL; + break; + case STL: + k = STHL; + break; + default: + break; + } + ap->machine[j].direction = fromTableDirection(k, ap->neighbors); + } else { + ap->machine[j].direction = fromTableDirection(*patptr++, ap->neighbors); + } + ap->machine[j].next = *patptr++; + } + ap->truchet = False; +} + +static void +getTurk(ModeInfo * mi, int i) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + int power2, j, number, total; + + /* To force a number, say has i + 2 (or 4) digits in binary */ + power2 = 1 << (i + 1); + /* Dont want numbers which in binary are all 1's. */ + number = NRAND(power2 - 1) + power2; + /* To force a particular number, say */ + + ap->ncolors = i + 2; + ap->nstates = 1; + total = ap->ncolors * ap->nstates; + for (j = 0; j < total; j++) { + ap->machine[j].color = (j + 1) % total; + if (ap->sharpturn && ap->neighbors > 4 && !(ap->neighbors % 2)) { + ap->machine[j].direction = (power2 & number) ? + fromTableDirection(THRS, ap->neighbors) : + fromTableDirection(THLS, ap->neighbors); + } else { + ap->machine[j].direction = (power2 & number) ? + fromTableDirection(TRS, ap->neighbors) : + fromTableDirection(TLS, ap->neighbors); + } + ap->machine[j].next = 0; + power2 >>= 1; + } + ap->truchet = (ap->truchet && ap->xs > 2 && ap->ys > 2 && + (ap->neighbors == 3 || ap->neighbors == 4 || ap->neighbors == 6)); + if (MI_IS_VERBOSE(mi)) + (void) fprintf(stdout, + "ants %d, neighbors %d, Turk's number %d, colors %d\n", + ap->n, ap->neighbors, number, ap->ncolors); +} + +void +init_ant(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + int size = MI_SIZE(mi); + antfarmstruct *ap; + int col, row, dir; + long i; + + /* jwz sez: small sizes look like crap */ + if (size < 0) + size = NRAND(-size)+1; + if (size < 5) + size += 5; + + if (antfarms == NULL) { + if ((antfarms = (antfarmstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (antfarmstruct))) == NULL) + return; + } + ap = &antfarms[MI_SCREEN(mi)]; + ap->redrawing = 0; + if (MI_NPIXELS(mi) <= 2) { + if (ap->stippledGC == None) { + XGCValues gcv; + + gcv.fill_style = FillOpaqueStippled; + ap->stippledGC = XCreateGC(display, window, GCFillStyle, &gcv); + } + if (ap->init_bits == 0) { + for (i = 1; i < NUMSTIPPLES; i++) + ANTBITS(stipples[i], STIPPLESIZE, STIPPLESIZE); + } + } + ap->generation = 0; + ap->n = MI_COUNT(mi); + if (ap->n < -MINANTS) { + /* if ap->n is random ... the size can change */ + if (ap->ants != NULL) { + (void) free((void *) ap->ants); + ap->ants = NULL; + } + ap->n = NRAND(-ap->n - MINANTS + 1) + MINANTS; + } else if (ap->n < MINANTS) + ap->n = MINANTS; + + ap->width = MI_WIDTH(mi); + ap->height = MI_HEIGHT(mi); + + if (neighbors == 8 || neighbors == 9 || neighbors == 12) + ap->neighbors = neighbors; /* Discourage but not deny use... */ + else + for (i = 0; i < NEIGHBORKINDS; i++) { + if (neighbors == plots[i]) { + ap->neighbors = plots[i]; + break; + } + if (i == NEIGHBORKINDS - 1) { + ap->neighbors = plots[NRAND(NEIGHBORKINDS)]; + break; + } + } + + if (ap->neighbors == 6) { + int nccols, ncrows; + + if (ap->width < 2) + ap->width = 2; + if (ap->height < 4) + ap->height = 4; + if (size < -MINSIZE) { + ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + if (ap->ys < MINRANDOMSIZE) + ap->ys = MIN(MINRANDOMSIZE, + MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE)); + } else if (size < MINSIZE) { + if (!size) + ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE); + else + ap->ys = MINSIZE; + } else + ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)); + ap->xs = ap->ys; + nccols = MAX(ap->width / ap->xs - 2, 2); + ncrows = MAX(ap->height / ap->ys - 1, 2); + ap->ncols = nccols / 2; + ap->nrows = 2 * (ncrows / 4); + ap->xb = (ap->width - ap->xs * nccols) / 2 + ap->xs / 2; + ap->yb = (ap->height - ap->ys * (ncrows / 2) * 2) / 2 + ap->ys; + for (i = 0; i < 6; i++) { + ap->shape.hexagon[i].x = (ap->xs - 1) * hexagonUnit[i].x; + ap->shape.hexagon[i].y = ((ap->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3; + } + /* Avoid array bounds read of hexagonUnit */ + ap->shape.hexagon[6].x = 0; + ap->shape.hexagon[6].y = 0; + } else if (ap->neighbors == 4 || ap->neighbors == 8) { + if (size < -MINSIZE) { + ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + if (ap->ys < MINRANDOMSIZE) + ap->ys = MIN(MINRANDOMSIZE, + MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE)); + } else if (size < MINSIZE) { + if (!size) + ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE); + else + ap->ys = MINSIZE; + } else + ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)); + ap->xs = ap->ys; + ap->ncols = MAX(ap->width / ap->xs, 2); + ap->nrows = MAX(ap->height / ap->ys, 2); + ap->xb = (ap->width - ap->xs * ap->ncols) / 2; + ap->yb = (ap->height - ap->ys * ap->nrows) / 2; + } else { /* TRI */ + int orient; + + if (ap->width < 2) + ap->width = 2; + if (ap->height < 2) + ap->height = 2; + if (size < -MINSIZE) { + ap->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + if (ap->ys < MINRANDOMSIZE) + ap->ys = MIN(MINRANDOMSIZE, + MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE)); + } else if (size < MINSIZE) { + if (!size) + ap->ys = MAX(MINSIZE, MIN(ap->width, ap->height) / MINGRIDSIZE); + else + ap->ys = MINSIZE; + } else + ap->ys = MIN(size, MAX(MINSIZE, MIN(ap->width, ap->height) / + MINGRIDSIZE)); + ap->xs = (int) (1.52 * ap->ys); + ap->ncols = (MAX(ap->width / ap->xs - 1, 2) / 2) * 2; + ap->nrows = (MAX(ap->height / ap->ys - 1, 2) / 2) * 2; + ap->xb = (ap->width - ap->xs * ap->ncols) / 2 + ap->xs / 2; + ap->yb = (ap->height - ap->ys * ap->nrows) / 2 + ap->ys; + for (orient = 0; orient < 2; orient++) { + for (i = 0; i < 3; i++) { + ap->shape.triangle[orient][i].x = + (ap->xs - 2) * triangleUnit[orient][i].x; + ap->shape.triangle[orient][i].y = + (ap->ys - 2) * triangleUnit[orient][i].y; + } + /* Avoid array bounds read of triangleUnit */ + ap->shape.triangle[orient][3].x = 0; + ap->shape.triangle[orient][3].y = 0; + } + } + + XSetLineAttributes(display, MI_GC(mi), 1, LineSolid, CapNotLast, JoinMiter); + MI_CLEARWINDOW(mi); + ap->painted = False; + + if (MI_IS_FULLRANDOM(mi)) { + ap->truchet = (Bool) (LRAND() & 1); + ap->sharpturn = (Bool) (LRAND() & 1); + } else { + ap->truchet = truchet; + ap->sharpturn = sharpturn; + } + /* Exclude odd # of neighbors, stepping forward not defined */ + if (!NRAND(NUMSTIPPLES) && ((ap->neighbors + 1) % 2)) { + getTable(mi, (int) (NRAND(NTABLES))); + } else + getTurk(mi, (int) (NRAND(NUMSTIPPLES - 1))); + if (MI_NPIXELS(mi) > 2) + for (i = 0; i < (int) ap->ncolors - 1; i++) + ap->colors[i] = (unsigned char) (NRAND(MI_NPIXELS(mi)) + + i * MI_NPIXELS(mi)) / ((int) (ap->ncolors - 1)); + if (ap->ants == NULL) + ap->ants = (antstruct *) malloc(ap->n * sizeof (antstruct)); + if (ap->tape != NULL) + (void) free((void *) ap->tape); + ap->tape = (unsigned char *) + calloc(ap->ncols * ap->nrows, sizeof (unsigned char)); + + if (ap->truchet_state != NULL) + (void) free((void *) ap->truchet_state); + ap->truchet_state = (unsigned char *) + calloc(ap->ncols * ap->nrows, sizeof (unsigned char)); + + col = ap->ncols / 2; + row = ap->nrows / 2; + dir = NRAND(ap->neighbors) * ANGLES / ap->neighbors; + /* Have them all start in the same spot, why not? */ + for (i = 0; i < ap->n; i++) { + ap->ants[i].col = col; + ap->ants[i].row = row; + ap->ants[i].direction = dir; + ap->ants[i].state = 0; + } + draw_anant(mi, col, row); +} + +void +draw_ant(ModeInfo * mi) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + antstruct *anant; + statestruct *status; + int i, state_pos, tape_pos; + unsigned char color; + short chg_dir, old_dir; + + MI_IS_DRAWN(mi) = True; + + ap->painted = True; + for (i = 0; i < ap->n; i++) { + anant = &ap->ants[i]; + tape_pos = anant->col + anant->row * ap->ncols; + color = ap->tape[tape_pos]; /* read tape */ + state_pos = color + anant->state * ap->ncolors; + status = &(ap->machine[state_pos]); + drawcell(mi, anant->col, anant->row, status->color); + ap->tape[tape_pos] = status->color; /* write on tape */ + + /* Find direction of Bees or Ants. */ + /* Translate relative direction to actual direction */ + old_dir = anant->direction; + chg_dir = (2 * ANGLES - status->direction) % ANGLES; + anant->direction = (chg_dir + old_dir) % ANGLES; + if (ap->truchet) { + int a = 0, b; + + if (ap->neighbors == 6) { + if (ap->sharpturn) { + a = (chg_dir / 120 == 2); + drawtruchet(mi, anant->col, anant->row, status->color, a); + } else { + a = (old_dir / 60) % 3; + b = (anant->direction / 60) % 3; + a = (a + b + 1) % 3; + drawtruchet(mi, anant->col, anant->row, status->color, a); + } + } else if (ap->neighbors == 4) { + a = old_dir / 180; + b = anant->direction / 180; + a = ((a && !b) || (b && !a)); + drawtruchet(mi, anant->col, anant->row, status->color, a); + } else if (ap->neighbors == 3) { + if (chg_dir == 240) + a = (2 + anant->direction / 120) % 3; + else + a = (1 + anant->direction / 120) % 3; + drawtruchet(mi, anant->col, anant->row, status->color, a); + } + ap->truchet_state[tape_pos] = a + 1; + } + anant->state = status->next; + + /* If edge than wrap it */ + old_dir = ((status->direction < ANGLES) ? anant->direction : old_dir); + position_of_neighbor(ap, old_dir, &(anant->col), &(anant->row)); + draw_anant(mi, anant->col, anant->row); + } + if (++ap->generation > MI_CYCLES(mi)) { +#ifdef STANDALONE + erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi)); +#endif + init_ant(mi); + } + if (ap->redrawing) { + for (i = 0; i < REDRAWSTEP; i++) { + if (ap->tape[ap->redrawpos] || + (ap->truchet && ap->truchet_state[ap->redrawpos])) { + drawcell(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols, + ap->tape[ap->redrawpos]); + if (ap->truchet) + drawtruchet(mi, ap->redrawpos % ap->ncols, ap->redrawpos / ap->ncols, + ap->tape[ap->redrawpos], + ap->truchet_state[ap->redrawpos] - 1); + } + if (++(ap->redrawpos) >= ap->ncols * ap->nrows) { + ap->redrawing = 0; + break; + } + } + } +} + +void +release_ant(ModeInfo * mi) +{ + if (antfarms != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { + antfarmstruct *ap = &antfarms[screen]; + int shade; + + if (ap->stippledGC != None) { + XFreeGC(MI_DISPLAY(mi), ap->stippledGC); + } + for (shade = 0; shade < ap->init_bits; shade++) + XFreePixmap(MI_DISPLAY(mi), ap->pixmaps[shade]); + if (ap->tape != NULL) + (void) free((void *) ap->tape); + if (ap->ants != NULL) + (void) free((void *) ap->ants); + if (ap->truchet_state != NULL) + (void) free((void *) ap->truchet_state); + } + (void) free((void *) antfarms); + antfarms = NULL; + } +} + +void +refresh_ant(ModeInfo * mi) +{ + antfarmstruct *ap = &antfarms[MI_SCREEN(mi)]; + + if (ap->painted) { + MI_CLEARWINDOW(mi); + ap->redrawing = 1; + ap->redrawpos = 0; + } +}