/* The Ant Automaton is based on an article in Scientific American, July 1994. * The original Fractint implementation was by Tim Wegner in Fractint 19.0. * This routine is a major rewrite by Luciano Genero & Fulvio Cappelli using * tables for speed, and adds a second ant type, multiple ants, and random * rules. * * Revision history: * 20 Mar 95 LG/FC First release of table driven version * 31 Mar 95 LG/FC Fixed a bug that writes one pixel off the screen * 31 Mar 95 LG/FC Changed ant type 1 to produce the same pattern as the * original implementation (they were mirrored on the * x axis) * 04 Apr 95 TW Added wrap option and further modified the code to match * the original algorithm. It now matches exactly. * 10 Apr 95 TW Suffix array does not contain enough memory. Crashes at * over 1024x768. Changed to extraseg. * 12 Apr 95 TW Added maxants range check. */ #include /* see Fractint.c for a description of the "include" hierarchy */ #include "port.h" #include "prototyp.h" #include "helpdefs.h" #define RANDOM(n) ((int)((long)((long)rand() * (long)(n)) >> 15)) /* Generate Random * Number 0 <= r < n */ #define MAX_ANTS 256 #define XO (xdots/2) #define YO (ydots/2) #define DIRS 4 #define INNER_LOOP 100 /* possible value of idir e relative movement in the 4 directions * for x 0, 1, 0, -1 * for y 1, 0, -1, 0 */ static int far *incx[DIRS]; /* tab for 4 directions */ static int far *incy[DIRS]; void setwait(long *wait) { char msg[30]; int kbdchar; for (;;) { sprintf(msg, "Delay %4ld", *wait); while ((int)strlen(msg) < 15) strcat(msg, " "); msg[15] = '\0'; showtempmsg((char far *) msg); kbdchar = getakey(); switch (kbdchar) { case RIGHT_ARROW_2: case UP_ARROW_2: (*wait) += 100; break; case RIGHT_ARROW: case UP_ARROW: (*wait) += 10; break; case DOWN_ARROW_2: case LEFT_ARROW_2: (*wait) -= 100; break; case LEFT_ARROW: case DOWN_ARROW: (*wait) -= 10; break; default: cleartempmsg(); return; } if (*wait < 0) *wait = 0; } } /* turkmite from scientific american july 1994 pag 91 * Tweaked by Luciano Genero & Fulvio Cappelli */ void TurkMite1(int maxtur, int rule_len, char *ru, long maxpts, long wait) { int color, ix, iy, idir, pixel, i; int kbdchar, step, antwrap; int x[MAX_ANTS + 1], y[MAX_ANTS + 1]; int next_col[MAX_ANTS + 1], rule[MAX_ANTS + 1], dir[MAX_ANTS + 1]; long count; antwrap = ((param[4] == 0) ? 0 : 1); step = (int) wait; if (step == 1) wait = 0; else step = 0; if (rule_len == 0) { /* random rule */ for (color = 0; color < MAX_ANTS; color++) { /* init the rules and colors for the * turkmites: 1 turn left, -1 turn right */ rule[color] = 1 - (RANDOM(2) * 2); next_col[color] = color + 1; } /* close the cycle */ next_col[color] = 0; } else { /* user defined rule */ for (color = 0; color < rule_len; color++) { /* init the rules and colors for the * turkmites: 1 turn left, -1 turn right */ rule[color] = (ru[color] * 2) - 1; next_col[color] = color + 1; } /* repeats to last color */ for (color = rule_len; color < MAX_ANTS; color++) { /* init the rules and colors for the * turkmites: 1 turn left, -1 turn right */ rule[color] = rule[color % rule_len]; next_col[color] = color + 1; } /* close the cycle */ next_col[color] = 0; } for (color = maxtur; color; color--) { /* init the various turmites N.B. non usa * x[0], y[0], dir[0] */ if (rule_len) { dir[color] = 1; x[color] = XO; y[color] = YO; } else { dir[color] = RANDOM(DIRS); x[color] = RANDOM(xdots); y[color] = RANDOM(ydots); } } maxpts = maxpts / (long) INNER_LOOP; for (count = 0; count < maxpts; count++) { /* check for a key only every inner_loop times */ kbdchar = keypressed(); if (kbdchar || step) { int done = 0; if (kbdchar == 0) kbdchar = getakey(); switch (kbdchar) { case SPACE: step = 1 - step; break; case ESC: done = 1; break; case RIGHT_ARROW: case UP_ARROW: case DOWN_ARROW: case LEFT_ARROW: case RIGHT_ARROW_2: case UP_ARROW_2: case DOWN_ARROW_2: case LEFT_ARROW_2: setwait(&wait); break; default: done = 1; break; } if (done) goto exit_ant; if (keypressed()) getakey(); } for (i = INNER_LOOP; i; i--) { if (wait > 0 && step == 0) { for (color = maxtur; color; color--) { /* move the various turmites */ ix = x[color]; /* temp vars */ iy = y[color]; idir = dir[color]; pixel = getcolor(ix, iy); putcolor(ix, iy, 15); sleepms(wait); putcolor(ix, iy, next_col[pixel]); idir += rule[pixel]; idir &= 3; if (antwrap == 0) if ((idir == 0 && iy == ydots - 1) || (idir == 1 && ix == xdots - 1) || (idir == 2 && iy == 0) || (idir == 3 && ix == 0)) goto exit_ant; x[color] = incx[idir][ix]; y[color] = incy[idir][iy]; dir[color] = idir; } } else { for (color = maxtur; color; color--) { /* move the various turmites without delay */ ix = x[color]; /* temp vars */ iy = y[color]; idir = dir[color]; pixel = getcolor(ix, iy); putcolor(ix, iy, next_col[pixel]); idir += rule[pixel]; idir &= 3; if (antwrap == 0) if ((idir == 0 && iy == ydots - 1) || (idir == 1 && ix == xdots - 1) || (idir == 2 && iy == 0) || (idir == 3 && ix == 0)) goto exit_ant; x[color] = incx[idir][ix]; y[color] = incy[idir][iy]; dir[color] = idir; } } } } exit_ant: return; } /* this one ignore the color of the current cell is more like a white ant */ void TurkMite2(int maxtur, int rule_len, char *ru, long maxpts, long wait) { int color, ix, iy, idir, pixel, dir[MAX_ANTS + 1], i; int kbdchar, step, antwrap; int x[MAX_ANTS + 1], y[MAX_ANTS + 1]; int rule[MAX_ANTS + 1], rule_mask; long count; antwrap = ((param[4] == 0) ? 0 : 1); step = (int) wait; if (step == 1) wait = 0; else step = 0; if (rule_len == 0) { /* random rule */ for (color = MAX_ANTS - 1; color; color--) { /* init the various turmites N.B. don't use * x[0], y[0], dir[0] */ dir[color] = RANDOM(DIRS); rule[color] = (rand() << RANDOM(2)) | RANDOM(2); x[color] = RANDOM(xdots); y[color] = RANDOM(ydots); } } else { /* the same rule the user wants for every * turkmite (max rule_len = 16 bit) */ rule_len = min(rule_len, 8 * sizeof(int)); for (i = 0, rule[0] = 0; i < rule_len; i++) rule[0] = (rule[0] << 1) | ru[i]; for (color = MAX_ANTS - 1; color; color--) { /* init the various turmites N.B. non usa * x[0], y[0], dir[0] */ dir[color] = 0; rule[color] = rule[0]; x[color] = XO; y[color] = YO; } } /* use this rule when a black pixel is found */ rule[0] = 0; rule_mask = 1; maxpts = maxpts / (long) INNER_LOOP; for (count = 0; count < maxpts; count++) { /* check for a key only every inner_loop times */ kbdchar = keypressed(); if (kbdchar || step) { int done = 0; if (kbdchar == 0) kbdchar = getakey(); switch (kbdchar) { case SPACE: step = 1 - step; break; case ESC: done = 1; break; case RIGHT_ARROW: case UP_ARROW: case DOWN_ARROW: case LEFT_ARROW: case RIGHT_ARROW_2: case UP_ARROW_2: case DOWN_ARROW_2: case LEFT_ARROW_2: setwait(&wait); break; default: done = 1; break; } if (done) goto exit_ant; if (keypressed()) getakey(); } for (i = INNER_LOOP; i; i--) { for (color = maxtur; color; color--) { /* move the various turmites */ ix = x[color]; /* temp vars */ iy = y[color]; idir = dir[color]; pixel = getcolor(ix, iy); putcolor(ix, iy, 15); if (wait > 0 && step == 0) sleepms(wait); if (rule[pixel] & rule_mask) { /* turn right */ idir--; putcolor(ix, iy, 0); } else { /* turn left */ idir++; putcolor(ix, iy, color); } idir &= 3; if (antwrap == 0) if ((idir == 0 && iy == ydots - 1) || (idir == 1 && ix == xdots - 1) || (idir == 2 && iy == 0) || (idir == 3 && ix == 0)) goto exit_ant; x[color] = incx[idir][ix]; y[color] = incy[idir][iy]; dir[color] = idir; } rule_mask = _rotl(rule_mask, 1); } } exit_ant: return; } /* N.B. use the common memory in extraseg - suffix not large enough*/ int ant(void) { int maxants, type, i; int oldhelpmode, rule_len; long maxpts, wait; char rule[MAX_ANTS]; char far *extra; extra = MK_FP(extraseg,0); for (i = 0; i < DIRS; i++) { incx[i] = (int far *) (extra + (xdots + 2) * sizeof(int) * i); /* steal some memory */ incy[i] = (int far *) (extra + (xdots + 2) * sizeof(int) * DIRS + (ydots + 2) *sizeof(int) * i); /* steal some memory */ } /* In this vectors put all the possible point that the ants can visit. * Wrap them from a side to the other insted of simply end calculation */ for (i = 0; i < xdots; i++) { incx[0][i] = i; incx[2][i] = i; } for(i = 0; i < xdots; i++) incx[3][i] = i + 1; incx[3][xdots-1] = 0; /* wrap from right of the screen to left */ for(i = 1; i < xdots; i++) incx[1][i] = i - 1; incx[1][0] = xdots-1; /* wrap from left of the screen to right */ for (i = 0; i < ydots; i++) { incy[1][i] = i; incy[3][i] = i; } for (i = 0; i < ydots; i++) incy[0][i] = i + 1; incy[0][ydots - 1] = 0; /* wrap from the top of the screen to the * bottom */ for (i = 1; i < ydots; i++) incy[2][i] = i - 1; incy[2][0] = ydots - 1; /* wrap from the bottom of the screen to the * top */ oldhelpmode = helpmode; helpmode = ANTCOMMANDS; maxpts = (long) param[1]; maxpts = labs(maxpts); wait = abs(orbit_delay); sprintf(rule, "%.17g", param[0]); rule_len = strlen(rule); if (rule_len > 1) { /* if rule_len == 0 random rule */ for (i = 0; i < rule_len; i++) { if (rule[i] != '1') rule[i] = (char) 0; else rule[i] = (char) 1; } } else rule_len = 0; /* set random seed for reproducibility */ if ((!rflag) && param[5] == 1) --rseed; if (param[5] != 0 && param[5] != 1) rseed = (int)param[5]; srand(rseed); if (!rflag) ++rseed; maxants = (int) param[2]; if (maxants < 1) /* if maxants == 0 maxants random */ maxants = 2 + RANDOM(MAX_ANTS - 2); else if (maxants > MAX_ANTS) param[2] = maxants = MAX_ANTS; type = (int) param[3] - 1; if (type < 0 || type > 1) type = RANDOM(2); /* if type == 0 choose a random type */ switch (type) { case 0: TurkMite1(maxants, rule_len, rule, maxpts, wait); break; case 1: TurkMite2(maxants, rule_len, rule, maxpts, wait); break; } helpmode = oldhelpmode; return 0; }