X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Floop.c;h=04419801919d5681feb0379b49a574964022e3aa;hp=c7280eaa936e3c92fbe0d5664ec6846124db629f;hb=a94197e76a5dea5cb60542840809d6c20d0abbf3;hpb=8eb2873d7054e705c4e83f22d18c40946a9e2529 diff --git a/hacks/loop.c b/hacks/loop.c index c7280eaa..04419801 100644 --- a/hacks/loop.c +++ b/hacks/loop.c @@ -2,7 +2,7 @@ /* loop --- Chris Langton's self-producing loops */ #if !defined( lint ) && !defined( SABER ) -static const char sccsid[] = "@(#)loop.c 4.13 98/10/18 xlockmore"; +static const char sccsid[] = "@(#)loop.c 5.01 2000/03/15 xlockmore"; #endif @@ -22,20 +22,35 @@ static const char sccsid[] = "@(#)loop.c 4.13 98/10/18 xlockmore"; * other special, indirect and consequential damages. * * Revision History: - * 18-Oct-98: Started creating a hexagon version, probably will not work - * for a while since some work has to go into getting not - * only the program to handle the hexagonal data but the loop - * has to be "programmed" as well. I suspect it should be easier - * than the original since the loop will have six sides to - * store its genes (data). - * 10-May-97: Compatible with xscreensaver - * 15-Nov-95: Coded from Chris Langton's Self-Reproduction in Cellular - * Automata Physica 10D 135-144 1984 - * also used wire.c as a guide. + * 15-Mar-2001: Added some flaws, random blue wall spots, to liven it up. + * This mod seems to expose a bug where hexagons are erased + * for no apparent reason. + * 01-Nov-2000: Allocation checks + * 16-Jun-2000: Fully coded the hexagonal rules. (Rules that end up in + * state zero were not bothered with since a calloc was used + * to set non-explicit rules to zero. This allows the + * compile-time option RAND_RULES to work here (at least to + * generation 540).) + * Also added compile-time option DELAYDEBUGLOOP for debugging + * life form. This also turns off the random initial direction + * of the loop. Set DELAYDEBUGLOOP to be 10 and use with + * something like this: + * xlock -mode loop -neighbors 6 -size 5 -delay 1 -count 540 -nolock + * 18-Oct-1998: Started creating a hexagon version. + * It proved not that difficult because I used Langton's Loop + * as a guide, hexagons have more neighbors so there is more + * freedom to program, and the loop will has six sides to + * store its genes (data). + * (Soon after this a triangular version with neighbors = 6 + * was attempted but was unsuccessful). + * 10-May-1997: Compatible with xscreensaver + * 15-Nov-1995: Coded from Chris Langton's Self-Reproduction in Cellular + * Automata Physica 10D 135-144 1984, also used wire.c as a + * guide. */ /*- - Grid Number of Neigbors + Grid Number of Neighbors ---- ------------------ Square 4 Hexagon 6 (currently in development) @@ -59,54 +74,84 @@ static const char sccsid[] = "@(#)loop.c 4.13 98/10/18 xlockmore"; machine is not contained in the loop. This is a simplification of von Neumann and Codd's self-producing Turing machine. The data spinning around could be viewed as both its DNA and its internal - clock. + clock. The program can be initalized to have the loop spin both ways... + but only one way around will work for a given rule. An open question (at + least to me): Is handedness a requirement for (artificial) life? Here + there is handedness at both the initial condition and the transition rule. */ #ifdef STANDALONE -# define PROGCLASS "loop" -# define HACK_INIT init_loop -# define HACK_DRAW draw_loop -# define loop_opts xlockmore_opts -# define DEFAULTS "*delay: 100000 \n" \ - "*cycles: 1600 \n" \ - "*size: -12 \n" \ - "*ncolors: 15 \n" \ - "*neighbors: 0 \n" -# define SMOOTH_COLORS -# include "xlockmore.h" /* in xscreensaver distribution */ +#define MODE_loop +#define PROGCLASS "loop" +#define HACK_INIT init_loop +#define HACK_DRAW draw_loop +#define loop_opts xlockmore_opts +#define DEFAULTS "*delay: 100000 \n" \ + "*count: -5 \n" \ + "*cycles: 1600 \n" \ + "*size: -12 \n" \ + "*ncolors: 15 \n" \ + "*neighbors: 0 \n" +#define UNIFORM_COLORS +#include "xlockmore.h" /* in xscreensaver distribution */ #else /* STANDALONE */ -# include "xlock.h" /* in xlockmore distribution */ +#include "xlock.h" /* in xlockmore distribution */ #endif /* STANDALONE */ - #include "automata.h" +#ifdef MODE_loop + /*- * neighbors of 0 randomizes between 4 and 6. */ -#ifdef STANDALONE -static int neighbors; -#else -extern int neighbors; -#endif /* !STANDALONE */ +#define DEF_NEIGHBORS "0" /* choose random value */ + +static int neighbors; + +static XrmOptionDescRec opts[] = +{ + {(char *) "-neighbors", (char *) ".loop.neighbors", XrmoptionSepArg, (caddr_t) NULL} +}; + +static argtype vars[] = +{ + {(caddr_t *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int} +}; + +static OptionStruct desc[] = +{ + {(char *) "-neighbors num", (char *) "squares 4 or hexagons 6"} +}; ModeSpecOpt loop_opts = -{0, NULL, 0, NULL, NULL}; +{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc}; + #ifdef USE_MODULES ModStruct loop_description = {"loop", "init_loop", "draw_loop", "release_loop", - "refresh_loop", "init_loop", NULL, &loop_opts, - 100000, 1, 1600, -12, 64, 1.0, "", + "refresh_loop", "init_loop", (char *) NULL, &loop_opts, + 100000, 5, 1600, -12, 64, 1.0, "", "Shows Langton's self-producing loops", 0, NULL}; #endif #define LOOPBITS(n,w,h)\ - lp->pixmaps[lp->init_bits++]=\ - XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1) + if ((lp->pixmaps[lp->init_bits]=\ + XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\ + free_loop(display,lp); return;} else {lp->init_bits++;} static int local_neighbors = 0; -static int neighbor_kind = 0; + +#if 0 +/* Used to fast forward to troubled generations, mainly used for debugging. + -delay 1 -count 170 -neighbors 6 # divisions starts + 540 first cell collision + 1111 mutant being born from 2 parents + 1156 mutant born + */ +#define DELAYDEBUGLOOP 10 +#endif #define COLORS 8 #define REALCOLORS (COLORS-2) @@ -114,33 +159,35 @@ static int neighbor_kind = 0; #define REDRAWSTEP 2000 /* How many cells to draw per cycle */ #define ADAM_SIZE 8 /* MIN 5 */ #if 1 -# define ADAM_LOOPX (ADAM_SIZE+2) -# define ADAM_LOOPY (ADAM_SIZE+2) +#define ADAM_LOOPX (ADAM_SIZE+2) +#define ADAM_LOOPY (ADAM_SIZE+2) #else -# define ADAM_LOOPX 16 -# define ADAM_LOOPY 10 +#define ADAM_LOOPX 16 +#define ADAM_LOOPY 10 #endif #define MINGRIDSIZE (3*ADAM_LOOPX) +#if 0 /* TRIA stuff was an attempt to make a triangular lifeform on a - hex grid but I got bored. You probably need an additional 7th - state for a coherent step by step process of separation and + hexagonal grid but I got bored. You may need an additional 7th + state for a coherent step by step process of cell separation and initial stem development. */ -/* #define TRIA 1 */ +#define TRIA 1 +#endif #ifdef TRIA -# define HEX_ADAM_SIZE 3 /* MIN 3 */ +#define HEX_ADAM_SIZE 3 /* MIN 3 */ #else -# define HEX_ADAM_SIZE 5 /* MIN 3 */ +#define HEX_ADAM_SIZE 5 /* MIN 3 */ #endif #if 1 -# define HEX_ADAM_LOOPX (2*HEX_ADAM_SIZE+1) -# define HEX_ADAM_LOOPY (2*HEX_ADAM_SIZE+1) +#define HEX_ADAM_LOOPX (2*HEX_ADAM_SIZE+1) +#define HEX_ADAM_LOOPY (2*HEX_ADAM_SIZE+1) #else -# define HEX_ADAM_LOOPX 3 -# define HEX_ADAM_LOOPY 7 +#define HEX_ADAM_LOOPX 3 +#define HEX_ADAM_LOOPY 7 #endif #define HEX_MINGRIDSIZE (6*HEX_ADAM_LOOPX) -#define MINSIZE 5 /* jwz -- really tiny cells don't look good */ +#define MINSIZE ((MI_NPIXELS(mi)>=COLORS)?1:(2+(local_neighbors==6))) #define NEIGHBORKINDS 2 #define ANGLES 360 #define MAXNEIGHBORS 6 @@ -161,6 +208,7 @@ typedef struct { int mincol, minrow, maxcol, maxrow; int width, height; int redrawing, redrawpos; + Bool dead, clockwise; unsigned char *newcells, *oldcells; int ncells[COLORS]; CellList *cellList[COLORS]; @@ -172,12 +220,22 @@ typedef struct { } shape; } loopstruct; -static loopstruct *loops = NULL; +static loopstruct *loops = (loopstruct *) NULL; #define TRANSITION(TT,V) V=TT&7;TT>>=3 +#define FINALTRANSITION(TT,V) V=TT&7 #define TABLE(R,T,L,B) (table[((B)<<9)|((L)<<6)|((T)<<3)|(R)]) #define HEX_TABLE(R,T,t,l,b,B) (table[((B)<<15)|((b)<<12)|((l)<<9)|((t)<<6)|((T)<<3)|(R)]) -#ifdef RAND_RULES /* Hack, see below */ + +#if 0 +/* Instead of setting "unused" state rules to zero it randomizes them. + These rules take over when something unexpected happens... like when a + cell hits a wall (the end of the screen). + */ +#define RAND_RULES +#endif + +#ifdef RAND_RULES #define TABLE_IN(C,R,T,L,B,I) (TABLE(R,T,L,B)&=~(7<<((C)*3)));\ (TABLE(R,T,L,B)|=((I)<<((C)*3))) #define HEX_TABLE_IN(C,R,T,t,l,b,B,I) (HEX_TABLE(R,T,t,l,b,B)&=~(7<<((C)*3)));\ @@ -189,8 +247,9 @@ static loopstruct *loops = NULL; #define TABLE_OUT(C,R,T,L,B) ((TABLE(R,T,L,B)>>((C)*3))&7) #define HEX_TABLE_OUT(C,R,T,t,l,b,B) ((HEX_TABLE(R,T,t,l,b,B)>>((C)*3))&7) -static unsigned int *table = NULL; /* 8*8*8*8 = 2^12 = 2^3^4 = 4K */ - /* 8*8*8*8*8*8 = too big? */ +static unsigned int *table = (unsigned int *) NULL; + /* square: 8*8*8*8 = 2^12 = 2^3^4 = 4096 */ + /* hexagon: 8*8*8*8*8*8 = 2^18 = 2^3^6 = 262144 = too big? */ static char plots[NEIGHBORKINDS] = { @@ -395,7 +454,7 @@ static unsigned int hex_transition_table[] = 020102022, 020202112, 000000012, 000000122, 000000212, - 010002121, + 010002121, 020001122, 020002112, 020011122, @@ -442,7 +501,7 @@ static unsigned int hex_transition_table[] = 020040422, 040002022, - + 010224224, 010222424, 010202424, 020142022, 020202412, 020011722, 020112072, 020172072, 020142072, @@ -450,7 +509,7 @@ static unsigned int hex_transition_table[] = 000210225, 000022015, 000022522, - 011225521, + 011225521, 020120525, 020020152, 020005122, 020214255, 020021152, 020255242, 050215222, 050225121, @@ -465,7 +524,7 @@ static unsigned int hex_transition_table[] = 001224251, 010022152, 010251221, 010522121, 011212151, 011221251, 011215221, - 020000220, 020002152, 020020220, 020021020, 020022152, + 020000220, 020002152, 020020220, 020022152, 020021422, 020022152, 020022522, 020025425, 020050422, 020051022, 020051122, 020211122, 020211222, 020215222, 020245122, @@ -486,7 +545,7 @@ static unsigned int hex_transition_table[] = 020021552, 012252277, 050002521, - 020005725, + 020005725, 050011022, 000000155, @@ -544,7 +603,7 @@ static unsigned int hex_transition_table[] = 020521122, 020025022, 020025522, - 020020522, + 020020522, 020202222, 020212222, @@ -557,7 +616,6 @@ static unsigned int hex_transition_table[] = 020212122, 020027222, 020024222, - 020020222, 020212722, 020212422, 020202122, @@ -569,6 +627,33 @@ static unsigned int hex_transition_table[] = 020212052, 020205052, + 070221250, + + 000000050, 000005220, 000002270, 070252220, + 000000450, 000007220, + 000220220, 000202220, 000022020, 000020220, + + 000222040, + 000220440, + 000022040, + 000040220, + + 000252220, + 050221120, 010221520, + 002222220, + + 000070220, 000220720, + 000020520, 000070250, 000222070, 000027020, + 000022070, 000202270, 000024020, 000220420, + 000220270, 000220240, 000072020, 000042020, + 000002020, 000002070, 000020270, 000020250, + 000270270, 000007020, 000040270, + + /* Collision starts (gen 540), not sure to have rules to save it + or depend on calloc to intialize remaining rules to 0 so that + the mutant will be born + */ + 000050220, #endif }; @@ -687,30 +772,26 @@ position_of_neighbor(int dir, int *pcol, int *prow) if (local_neighbors == 6) { switch (dir) { case 0: - col = col + 1; + col++; break; case 60: - if (row & 1) - col = col + 1; - row = row - 1; + col += (row & 1); + row--; break; case 120: - if (!(row & 1)) - col = col - 1; - row = row - 1; + col -= !(row & 1); + row--; break; case 180: - col = col - 1; + col--; break; case 240: - if (!(row & 1)) - col = col - 1; - row = row + 1; + col -= !(row & 1); + row++; break; case 300: - if (row & 1) - col = col + 1; - row = row + 1; + col += (row & 1); + row++; break; default: (void) fprintf(stderr, "wrong direction %d\n", dir); @@ -718,16 +799,16 @@ position_of_neighbor(int dir, int *pcol, int *prow) } else { switch (dir) { case 0: - col = col + 1; + col++; break; case 90: - row = row - 1; + row--; break; case 180: - col = col - 1; + col--; break; case 270: - row = row + 1; + row++; break; default: (void) fprintf(stderr, "wrong direction %d\n", dir); @@ -755,8 +836,8 @@ fillcell(ModeInfo * mi, GC gc, int col, int row) lp->shape.hexagon[0].x = lp->xb + ccol * lp->xs; lp->shape.hexagon[0].y = lp->yb + crow * lp->ys; if (lp->xs == 1 && lp->ys == 1) - XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc, - lp->shape.hexagon[0].x, lp->shape.hexagon[0].y, 1, 1); + XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + lp->shape.hexagon[0].x, lp->shape.hexagon[0].y); else XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, lp->shape.hexagon, 6, Convex, CoordModePrevious); @@ -788,23 +869,6 @@ drawcell(ModeInfo * mi, int col, int row, int state) fillcell(mi, gc, col, row); } -static void -addtolist(ModeInfo * mi, int col, int row, unsigned char state) -{ - loopstruct *lp = &loops[MI_SCREEN(mi)]; - CellList *current = lp->cellList[state]; - - lp->cellList[state] = NULL; - if ((lp->cellList[state] = (CellList *) malloc(sizeof (CellList))) == NULL) { - lp->cellList[state] = current; - return; - } - lp->cellList[state]->pt.x = col; - lp->cellList[state]->pt.y = row; - lp->cellList[state]->next = current; - lp->ncells[state]++; -} - #ifdef DEBUG static void print_state(ModeInfo * mi, int state) @@ -838,21 +902,75 @@ free_state(loopstruct * lp, int state) } static void +free_list(loopstruct * lp) +{ + int state; + + for (state = 0; state < COLORS; state++) + free_state(lp, state); +} + +static void +free_loop(Display *display, loopstruct * lp) +{ + int shade; + + for (shade = 0; shade < lp->init_bits; shade++) + if (lp->pixmaps[shade] != None) { + XFreePixmap(display, lp->pixmaps[shade]); + lp->pixmaps[shade] = None; + } + if (lp->stippledGC != None) { + XFreeGC(display, lp->stippledGC); + lp->stippledGC = None; + } + if (lp->oldcells != NULL) { + (void) free((void *) lp->oldcells); + lp->oldcells = (unsigned char *) NULL; + } + if (lp->newcells != NULL) { + (void) free((void *) lp->newcells); + lp->newcells = (unsigned char *) NULL; + } + free_list(lp); +} + +static Bool +addtolist(ModeInfo * mi, int col, int row, unsigned char state) +{ + loopstruct *lp = &loops[MI_SCREEN(mi)]; + CellList *current = lp->cellList[state]; + + if ((lp->cellList[state] = (CellList *) malloc(sizeof (CellList))) == + NULL) { + lp->cellList[state] = current; + free_loop(MI_DISPLAY(mi), lp); + return False; + } + lp->cellList[state]->pt.x = col; + lp->cellList[state]->pt.y = row; + lp->cellList[state]->next = current; + lp->ncells[state]++; + return True; +} + +static Bool draw_state(ModeInfo * mi, int state) { loopstruct *lp = &loops[MI_SCREEN(mi)]; + Display *display = MI_DISPLAY(mi); GC gc; XGCValues gcv; CellList *current = lp->cellList[state]; if (MI_NPIXELS(mi) >= COLORS) { gc = MI_GC(mi); - XSetForeground(MI_DISPLAY(mi), gc, lp->colors[state]); + XSetForeground(display, gc, lp->colors[state]); } else { gcv.stipple = lp->pixmaps[state]; gcv.foreground = MI_WHITE_PIXEL(mi); gcv.background = MI_BLACK_PIXEL(mi); - XChangeGC(MI_DISPLAY(mi), lp->stippledGC, + XChangeGC(display, lp->stippledGC, GCStipple | GCForeground | GCBackground, &gcv); gc = lp->stippledGC; } @@ -867,21 +985,22 @@ draw_state(ModeInfo * mi, int state) lp->shape.hexagon[0].x = lp->xb + ccol * lp->xs; lp->shape.hexagon[0].y = lp->yb + crow * lp->ys; if (lp->xs == 1 && lp->ys == 1) - XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc, - lp->shape.hexagon[0].x, lp->shape.hexagon[0].y, 1, 1); + XDrawPoint(display, MI_WINDOW(mi), gc, + lp->shape.hexagon[0].x, lp->shape.hexagon[0].y); else - XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc, + XFillPolygon(display, MI_WINDOW(mi), gc, lp->shape.hexagon, 6, Convex, CoordModePrevious); current = current->next; } } else { /* Take advantage of XFillRectangles */ - XRectangle *rects = NULL; + XRectangle *rects; int nrects = 0; /* Create Rectangle list from part of the cellList */ - if ((rects = (XRectangle *) malloc(lp->ncells[state] * sizeof (XRectangle))) == NULL) { - return; + if ((rects = (XRectangle *) malloc(lp->ncells[state] * + sizeof (XRectangle))) == NULL) { + return False; } while (current) { @@ -893,15 +1012,16 @@ draw_state(ModeInfo * mi, int state) nrects++; } /* Finally get to draw */ - XFillRectangles(MI_DISPLAY(mi), MI_WINDOW(mi), gc, rects, nrects); + XFillRectangles(display, MI_WINDOW(mi), gc, rects, nrects); /* Free up rects list and the appropriate part of the cellList */ (void) free((void *) rects); } free_state(lp, state); - XFlush(MI_DISPLAY(mi)); + XFlush(display); + return True; } -static int +static Bool init_table(void) { if (table == NULL) { @@ -917,16 +1037,21 @@ init_table(void) mult *= 8; if ((table = (unsigned int *) calloc(mult, sizeof (unsigned int))) == NULL) { - return 1; + return False; } + #ifdef RAND_RULES /* Here I was interested to see what happens when it hits a wall.... Rules not normally used take over... takes too much time though */ - { + /* Each state = 3 bits */ + if (MAXRAND < 16777216.0) { for (j = 0; j < mult; j++) { - for (k = 0; k < 8; k++) - table[j] |= (unsigned int) ((unsigned int) (NRAND(8)) << (k * 3)); + table[j] = (unsigned int) ((NRAND(4096) << 12) & NRAND(4096)); + } + } else { + for (j = 0; j < mult; j++) { + table[j] = (unsigned int) (NRAND(16777216)); } } #endif @@ -937,7 +1062,7 @@ init_table(void) for (k = 0; k < local_neighbors; k++) { TRANSITION(tt, n[k]); } - TRANSITION(tt, c); + FINALTRANSITION(tt, c); HEX_TABLE_IN(c, n[0], n[1], n[2], n[3], n[4], n[5], i); HEX_TABLE_IN(c, n[1], n[2], n[3], n[4], n[5], n[0], i); HEX_TABLE_IN(c, n[2], n[3], n[4], n[5], n[0], n[1], i); @@ -952,7 +1077,7 @@ init_table(void) for (k = 0; k < local_neighbors; k++) { TRANSITION(tt, n[k]); } - TRANSITION(tt, c); + FINALTRANSITION(tt, c); TABLE_IN(c, n[0], n[1], n[2], n[3], i); TABLE_IN(c, n[1], n[2], n[3], n[0], i); TABLE_IN(c, n[2], n[3], n[0], n[1], i); @@ -960,7 +1085,56 @@ init_table(void) } } } - return 0; + return True; +} + +static void +init_flaw(ModeInfo * mi) +{ + loopstruct *lp = &loops[MI_SCREEN(mi)]; + int a, b; + +#define BLUE 2 + if (lp->bncols <= 3 || lp->bnrows <= 3) + return; + a = MIN(lp->bncols - 3, 2 * ((local_neighbors == 6) ? + HEX_MINGRIDSIZE : MINGRIDSIZE)); + a = NRAND(a) + (lp->bncols - a) / 2; + b = MIN(lp->bnrows - 3, 2 * ((local_neighbors == 6) ? + HEX_MINGRIDSIZE : MINGRIDSIZE)); + b = NRAND(b) + (lp->bnrows - b) / 2; + if (lp->mincol > a) + lp->mincol = a; + if (lp->minrow > b) + lp->minrow = b; + if (lp->maxcol < a + 2) + lp->maxcol = a + 2; + if (lp->maxrow < b + 2) + lp->maxrow = b + 2; + + if (local_neighbors == 6) { + lp->newcells[b * lp->bncols + a + !(b % 2) ] = BLUE; + lp->newcells[b * lp->bncols + a + 1 + !(b % 2)] = BLUE; + lp->newcells[(b + 1) * lp->bncols + a] = BLUE; + lp->newcells[(b + 1) * lp->bncols + a + 2] = BLUE; + lp->newcells[(b + 2) * lp->bncols + a + !(b % 2)] = BLUE; + lp->newcells[(b + 2) * lp->bncols + a + 1 + !(b % 2)] = BLUE; + } else { + int orient = NRAND(4); + lp->newcells[lp->bncols * (b + 1) + a + 1] = BLUE; + if (orient == 0 || orient == 1) { + lp->newcells[lp->bncols * b + a + 1] = BLUE; + } + if (orient == 1 || orient == 2) { + lp->newcells[lp->bncols * (b + 1) + a + 2] = BLUE; + } + if (orient == 2 || orient == 3) { + lp->newcells[lp->bncols * (b + 2) + a + 1] = BLUE; + } + if (orient == 3 || orient == 0) { + lp->newcells[lp->bncols * (b + 1) + a] = BLUE; + } + } } static void @@ -968,165 +1142,232 @@ init_adam(ModeInfo * mi) { loopstruct *lp = &loops[MI_SCREEN(mi)]; XPoint start, dirx, diry; - int i, j; + int i, j, dir; - if (local_neighbors == 6) { +#ifdef DELAYDEBUGLOOP + lp->clockwise = 0; + if (!MI_COUNT(mi)) /* Probably doing testing so do not confuse */ +#endif + lp->clockwise = (Bool) (LRAND() & 1); +#ifdef DELAYDEBUGLOOP + dir = 0; + if (!MI_COUNT(mi)) /* Probably doing testing so do not confuse */ +#endif + dir = NRAND(local_neighbors); + if (local_neighbors == 6) { int k; - /* switch (0) */ - switch (NRAND(6)) { + switch (dir) { case 0: start.x = (lp->bncols - HEX_ADAM_LOOPX / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPY) / 2; - lp->mincol = start.x - 2; - lp->minrow = start.y - 1; - lp->maxcol = start.x + HEX_ADAM_LOOPX + 1; - lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; + if (lp->mincol > start.x - 2) + lp->mincol = start.x - 2; + if (lp->minrow > start.y - 1) + lp->minrow = start.y - 1; + if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1) + lp->maxcol = start.x + HEX_ADAM_LOOPX + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; for (j = 0; j < HEX_ADAM_LOOPY; j++) { for (i = 0; i < HEX_ADAM_LOOPX; i++) { k = (((lp->bnrows / 2 + HEX_ADAM_LOOPY / 2) % 2) ? -j / 2 : -(j + 1) / 2); lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = - hex_self_reproducing_loop[j][i]; + (lp->clockwise) ? + hex_self_reproducing_loop[i][j] : + hex_self_reproducing_loop[j][i]; } } break; case 1: start.x = (lp->bncols - (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2; - lp->mincol = start.x - 1; - lp->minrow = start.y - HEX_ADAM_LOOPX; - lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1; - lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; + if (lp->mincol > start.x - 1) + lp->mincol = start.x - 1; + if (lp->minrow > start.y - HEX_ADAM_LOOPX) + lp->minrow = start.y - HEX_ADAM_LOOPX; + if (lp->maxcol < start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1) + lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; for (j = 0; j < HEX_ADAM_LOOPY; j++) { for (i = 0; i < HEX_ADAM_LOOPX; i++) { k = (((lp->bnrows / 2 + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) % 2) ? -(i + j + 1) / 2 : -(i + j) / 2); lp->newcells[(start.y + j - i) * lp->bncols + start.x + i + j + k] = - hex_self_reproducing_loop[j][i]; + (lp->clockwise) ? + hex_self_reproducing_loop[i][j] : + hex_self_reproducing_loop[j][i]; } } break; case 2: start.x = (lp->bncols - HEX_ADAM_LOOPY / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPX) / 2; - lp->mincol = start.x - 2; - lp->minrow = start.y - 1; - lp->maxcol = start.x + HEX_ADAM_LOOPY + 1; - lp->maxrow = start.y + HEX_ADAM_LOOPX + 1; + if (lp->mincol > start.x - 2) + lp->mincol = start.x - 2; + if (lp->minrow > start.y - 1) + lp->minrow = start.y - 1; + if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1) + lp->maxcol = start.x + HEX_ADAM_LOOPX + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; for (j = 0; j < HEX_ADAM_LOOPX; j++) { for (i = 0; i < HEX_ADAM_LOOPY; i++) { k = (((lp->bnrows / 2 + HEX_ADAM_LOOPX / 2) % 2) ? -(HEX_ADAM_LOOPX - j - 1) / 2 : -(HEX_ADAM_LOOPX - j) / 2); lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = - hex_self_reproducing_loop[i][HEX_ADAM_LOOPX - j - 1]; + (lp->clockwise) ? + hex_self_reproducing_loop[j][HEX_ADAM_LOOPX - i - 1] : + hex_self_reproducing_loop[i][HEX_ADAM_LOOPY - j - 1]; } } break; case 3: start.x = (lp->bncols - HEX_ADAM_LOOPX / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPY) / 2; - lp->mincol = start.x - 1, lp->minrow = start.y - 1; - lp->maxcol = start.x + HEX_ADAM_LOOPX + 1, lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; + if (lp->mincol > start.x - 1) + lp->mincol = start.x - 1; + if (lp->minrow > start.y - 1) + lp->minrow = start.y - 1; + if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1) + lp->maxcol = start.x + HEX_ADAM_LOOPX + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; for (j = 0; j < HEX_ADAM_LOOPY; j++) { for (i = 0; i < HEX_ADAM_LOOPX; i++) { k = (((lp->bnrows / 2 + HEX_ADAM_LOOPY / 2) % 2) ? -j / 2 : -(j + 1) / 2); lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = - hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1]; + (lp->clockwise) ? + hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][HEX_ADAM_LOOPY - j - 1] : + hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1]; } } break; case 4: start.x = (lp->bncols - (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2; - lp->mincol = start.x - 1; - lp->minrow = start.y - HEX_ADAM_LOOPX; - lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1; - lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; + if (lp->mincol > start.x - 1) + lp->mincol = start.x - 1; + if (lp->minrow > start.y - HEX_ADAM_LOOPX) + lp->minrow = start.y - HEX_ADAM_LOOPX; + if (lp->maxcol < start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1) + lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPY + 1; for (j = 0; j < HEX_ADAM_LOOPY; j++) { for (i = 0; i < HEX_ADAM_LOOPX; i++) { k = (((lp->bnrows / 2 + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) % 2) ? -(i + j + 1) / 2 : -(i + j) / 2); lp->newcells[(start.y + j - i) * lp->bncols + start.x + i + j + k] = - hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1]; + (lp->clockwise) ? + hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][HEX_ADAM_LOOPY - j - 1] : + hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1]; } } break; case 5: start.x = (lp->bncols - HEX_ADAM_LOOPY / 2) / 2; start.y = (lp->bnrows - HEX_ADAM_LOOPX) / 2; - lp->mincol = start.x - 2; - lp->minrow = start.y - 1; - lp->maxcol = start.x + HEX_ADAM_LOOPY + 1; - lp->maxrow = start.y + HEX_ADAM_LOOPX + 1; + if (lp->mincol > start.x - 2) + lp->mincol = start.x - 2; + if (lp->minrow > start.y - 1) + lp->minrow = start.y - 1; + if (lp->maxcol < start.x + HEX_ADAM_LOOPY + 1) + lp->maxcol = start.x + HEX_ADAM_LOOPY + 1; + if (lp->maxrow < start.y + HEX_ADAM_LOOPX + 1) + lp->maxrow = start.y + HEX_ADAM_LOOPX + 1; for (j = 0; j < HEX_ADAM_LOOPX; j++) { for (i = 0; i < HEX_ADAM_LOOPY; i++) { k = (((lp->bnrows / 2 + HEX_ADAM_LOOPX / 2) % 2) ? -(HEX_ADAM_LOOPX - j - 1) / 2 : -(HEX_ADAM_LOOPX - j) / 2); lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] = - hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][j]; + (lp->clockwise) ? + hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][i] : + hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][j]; } } break; } #if DEBUGTEST - /* printf ("s %d s %d \n", start.x, start.y); */ - printf ("%d %d %d %d %d\t", + /* (void) printf ("s %d s %d \n", start.x, start.y); */ + (void) printf ("%d %d %d %d %d\n", start.x + i + ((lp->bnrows / 2 % 2) ? -j / 2 : -(j + 1) / 2) - lp->bx, start.y + j - lp->by, i, j, hex_self_reproducing_loop[j][i]); /* Draw right away */ drawcell(mi, start.x + i + ((lp->bnrows / 2 % 2) ? -j / 2 : -(j + 1) / 2) - lp->bx, start.y + j - lp->by, hex_self_reproducing_loop[j][i]); -#endif -#if DEBUGTEST - printf ("\n"); -#endif -#if DEBUGTEST - printf ("\n"); #endif } else { - switch (NRAND(4)) { + switch (dir) { case 0: start.x = (lp->bncols - ADAM_LOOPX) / 2; start.y = (lp->bnrows - ADAM_LOOPY) / 2; dirx.x = 1, dirx.y = 0; diry.x = 0, diry.y = 1; - lp->mincol = start.x, lp->minrow = start.y; - lp->maxcol = start.x + ADAM_LOOPX, lp->maxrow = start.y + ADAM_LOOPY; + if (lp->mincol > start.x) + lp->mincol = start.x; + if (lp->minrow > start.y) + lp->minrow = start.y; + if (lp->maxcol < start.x + ADAM_LOOPX) + lp->maxcol = start.x + ADAM_LOOPX; + if (lp->maxrow < start.y + ADAM_LOOPY) + lp->maxrow = start.y + ADAM_LOOPY; break; case 1: start.x = (lp->bncols + ADAM_LOOPY) / 2; start.y = (lp->bnrows - ADAM_LOOPX) / 2; dirx.x = 0, dirx.y = 1; diry.x = -1, diry.y = 0; - lp->mincol = start.x - ADAM_LOOPY, lp->minrow = start.y; - lp->maxcol = start.x, lp->maxrow = start.y + ADAM_LOOPX; + if (lp->mincol > start.x - ADAM_LOOPY) + lp->mincol = start.x - ADAM_LOOPY; + if (lp->minrow > start.y) + lp->minrow = start.y; + if (lp->maxcol < start.x) + lp->maxcol = start.x; + if (lp->maxrow < start.y + ADAM_LOOPX) + lp->maxrow = start.y + ADAM_LOOPX; break; case 2: start.x = (lp->bncols + ADAM_LOOPX) / 2; start.y = (lp->bnrows + ADAM_LOOPY) / 2; dirx.x = -1, dirx.y = 0; diry.x = 0, diry.y = -1; - lp->mincol = start.x - ADAM_LOOPX, lp->minrow = start.y - ADAM_LOOPY; - lp->maxcol = start.x, lp->maxrow = start.y; + if (lp->mincol > start.x - ADAM_LOOPX) + lp->mincol = start.x - ADAM_LOOPX; + if (lp->minrow > start.y - ADAM_LOOPY) + lp->minrow = start.y - ADAM_LOOPY; + if (lp->maxcol < start.x) + lp->maxcol = start.x; + if (lp->maxrow < start.y) + lp->maxrow = start.y; break; case 3: start.x = (lp->bncols - ADAM_LOOPY) / 2; start.y = (lp->bnrows + ADAM_LOOPX) / 2; dirx.x = 0, dirx.y = -1; diry.x = 1, diry.y = 0; - lp->mincol = start.x, lp->minrow = start.y - ADAM_LOOPX; - lp->maxcol = start.x + ADAM_LOOPY, lp->maxrow = start.y; + if (lp->mincol > start.x) + lp->mincol = start.x; + if (lp->minrow > start.y - ADAM_LOOPX) + lp->minrow = start.y - ADAM_LOOPX; + if (lp->maxcol < start.x + ADAM_LOOPX) + lp->maxcol = start.x + ADAM_LOOPX; + if (lp->maxrow < start.y) + lp->maxrow = start.y; break; } for (j = 0; j < ADAM_LOOPY; j++) for (i = 0; i < ADAM_LOOPX; i++) - lp->newcells[(start.y + dirx.y * i + diry.y * j) * lp->bncols + - start.x + dirx.x * i + diry.x * j] = - self_reproducing_loop[j][i]; + lp->newcells[lp->bncols * (start.y + dirx.y * i + diry.y * j) + + start.x + dirx.x * i + diry.x * j] = + (lp->clockwise) ? + self_reproducing_loop[j][ADAM_LOOPX - i - 1] : + self_reproducing_loop[j][i]; #if DEBUG /* Draw right away */ drawcell(mi, start.x + dirx.x * i + diry.x * j - lp->bx, start.y + dirx.y * i + diry.y * j - lp->by, - self_reproducing_loop[j][i]); + (lp->clockwise) ? self_reproducing_loop[j][ADAM_LOOPX - i - i] : self_reproducing_loop[j][i]); #endif } } @@ -1156,50 +1397,32 @@ do_gen(loopstruct * lp) } } if (local_neighbors == 6) { - *z = HEX_TABLE_OUT(c, n[0], n[1], n[2], n[3], n[4], n[5]); + *z = (lp->clockwise) ? + HEX_TABLE_OUT(c, n[5], n[4], n[3], n[2], n[1], n[0]) : + HEX_TABLE_OUT(c, n[0], n[1], n[2], n[3], n[4], n[5]); } else { - *z = TABLE_OUT(c, n[0], n[1], n[2], n[3]); + *z = (lp->clockwise) ? + TABLE_OUT(c, n[3], n[2], n[1], n[0]) : + TABLE_OUT(c, n[0], n[1], n[2], n[3]); } } } } -static void -free_list(loopstruct * lp) -{ - int state; - - for (state = 0; state < COLORS; state++) - free_state(lp, state); -} - void release_loop(ModeInfo * mi) { if (loops != NULL) { int screen; - for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { - loopstruct *lp = &loops[screen]; - int shade; - - for (shade = 0; shade < lp->init_bits; shade++) - if (lp->pixmaps[shade] != None) - XFreePixmap(MI_DISPLAY(mi), lp->pixmaps[shade]); - if (lp->stippledGC != None) - XFreeGC(MI_DISPLAY(mi), lp->stippledGC); - if (lp->oldcells != NULL) - (void) free((void *) lp->oldcells); - if (lp->newcells != NULL) - (void) free((void *) lp->newcells); - free_list(lp); - } + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_loop(MI_DISPLAY(mi), &loops[screen]); (void) free((void *) loops); - loops = NULL; + loops = (loopstruct *) NULL; } if (table != NULL) { (void) free((void *) table); - table = NULL; + table = (unsigned int *) NULL; } } @@ -1224,9 +1447,9 @@ init_loop(ModeInfo * mi) if ((MI_NPIXELS(mi) < COLORS) && (lp->init_bits == 0)) { if (lp->stippledGC == None) { gcv.fill_style = FillOpaqueStippled; - lp->stippledGC = XCreateGC(display, window, GCFillStyle, &gcv); - if (lp->stippledGC == None) { - release_loop(mi); + if ((lp->stippledGC = XCreateGC(display, window, + GCFillStyle, &gcv)) == None) { + free_loop(display, lp); return; } } @@ -1238,10 +1461,6 @@ init_loop(ModeInfo * mi) LOOPBITS(stipples[7], STIPPLESIZE, STIPPLESIZE); LOOPBITS(stipples[8], STIPPLESIZE, STIPPLESIZE); LOOPBITS(stipples[10], STIPPLESIZE, STIPPLESIZE); - if (lp->pixmaps[COLORS - 1] == None) { - release_loop(mi); - return; - } } if (MI_NPIXELS(mi) >= COLORS) { /* Maybe these colors should be randomized */ @@ -1259,21 +1478,17 @@ init_loop(ModeInfo * mi) lp->width = MI_WIDTH(mi); lp->height = MI_HEIGHT(mi); - if (!local_neighbors) { - for (i = 0; i < NEIGHBORKINDS; i++) { - if (neighbors == plots[i]) { - local_neighbors = neighbors; - neighbor_kind = i; - break; - } + if (!local_neighbors) { + for (i = 0; i < NEIGHBORKINDS; i++) { + if (neighbors == plots[i]) { + local_neighbors = neighbors; + break; + } if (i == NEIGHBORKINDS - 1) { - #if 1 local_neighbors = plots[NRAND(NEIGHBORKINDS)]; - neighbor_kind = (local_neighbors == 4) ? 0 : 1; #else local_neighbors = 4; - neighbor_kind = 0; #endif break; } @@ -1284,10 +1499,10 @@ init_loop(ModeInfo * mi) if (local_neighbors == 6) { int nccols, ncrows; - if (lp->width < 4) - lp->width = 4; - if (lp->height < 4) - lp->height = 4; + if (lp->width < 8) + lp->width = 8; + if (lp->height < 8) + lp->height = 8; if (size < -MINSIZE) { lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) / HEX_MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; @@ -1300,11 +1515,11 @@ init_loop(ModeInfo * mi) lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) / HEX_MINGRIDSIZE)); lp->xs = lp->ys; - nccols = MAX(lp->width / lp->xs - 2, HEX_ADAM_LOOPX + 1); - ncrows = MAX(lp->height / lp->ys - 1, HEX_ADAM_LOOPY + 1); + nccols = MAX(lp->width / lp->xs - 2, HEX_MINGRIDSIZE); + ncrows = MAX(lp->height / lp->ys - 1, HEX_MINGRIDSIZE); lp->ncols = nccols / 2; lp->nrows = ncrows / 2; - lp->nrows -= !(lp->nrows & 1); /* Must be odd */ + lp->nrows -= !(lp->nrows & 1); /* Must be odd */ lp->xb = (lp->width - lp->xs * nccols) / 2 + lp->xs; lp->yb = (lp->height - lp->ys * ncrows) / 2 + lp->ys; for (i = 0; i < 6; i++) { @@ -1338,39 +1553,65 @@ init_loop(ModeInfo * mi) if (lp->oldcells != NULL) { (void) free((void *) lp->oldcells); - lp->oldcells = NULL; - } - if ((lp->oldcells = (unsigned char *) calloc(lp->bncols * lp->bnrows, sizeof (unsigned char))) == NULL) { - release_loop(mi); + lp->oldcells = (unsigned char *) NULL; + } + if ((lp->oldcells = (unsigned char *) calloc(lp->bncols * lp->bnrows, + sizeof (unsigned char))) == NULL) { + free_loop(display, lp); return; } if (lp->newcells != NULL) { (void) free((void *) lp->newcells); - lp->newcells = NULL; + lp->newcells = (unsigned char *) NULL; } - if ((lp->newcells = (unsigned char *) calloc(lp->bncols * lp->bnrows, sizeof (unsigned char))) == NULL) { - release_loop(mi); + if ((lp->newcells = (unsigned char *) calloc(lp->bncols * lp->bnrows, + sizeof (unsigned char))) == NULL) { + free_loop(display, lp); return; } - if (init_table()) { + if (!init_table()) { release_loop(mi); return; } + lp->mincol = lp->bncols - 1; + lp->minrow = lp->bnrows - 1; + lp->maxcol = 0; + lp->maxrow = 0; +#ifndef DELAYDEBUGLOOP + { + int flaws = MI_COUNT(mi); + + if (flaws < 0) + flaws = NRAND(-MI_COUNT(mi) + 1); + for (i = 0; i < flaws; i++) { + init_flaw(mi); + } + /* actual flaws might be less since the adam loop done next */ + } +#endif init_adam(mi); } void draw_loop(ModeInfo * mi) { - loopstruct *lp = &loops[MI_SCREEN(mi)]; - int offset, i, j, life = 0; + int offset, i, j; unsigned char *z, *znew; + loopstruct *lp; - if (loops == NULL) { - init_loop(mi); + if (loops == NULL) return; - } + lp = &loops[MI_SCREEN(mi)]; + if (lp->newcells == NULL) + return; + MI_IS_DRAWN(mi) = True; + lp->dead = True; +#ifdef DELAYDEBUGLOOP + if (MI_COUNT(mi) && lp->generation > MI_COUNT(mi)) { + (void) sleep(DELAYDEBUGLOOP); + } +#endif for (j = lp->minrow; j <= lp->maxrow; j++) { for (i = lp->mincol; i <= lp->maxcol; i++) { @@ -1378,9 +1619,10 @@ draw_loop(ModeInfo * mi) z = lp->oldcells + offset; znew = lp->newcells + offset; if (*z != *znew) { + lp->dead = False; *z = *znew; - addtolist(mi, i - lp->bx, j - lp->by, *znew); - life = 1; + if (!addtolist(mi, i - lp->bx, j - lp->by, *znew)) + return; if (i == lp->mincol && i > lp->bx) lp->mincol--; if (j == lp->minrow && j > lp->by) @@ -1393,8 +1635,11 @@ draw_loop(ModeInfo * mi) } } for (i = 0; i < COLORS; i++) - draw_state(mi, i); - if (++lp->generation > MI_CYCLES(mi) /* || !life */) { + if (!draw_state(mi, i)) { + free_loop(MI_DISPLAY(mi), lp); + return; + } + if (++lp->generation > MI_CYCLES(mi) || lp->dead) { init_loop(mi); return; } else @@ -1418,13 +1663,15 @@ draw_loop(ModeInfo * mi) void refresh_loop(ModeInfo * mi) { - loopstruct *lp = &loops[MI_SCREEN(mi)]; + loopstruct *lp; - if (loops == NULL) { - init_loop(mi); + if (loops == NULL) return; - } + lp = &loops[MI_SCREEN(mi)]; + MI_CLEARWINDOW(mi); lp->redrawing = 1; lp->redrawpos = lp->by * lp->ncols + lp->bx; } + +#endif /* MODE_loop */