1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* loop --- Chris Langton's self-producing loops */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)loop.c 4.13 98/10/18 xlockmore";
10 * Copyright (c) 1996 by David Bagley.
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
25 * 18-Oct-98: Started creating a hexagon version, probably will not work
26 * for a while since some work has to go into getting not
27 * only the program to handle the hexagonal data but the loop
28 * has to be "programmed" as well. I suspect it should be easier
29 * than the original since the loop will have six sides to
30 * store its genes (data).
31 * 10-May-97: Compatible with xscreensaver
32 * 15-Nov-95: Coded from Chris Langton's Self-Reproduction in Cellular
33 * Automata Physica 10D 135-144 1984
34 * also used wire.c as a guide.
38 Grid Number of Neigbors
39 ---- ------------------
41 Hexagon 6 (currently in development)
45 * From Steven Levy's Artificial Life
46 * Chris Langton's cellular automata "loops" reproduce in the spirit of life.
47 * Beginning from a single organism, the loops from a colony. As the loops
48 * on the outer fringes reproduce, the inner loops -- blocked by their
49 * daughters -- can no longer produce offspring. These dead progenitors
50 * provide a base for future generations' expansion, much like the formation
51 * of a coral reef. This self-organizing behavior emerges spontaneously,
52 * from the bottom up -- a key characteristic of artificial life.
56 Don't Panic -- When the artificial life tries to leave its petri
57 dish (ie. the screen) it will (usually) die...
58 The loops are short of "real" life because a general purpose Turing
59 machine is not contained in the loop. This is a simplification of
60 von Neumann and Codd's self-producing Turing machine.
61 The data spinning around could be viewed as both its DNA and its internal
66 # define PROGCLASS "loop"
67 # define HACK_INIT init_loop
68 # define HACK_DRAW draw_loop
69 # define loop_opts xlockmore_opts
70 # define DEFAULTS "*delay: 100000 \n" \
75 # define SMOOTH_COLORS
76 # include "xlockmore.h" /* in xscreensaver distribution */
77 #else /* STANDALONE */
78 # include "xlock.h" /* in xlockmore distribution */
79 #endif /* STANDALONE */
84 * neighbors of 0 randomizes between 4 and 6.
90 #endif /* !STANDALONE */
92 ModeSpecOpt loop_opts =
93 {0, NULL, 0, NULL, NULL};
96 ModStruct loop_description =
97 {"loop", "init_loop", "draw_loop", "release_loop",
98 "refresh_loop", "init_loop", NULL, &loop_opts,
99 100000, 1, 1600, -12, 64, 1.0, "",
100 "Shows Langton's self-producing loops", 0, NULL};
104 #define LOOPBITS(n,w,h)\
105 lp->pixmaps[lp->init_bits++]=\
106 XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1)
108 static int local_neighbors = 0;
109 static int neighbor_kind = 0;
112 #define REALCOLORS (COLORS-2)
114 #define REDRAWSTEP 2000 /* How many cells to draw per cycle */
115 #define ADAM_SIZE 8 /* MIN 5 */
117 # define ADAM_LOOPX (ADAM_SIZE+2)
118 # define ADAM_LOOPY (ADAM_SIZE+2)
120 # define ADAM_LOOPX 16
121 # define ADAM_LOOPY 10
123 #define MINGRIDSIZE (3*ADAM_LOOPX)
124 /* TRIA stuff was an attempt to make a triangular lifeform on a
125 hex grid but I got bored. You probably need an additional 7th
126 state for a coherent step by step process of separation and
127 initial stem development.
131 # define HEX_ADAM_SIZE 3 /* MIN 3 */
133 # define HEX_ADAM_SIZE 5 /* MIN 3 */
136 # define HEX_ADAM_LOOPX (2*HEX_ADAM_SIZE+1)
137 # define HEX_ADAM_LOOPY (2*HEX_ADAM_SIZE+1)
139 # define HEX_ADAM_LOOPX 3
140 # define HEX_ADAM_LOOPY 7
142 #define HEX_MINGRIDSIZE (6*HEX_ADAM_LOOPX)
143 #define MINSIZE 5 /* jwz -- really tiny cells don't look good */
144 #define NEIGHBORKINDS 2
146 #define MAXNEIGHBORS 6
148 /* Singly linked list */
149 typedef struct _CellList {
151 struct _CellList *next;
160 int bx, by, bnrows, bncols;
161 int mincol, minrow, maxcol, maxrow;
163 int redrawing, redrawpos;
164 unsigned char *newcells, *oldcells;
166 CellList *cellList[COLORS];
167 unsigned long colors[COLORS];
169 Pixmap pixmaps[COLORS];
175 static loopstruct *loops = NULL;
177 #define TRANSITION(TT,V) V=TT&7;TT>>=3
178 #define TABLE(R,T,L,B) (table[((B)<<9)|((L)<<6)|((T)<<3)|(R)])
179 #define HEX_TABLE(R,T,t,l,b,B) (table[((B)<<15)|((b)<<12)|((l)<<9)|((t)<<6)|((T)<<3)|(R)])
180 #ifdef RAND_RULES /* Hack, see below */
181 #define TABLE_IN(C,R,T,L,B,I) (TABLE(R,T,L,B)&=~(7<<((C)*3)));\
182 (TABLE(R,T,L,B)|=((I)<<((C)*3)))
183 #define HEX_TABLE_IN(C,R,T,t,l,b,B,I) (HEX_TABLE(R,T,t,l,b,B)&=~(7<<((C)*3)));\
184 (HEX_TABLE(R,T,t,l,b,B)|=((I)<<((C)*3)))
186 #define TABLE_IN(C,R,T,L,B,I) (TABLE(R,T,L,B)|=((I)<<((C)*3)))
187 #define HEX_TABLE_IN(C,R,T,t,l,b,B,I) (HEX_TABLE(R,T,t,l,b,B)|=((I)<<((C)*3)))
189 #define TABLE_OUT(C,R,T,L,B) ((TABLE(R,T,L,B)>>((C)*3))&7)
190 #define HEX_TABLE_OUT(C,R,T,t,l,b,B) ((HEX_TABLE(R,T,t,l,b,B)>>((C)*3))&7)
192 static unsigned int *table = NULL; /* 8*8*8*8 = 2^12 = 2^3^4 = 4K */
193 /* 8*8*8*8*8*8 = too big? */
195 static char plots[NEIGHBORKINDS] =
197 4, 6 /* Neighborhoods */
200 static unsigned int transition_table[] =
201 { /* Octal CBLTR->I */
202 /* CBLTRI CBLTRI CBLTRI CBLTRI CBLTRI */
203 0000000, 0025271, 0113221, 0202422, 0301021,
204 0000012, 0100011, 0122244, 0202452, 0301220,
205 0000020, 0100061, 0122277, 0202520, 0302511,
206 0000030, 0100077, 0122434, 0202552, 0401120,
207 0000050, 0100111, 0122547, 0202622, 0401220,
208 0000063, 0100121, 0123244, 0202722, 0401250,
209 0000071, 0100211, 0123277, 0203122, 0402120,
210 0000112, 0100244, 0124255, 0203216, 0402221,
211 0000122, 0100277, 0124267, 0203226, 0402326,
212 0000132, 0100511, 0125275, 0203422, 0402520,
213 0000212, 0101011, 0200012, 0204222, 0403221,
214 0000220, 0101111, 0200022, 0205122, 0500022,
215 0000230, 0101244, 0200042, 0205212, 0500215,
216 0000262, 0101277, 0200071, 0205222, 0500225,
217 0000272, 0102026, 0200122, 0205521, 0500232,
218 0000320, 0102121, 0200152, 0205725, 0500272,
219 0000525, 0102211, 0200212, 0206222, 0500520,
220 0000622, 0102244, 0200222, 0206722, 0502022,
221 0000722, 0102263, 0200232, 0207122, 0502122,
222 0001022, 0102277, 0200242, 0207222, 0502152,
223 0001120, 0102327, 0200250, 0207422, 0502220,
224 0002020, 0102424, 0200262, 0207722, 0502244,
225 0002030, 0102626, 0200272, 0211222, 0502722,
226 0002050, 0102644, 0200326, 0211261, 0512122,
227 0002125, 0102677, 0200423, 0212222, 0512220,
228 0002220, 0102710, 0200517, 0212242, 0512422,
229 0002322, 0102727, 0200522, 0212262, 0512722,
230 0005222, 0105427, 0200575, 0212272, 0600011,
231 0012321, 0111121, 0200722, 0214222, 0600021,
232 0012421, 0111221, 0201022, 0215222, 0602120,
233 0012525, 0111244, 0201122, 0216222, 0612125,
234 0012621, 0111251, 0201222, 0217222, 0612131,
235 0012721, 0111261, 0201422, 0222272, 0612225,
236 0012751, 0111277, 0201722, 0222442, 0700077,
237 0014221, 0111522, 0202022, 0222462, 0701120,
238 0014321, 0112121, 0202032, 0222762, 0701220,
239 0014421, 0112221, 0202052, 0222772, 0701250,
240 0014721, 0112244, 0202073, 0300013, 0702120,
241 0016251, 0112251, 0202122, 0300022, 0702221,
242 0017221, 0112277, 0202152, 0300041, 0702251,
243 0017255, 0112321, 0202212, 0300076, 0702321,
244 0017521, 0112424, 0202222, 0300123, 0702525,
245 0017621, 0112621, 0202272, 0300421, 0702720,
246 0017721, 0112727, 0202321, 0300622
249 static unsigned int hex_transition_table[] =
250 { /* Octal CBbltTR->I */
251 /* CBbltTRI CBbltTRI CBbltTRI CBbltTRI CBbltTRI */
254 000000000, 000000020, 000000220, 000002220, 000022220,
255 011122121, 011121221, 011122221, 011221221,
256 011222221, 011112121, 011112221,
257 020021122, 020002122, 020211222, 021111222,
258 020221122, 020027122, 020020722, 020021022,
260 011122727, 011227227, 010122121, 010222211,
261 021117222, 020112272,
264 010221121, 011721221, 011222277,
265 020111222, 020221172,
268 010212277, 010221221,
273 020002022, 021122172,
275 011122277, 011172121,
276 010212177, 011212277,
280 070121270, 070721220,
281 000112721, 000272211,
282 010022211, 012222277,
283 020072272, 020227122, 020217222,
288 020021072, 020070722,
289 070002072, 070007022,
292 000000070, 000000770, 000072220, 000000270,
293 020110222, 020220272, 020220722,
294 070007071, 070002072, 070007022,
295 000000012, 000000122, 000000212, 001277721,
296 020122072, 020202212,
298 020001122, 020002112,
300 020122022, 020027022, 020070122, 020020122,
303 010227227, 010227277,
310 010022277, 010202177, 010227127,
314 020024122, 020020422,
317 010221241, 010224224,
322 020112242, 021422172,
324 001224221, 001427221,
329 010022244, 010202144, 010224124,
333 040121240, 040421220,
334 000242211, 000112421,
335 020042242, 020214222, 020021422, 020220242, 020024022,
342 001244421, 000000420, 000000440, 000000240, 000000040,
343 020040121, 020021042,
344 040004022, 040004042, 040002042,
346 020011122, 020002112,
353 020224072, 021417222,
359 070207072, 070701220,
364 020021222, 020202272, 020120222, 020221722,
368 020101272, 020272172, 020721422, 020721722,
369 020011222, 020202242,
387 000000000, 000000020, 000000220, 000002220,
388 011212121, 011212221, 011221221, 011222221,
389 020002122, 020021122, 020211122,
391 010221221, 010222121,
392 020002022, 020021022, 020020122, 020112022,
395 020102022, 020202112,
397 000000012, 000000122, 000000212,
399 020001122, 020002112, 020011122,
402 001227221, 001272221, 001272721,
403 012212277, 011222727, 011212727,
404 020021722, 020027122, 020020722, 020027022,
405 020211722, 020202172, 020120272,
406 020271122, 020202172, 020207122, 020217122,
407 020120272, 020210722, 020270722,
408 070212220, 070221220, 070212120,
415 001277721, 000000070, 000000270, 000000720, 000000770,
416 020070122, 020021072,
417 070002072, 070007022, 070007071,
422 010227227, 010222727, 010202727,
423 020172022, 020202712,
425 001224221, 001242221, 001242421,
426 012212244, 011222424, 011212424,
427 020021422, 020024122, 020020422, 020024022,
428 020211422, 020202142, 020120242,
429 020241122, 020202142, 020204122, 020214122,
430 020120242, 020210422, 020240422,
431 040212220, 040221220, 040212120,
438 001244421, 000000040, 000000240, 000000420, 000000440,
439 020040122, 020021042,
441 040004021, 040004042,
446 010224224, 010222424, 010202424,
447 020142022, 020202412,
448 020011722, 020112072, 020172072, 020142072,
452 000210225, 000022015, 000022522,
454 020120525, 020020152, 020005122, 020214255, 020021152,
456 050215222, 050225121,
458 000225220, 001254222,
459 010221250, 011221251, 011225221,
460 020025122, 020152152, 020211252, 020214522, 020511125,
464 000000250, 000000520, 000150220, 000220520, 000222210,
466 010022152, 010251221, 010522121, 011212151, 011221251,
468 020000220, 020002152, 020020220, 020021020, 020022152,
469 020021422, 020022152, 020022522, 020025425, 020050422,
470 020051022, 020051122, 020211122, 020211222, 020215222,
472 050021125, 050021025, 050011125, 051242221,
475 000220250, 000220520, 001227521, 001275221,
476 011257227, 011522727,
477 020002052, 020002752, 020021052, 020057125,
478 050020722, 050027125,
577 Neighborhoods are read as follows (rotations are not listed):
587 static unsigned char self_reproducing_loop[ADAM_LOOPY][ADAM_LOOPX] =
590 {0, 2, 2, 2, 2, 2, 2, 2, 2, 0},
591 {2, 4, 0, 1, 4, 0, 1, 1, 1, 2},
592 {2, 1, 2, 2, 2, 2, 2, 2, 1, 2},
593 {2, 0, 2, 0, 0, 0, 0, 2, 1, 2},
594 {2, 7, 2, 0, 0, 0, 0, 2, 7, 2},
595 {2, 1, 2, 0, 0, 0, 0, 2, 0, 2},
596 {2, 0, 2, 0, 0, 0, 0, 2, 1, 2},
597 {2, 7, 2, 2, 2, 2, 2, 2, 7, 2},
598 {2, 1, 0, 6, 1, 0, 7, 1, 0, 2},
599 {0, 2, 2, 2, 2, 2, 2, 2, 2, 0}
602 static unsigned char hex_self_reproducing_loop[HEX_ADAM_LOOPY][HEX_ADAM_LOOPX] =
605 /* Experimental TRIA5:7x7 */
613 /* Stem cells, only "5" will fully reproduce itself */
615 {2,2,2,2,0,0,0,0,0,0,0,0},
616 {2,1,1,1,2,0,0,0,0,0,0,0},
617 {2,1,2,2,1,2,2,2,2,2,2,0},
618 {2,1,2,0,2,7,1,1,1,1,1,2},
619 {0,2,1,2,2,0,2,2,2,2,2,2},
620 {0,0,2,0,4,1,2,0,0,0,0,0},
621 {0,0,0,2,2,2,2,0,0,0,0,0}
623 {2,2,2,2,2,0,0,0,0,0,0,0,0,0},
624 {2,1,1,1,1,2,0,0,0,0,0,0,0,0},
625 {2,1,2,2,2,1,2,0,0,0,0,0,0,0},
626 {2,1,2,0,0,2,1,2,2,2,2,2,2,0},
627 {2,1,2,0,0,0,2,7,1,1,1,1,1,2},
628 {0,2,1,2,0,0,2,0,2,2,2,2,2,2},
629 {0,0,2,0,2,2,2,1,2,0,0,0,0,0},
630 {0,0,0,2,4,1,0,7,2,0,0,0,0,0},
631 {0,0,0,0,2,2,2,2,2,0,0,0,0,0}
633 {2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0},
634 {2,1,1,1,1,1,2,0,0,0,0,0,0,0,0,0},
635 {2,1,2,2,2,2,1,2,0,0,0,0,0,0,0,0},
636 {2,1,2,0,0,0,2,1,2,0,0,0,0,0,0,0},
637 {2,1,2,0,0,0,0,2,1,2,2,2,2,2,2,0},
638 {2,1,2,0,0,0,0,0,2,7,1,1,1,1,1,2},
639 {0,2,1,2,0,0,0,0,2,0,2,2,2,2,2,2},
640 {0,0,2,0,2,0,0,0,2,1,2,0,0,0,0,0},
641 {0,0,0,2,4,2,2,2,2,7,2,0,0,0,0,0},
642 {0,0,0,0,2,1,0,7,1,0,2,0,0,0,0,0},
643 {0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0}
644 /* test:3x7 (0,4) is blank ... very strange.
645 init_adam seems ok something after that I guess */
653 #else /* this might be better for hexagons, spacewise efficient... */
655 /* Experimental TRIA5:7x7 */
665 {2,2,2,2,2,2,0,0,0,0,0},
666 {2,1,1,7,0,1,2,0,0,0,0},
667 {2,1,2,2,2,2,7,2,0,0,0},
668 {2,1,2,0,0,0,2,0,2,0,0},
669 {2,1,2,0,0,0,0,2,1,2,0},
670 {2,1,2,0,0,0,0,0,2,7,2},
671 {0,2,1,2,0,0,0,0,2,0,2},
672 {0,0,2,1,2,0,0,0,2,1,2},
673 {0,0,0,2,1,2,2,2,2,4,2},
674 {0,0,0,0,2,1,1,1,1,5,2},
675 {0,0,0,0,0,2,2,2,2,2,2}
681 position_of_neighbor(int dir, int *pcol, int *prow)
683 int col = *pcol, row = *prow;
687 if (local_neighbors == 6) {
716 (void) fprintf(stderr, "wrong direction %d\n", dir);
733 (void) fprintf(stderr, "wrong direction %d\n", dir);
741 withinBounds(loopstruct * lp, int col, int row)
743 return (row >= 1 && row < lp->bnrows - 1 &&
744 col >= 1 && col < lp->bncols - 1 - (local_neighbors == 6 && (row % 2)));
748 fillcell(ModeInfo * mi, GC gc, int col, int row)
750 loopstruct *lp = &loops[MI_SCREEN(mi)];
752 if (local_neighbors == 6) {
753 int ccol = 2 * col + !(row & 1), crow = 2 * row;
755 lp->shape.hexagon[0].x = lp->xb + ccol * lp->xs;
756 lp->shape.hexagon[0].y = lp->yb + crow * lp->ys;
757 if (lp->xs == 1 && lp->ys == 1)
758 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
759 lp->shape.hexagon[0].x, lp->shape.hexagon[0].y, 1, 1);
761 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
762 lp->shape.hexagon, 6, Convex, CoordModePrevious);
764 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
765 lp->xb + lp->xs * col, lp->yb + lp->ys * row,
766 lp->xs - (lp->xs > 3), lp->ys - (lp->ys > 3));
771 drawcell(ModeInfo * mi, int col, int row, int state)
773 loopstruct *lp = &loops[MI_SCREEN(mi)];
777 if (MI_NPIXELS(mi) >= COLORS) {
779 XSetForeground(MI_DISPLAY(mi), gc, lp->colors[state]);
781 gcv.stipple = lp->pixmaps[state];
782 gcv.foreground = MI_WHITE_PIXEL(mi);
783 gcv.background = MI_BLACK_PIXEL(mi);
784 XChangeGC(MI_DISPLAY(mi), lp->stippledGC,
785 GCStipple | GCForeground | GCBackground, &gcv);
788 fillcell(mi, gc, col, row);
792 addtolist(ModeInfo * mi, int col, int row, unsigned char state)
794 loopstruct *lp = &loops[MI_SCREEN(mi)];
795 CellList *current = lp->cellList[state];
797 lp->cellList[state] = NULL;
798 if ((lp->cellList[state] = (CellList *) malloc(sizeof (CellList))) == NULL) {
799 lp->cellList[state] = current;
802 lp->cellList[state]->pt.x = col;
803 lp->cellList[state]->pt.y = row;
804 lp->cellList[state]->next = current;
810 print_state(ModeInfo * mi, int state)
812 loopstruct *lp = &loops[MI_SCREEN(mi)];
813 CellList *locallist = lp->cellList[state];
816 (void) printf("state %d\n", state);
818 (void) printf("%d x %d, y %d\n", i,
819 locallist->pt.x, locallist->pt.y);
820 locallist = locallist->next;
828 free_state(loopstruct * lp, int state)
832 while (lp->cellList[state]) {
833 current = lp->cellList[state];
834 lp->cellList[state] = lp->cellList[state]->next;
835 (void) free((void *) current);
837 lp->ncells[state] = 0;
841 draw_state(ModeInfo * mi, int state)
843 loopstruct *lp = &loops[MI_SCREEN(mi)];
846 CellList *current = lp->cellList[state];
848 if (MI_NPIXELS(mi) >= COLORS) {
850 XSetForeground(MI_DISPLAY(mi), gc, lp->colors[state]);
852 gcv.stipple = lp->pixmaps[state];
853 gcv.foreground = MI_WHITE_PIXEL(mi);
854 gcv.background = MI_BLACK_PIXEL(mi);
855 XChangeGC(MI_DISPLAY(mi), lp->stippledGC,
856 GCStipple | GCForeground | GCBackground, &gcv);
860 if (local_neighbors == 6) { /* Draw right away, slow */
862 int col, row, ccol, crow;
866 ccol = 2 * col + !(row & 1), crow = 2 * row;
867 lp->shape.hexagon[0].x = lp->xb + ccol * lp->xs;
868 lp->shape.hexagon[0].y = lp->yb + crow * lp->ys;
869 if (lp->xs == 1 && lp->ys == 1)
870 XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
871 lp->shape.hexagon[0].x, lp->shape.hexagon[0].y, 1, 1);
873 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
874 lp->shape.hexagon, 6, Convex, CoordModePrevious);
875 current = current->next;
878 /* Take advantage of XFillRectangles */
879 XRectangle *rects = NULL;
882 /* Create Rectangle list from part of the cellList */
883 if ((rects = (XRectangle *) malloc(lp->ncells[state] * sizeof (XRectangle))) == NULL) {
888 rects[nrects].x = lp->xb + current->pt.x * lp->xs;
889 rects[nrects].y = lp->yb + current->pt.y * lp->ys;
890 rects[nrects].width = lp->xs - (lp->xs > 3);
891 rects[nrects].height = lp->ys - (lp->ys > 3);
892 current = current->next;
895 /* Finally get to draw */
896 XFillRectangles(MI_DISPLAY(mi), MI_WINDOW(mi), gc, rects, nrects);
897 /* Free up rects list and the appropriate part of the cellList */
898 (void) free((void *) rects);
900 free_state(lp, state);
901 XFlush(MI_DISPLAY(mi));
909 unsigned int tt, c, n[MAXNEIGHBORS], i;
911 int size_transition_table = sizeof (transition_table) /
912 sizeof (unsigned int);
913 int size_hex_transition_table = sizeof (hex_transition_table) /
914 sizeof (unsigned int);
916 for (j = 0; j < local_neighbors; j++)
919 if ((table = (unsigned int *) calloc(mult, sizeof (unsigned int))) == NULL) {
924 /* Here I was interested to see what happens when it hits a wall....
925 Rules not normally used take over... takes too much time though */
927 for (j = 0; j < mult; j++) {
928 for (k = 0; k < 8; k++)
929 table[j] |= (unsigned int) ((unsigned int) (NRAND(8)) << (k * 3));
933 if (local_neighbors == 6) {
934 for (j = 0; j < size_hex_transition_table; j++) {
935 tt = hex_transition_table[j];
937 for (k = 0; k < local_neighbors; k++) {
938 TRANSITION(tt, n[k]);
941 HEX_TABLE_IN(c, n[0], n[1], n[2], n[3], n[4], n[5], i);
942 HEX_TABLE_IN(c, n[1], n[2], n[3], n[4], n[5], n[0], i);
943 HEX_TABLE_IN(c, n[2], n[3], n[4], n[5], n[0], n[1], i);
944 HEX_TABLE_IN(c, n[3], n[4], n[5], n[0], n[1], n[2], i);
945 HEX_TABLE_IN(c, n[4], n[5], n[0], n[1], n[2], n[3], i);
946 HEX_TABLE_IN(c, n[5], n[0], n[1], n[2], n[3], n[4], i);
949 for (j = 0; j < size_transition_table; j++) {
950 tt = transition_table[j];
952 for (k = 0; k < local_neighbors; k++) {
953 TRANSITION(tt, n[k]);
956 TABLE_IN(c, n[0], n[1], n[2], n[3], i);
957 TABLE_IN(c, n[1], n[2], n[3], n[0], i);
958 TABLE_IN(c, n[2], n[3], n[0], n[1], i);
959 TABLE_IN(c, n[3], n[0], n[1], n[2], i);
967 init_adam(ModeInfo * mi)
969 loopstruct *lp = &loops[MI_SCREEN(mi)];
970 XPoint start, dirx, diry;
973 if (local_neighbors == 6) {
979 start.x = (lp->bncols - HEX_ADAM_LOOPX / 2) / 2;
980 start.y = (lp->bnrows - HEX_ADAM_LOOPY) / 2;
981 lp->mincol = start.x - 2;
982 lp->minrow = start.y - 1;
983 lp->maxcol = start.x + HEX_ADAM_LOOPX + 1;
984 lp->maxrow = start.y + HEX_ADAM_LOOPY + 1;
985 for (j = 0; j < HEX_ADAM_LOOPY; j++) {
986 for (i = 0; i < HEX_ADAM_LOOPX; i++) {
987 k = (((lp->bnrows / 2 + HEX_ADAM_LOOPY / 2) % 2) ? -j / 2 : -(j + 1) / 2);
988 lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] =
989 hex_self_reproducing_loop[j][i];
994 start.x = (lp->bncols - (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) / 2;
995 start.y = (lp->bnrows - HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2;
996 lp->mincol = start.x - 1;
997 lp->minrow = start.y - HEX_ADAM_LOOPX;
998 lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1;
999 lp->maxrow = start.y + HEX_ADAM_LOOPY + 1;
1000 for (j = 0; j < HEX_ADAM_LOOPY; j++) {
1001 for (i = 0; i < HEX_ADAM_LOOPX; i++) {
1002 k = (((lp->bnrows / 2 + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) % 2)
1003 ? -(i + j + 1) / 2 : -(i + j) / 2);
1004 lp->newcells[(start.y + j - i) * lp->bncols + start.x + i + j + k] =
1005 hex_self_reproducing_loop[j][i];
1010 start.x = (lp->bncols - HEX_ADAM_LOOPY / 2) / 2;
1011 start.y = (lp->bnrows - HEX_ADAM_LOOPX) / 2;
1012 lp->mincol = start.x - 2;
1013 lp->minrow = start.y - 1;
1014 lp->maxcol = start.x + HEX_ADAM_LOOPY + 1;
1015 lp->maxrow = start.y + HEX_ADAM_LOOPX + 1;
1016 for (j = 0; j < HEX_ADAM_LOOPX; j++) {
1017 for (i = 0; i < HEX_ADAM_LOOPY; i++) {
1018 k = (((lp->bnrows / 2 + HEX_ADAM_LOOPX / 2) % 2) ? -(HEX_ADAM_LOOPX - j - 1) / 2 : -(HEX_ADAM_LOOPX - j) / 2);
1019 lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] =
1020 hex_self_reproducing_loop[i][HEX_ADAM_LOOPX - j - 1];
1025 start.x = (lp->bncols - HEX_ADAM_LOOPX / 2) / 2;
1026 start.y = (lp->bnrows - HEX_ADAM_LOOPY) / 2;
1027 lp->mincol = start.x - 1, lp->minrow = start.y - 1;
1028 lp->maxcol = start.x + HEX_ADAM_LOOPX + 1, lp->maxrow = start.y + HEX_ADAM_LOOPY + 1;
1029 for (j = 0; j < HEX_ADAM_LOOPY; j++) {
1030 for (i = 0; i < HEX_ADAM_LOOPX; i++) {
1031 k = (((lp->bnrows / 2 + HEX_ADAM_LOOPY / 2) % 2) ? -j / 2 : -(j + 1) / 2);
1032 lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] =
1033 hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1];
1038 start.x = (lp->bncols - (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) / 2;
1039 start.y = (lp->bnrows - HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2;
1040 lp->mincol = start.x - 1;
1041 lp->minrow = start.y - HEX_ADAM_LOOPX;
1042 lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1;
1043 lp->maxrow = start.y + HEX_ADAM_LOOPY + 1;
1044 for (j = 0; j < HEX_ADAM_LOOPY; j++) {
1045 for (i = 0; i < HEX_ADAM_LOOPX; i++) {
1046 k = (((lp->bnrows / 2 + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) % 2)
1047 ? -(i + j + 1) / 2 : -(i + j) / 2);
1048 lp->newcells[(start.y + j - i) * lp->bncols + start.x + i + j + k] =
1049 hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1];
1054 start.x = (lp->bncols - HEX_ADAM_LOOPY / 2) / 2;
1055 start.y = (lp->bnrows - HEX_ADAM_LOOPX) / 2;
1056 lp->mincol = start.x - 2;
1057 lp->minrow = start.y - 1;
1058 lp->maxcol = start.x + HEX_ADAM_LOOPY + 1;
1059 lp->maxrow = start.y + HEX_ADAM_LOOPX + 1;
1060 for (j = 0; j < HEX_ADAM_LOOPX; j++) {
1061 for (i = 0; i < HEX_ADAM_LOOPY; i++) {
1062 k = (((lp->bnrows / 2 + HEX_ADAM_LOOPX / 2) % 2) ? -(HEX_ADAM_LOOPX - j - 1) / 2 : -(HEX_ADAM_LOOPX - j) / 2);
1063 lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] =
1064 hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][j];
1070 /* printf ("s %d s %d \n", start.x, start.y); */
1071 printf ("%d %d %d %d %d\t",
1072 start.x + i + ((lp->bnrows / 2 % 2) ? -j / 2 : -(j + 1) / 2) - lp->bx,
1073 start.y + j - lp->by, i, j, hex_self_reproducing_loop[j][i]);
1074 /* Draw right away */
1075 drawcell(mi, start.x + i + ((lp->bnrows / 2 % 2) ? -j / 2 : -(j + 1) / 2) - lp->bx,
1076 start.y + j - lp->by,
1077 hex_self_reproducing_loop[j][i]);
1088 start.x = (lp->bncols - ADAM_LOOPX) / 2;
1089 start.y = (lp->bnrows - ADAM_LOOPY) / 2;
1090 dirx.x = 1, dirx.y = 0;
1091 diry.x = 0, diry.y = 1;
1092 lp->mincol = start.x, lp->minrow = start.y;
1093 lp->maxcol = start.x + ADAM_LOOPX, lp->maxrow = start.y + ADAM_LOOPY;
1096 start.x = (lp->bncols + ADAM_LOOPY) / 2;
1097 start.y = (lp->bnrows - ADAM_LOOPX) / 2;
1098 dirx.x = 0, dirx.y = 1;
1099 diry.x = -1, diry.y = 0;
1100 lp->mincol = start.x - ADAM_LOOPY, lp->minrow = start.y;
1101 lp->maxcol = start.x, lp->maxrow = start.y + ADAM_LOOPX;
1104 start.x = (lp->bncols + ADAM_LOOPX) / 2;
1105 start.y = (lp->bnrows + ADAM_LOOPY) / 2;
1106 dirx.x = -1, dirx.y = 0;
1107 diry.x = 0, diry.y = -1;
1108 lp->mincol = start.x - ADAM_LOOPX, lp->minrow = start.y - ADAM_LOOPY;
1109 lp->maxcol = start.x, lp->maxrow = start.y;
1112 start.x = (lp->bncols - ADAM_LOOPY) / 2;
1113 start.y = (lp->bnrows + ADAM_LOOPX) / 2;
1114 dirx.x = 0, dirx.y = -1;
1115 diry.x = 1, diry.y = 0;
1116 lp->mincol = start.x, lp->minrow = start.y - ADAM_LOOPX;
1117 lp->maxcol = start.x + ADAM_LOOPY, lp->maxrow = start.y;
1120 for (j = 0; j < ADAM_LOOPY; j++)
1121 for (i = 0; i < ADAM_LOOPX; i++)
1122 lp->newcells[(start.y + dirx.y * i + diry.y * j) * lp->bncols +
1123 start.x + dirx.x * i + diry.x * j] =
1124 self_reproducing_loop[j][i];
1126 /* Draw right away */
1127 drawcell(mi, start.x + dirx.x * i + diry.x * j - lp->bx,
1128 start.y + dirx.y * i + diry.y * j - lp->by,
1129 self_reproducing_loop[j][i]);
1136 do_gen(loopstruct * lp)
1140 unsigned int n[MAXNEIGHBORS];
1143 #define LOC(X, Y) (*(lp->oldcells + (X) + ((Y) * lp->bncols)))
1145 for (j = lp->minrow; j <= lp->maxrow; j++) {
1146 for (i = lp->mincol; i <= lp->maxcol; i++) {
1147 z = lp->newcells + i + j * lp->bncols;
1149 for (k = 0; k < local_neighbors; k++) {
1150 int newi = i, newj = j;
1152 position_of_neighbor(k * ANGLES / local_neighbors, &newi, &newj);
1154 if (withinBounds(lp, newi, newj)) {
1155 n[k] = LOC(newi, newj);
1158 if (local_neighbors == 6) {
1159 *z = HEX_TABLE_OUT(c, n[0], n[1], n[2], n[3], n[4], n[5]);
1161 *z = TABLE_OUT(c, n[0], n[1], n[2], n[3]);
1168 free_list(loopstruct * lp)
1172 for (state = 0; state < COLORS; state++)
1173 free_state(lp, state);
1177 release_loop(ModeInfo * mi)
1179 if (loops != NULL) {
1182 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1183 loopstruct *lp = &loops[screen];
1186 for (shade = 0; shade < lp->init_bits; shade++)
1187 if (lp->pixmaps[shade] != None)
1188 XFreePixmap(MI_DISPLAY(mi), lp->pixmaps[shade]);
1189 if (lp->stippledGC != None)
1190 XFreeGC(MI_DISPLAY(mi), lp->stippledGC);
1191 if (lp->oldcells != NULL)
1192 (void) free((void *) lp->oldcells);
1193 if (lp->newcells != NULL)
1194 (void) free((void *) lp->newcells);
1197 (void) free((void *) loops);
1200 if (table != NULL) {
1201 (void) free((void *) table);
1207 init_loop(ModeInfo * mi)
1209 Display *display = MI_DISPLAY(mi);
1210 Window window = MI_WINDOW(mi);
1211 int i, size = MI_SIZE(mi);
1215 if (loops == NULL) {
1216 if ((loops = (loopstruct *) calloc(MI_NUM_SCREENS(mi),
1217 sizeof (loopstruct))) == NULL)
1220 lp = &loops[MI_SCREEN(mi)];
1224 if ((MI_NPIXELS(mi) < COLORS) && (lp->init_bits == 0)) {
1225 if (lp->stippledGC == None) {
1226 gcv.fill_style = FillOpaqueStippled;
1227 lp->stippledGC = XCreateGC(display, window, GCFillStyle, &gcv);
1228 if (lp->stippledGC == None) {
1233 LOOPBITS(stipples[0], STIPPLESIZE, STIPPLESIZE);
1234 LOOPBITS(stipples[2], STIPPLESIZE, STIPPLESIZE);
1235 LOOPBITS(stipples[3], STIPPLESIZE, STIPPLESIZE);
1236 LOOPBITS(stipples[4], STIPPLESIZE, STIPPLESIZE);
1237 LOOPBITS(stipples[6], STIPPLESIZE, STIPPLESIZE);
1238 LOOPBITS(stipples[7], STIPPLESIZE, STIPPLESIZE);
1239 LOOPBITS(stipples[8], STIPPLESIZE, STIPPLESIZE);
1240 LOOPBITS(stipples[10], STIPPLESIZE, STIPPLESIZE);
1241 if (lp->pixmaps[COLORS - 1] == None) {
1246 if (MI_NPIXELS(mi) >= COLORS) {
1247 /* Maybe these colors should be randomized */
1248 lp->colors[0] = MI_BLACK_PIXEL(mi);
1249 lp->colors[1] = MI_PIXEL(mi, 0); /* RED */
1250 lp->colors[5] = MI_PIXEL(mi, MI_NPIXELS(mi) / REALCOLORS); /* YELLOW */
1251 lp->colors[4] = MI_PIXEL(mi, 2 * MI_NPIXELS(mi) / REALCOLORS); /* GREEN */
1252 lp->colors[6] = MI_PIXEL(mi, 3 * MI_NPIXELS(mi) / REALCOLORS); /* CYAN */
1253 lp->colors[2] = MI_PIXEL(mi, 4 * MI_NPIXELS(mi) / REALCOLORS); /* BLUE */
1254 lp->colors[3] = MI_PIXEL(mi, 5 * MI_NPIXELS(mi) / REALCOLORS); /* MAGENTA */
1255 lp->colors[7] = MI_WHITE_PIXEL(mi);
1259 lp->width = MI_WIDTH(mi);
1260 lp->height = MI_HEIGHT(mi);
1262 if (!local_neighbors) {
1263 for (i = 0; i < NEIGHBORKINDS; i++) {
1264 if (neighbors == plots[i]) {
1265 local_neighbors = neighbors;
1269 if (i == NEIGHBORKINDS - 1) {
1272 local_neighbors = plots[NRAND(NEIGHBORKINDS)];
1273 neighbor_kind = (local_neighbors == 4) ? 0 : 1;
1275 local_neighbors = 4;
1284 if (local_neighbors == 6) {
1291 if (size < -MINSIZE) {
1292 lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) /
1293 HEX_MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1294 } else if (size < MINSIZE) {
1296 lp->ys = MAX(MINSIZE, MIN(lp->width, lp->height) / HEX_MINGRIDSIZE);
1300 lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) /
1303 nccols = MAX(lp->width / lp->xs - 2, HEX_ADAM_LOOPX + 1);
1304 ncrows = MAX(lp->height / lp->ys - 1, HEX_ADAM_LOOPY + 1);
1305 lp->ncols = nccols / 2;
1306 lp->nrows = ncrows / 2;
1307 lp->nrows -= !(lp->nrows & 1); /* Must be odd */
1308 lp->xb = (lp->width - lp->xs * nccols) / 2 + lp->xs;
1309 lp->yb = (lp->height - lp->ys * ncrows) / 2 + lp->ys;
1310 for (i = 0; i < 6; i++) {
1311 lp->shape.hexagon[i].x = (lp->xs - 1) * hexagonUnit[i].x;
1312 lp->shape.hexagon[i].y = ((lp->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
1315 if (size < -MINSIZE)
1316 lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) /
1317 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1318 else if (size < MINSIZE) {
1320 lp->ys = MAX(MINSIZE, MIN(lp->width, lp->height) / MINGRIDSIZE);
1324 lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) /
1327 lp->ncols = MAX(lp->width / lp->xs, ADAM_LOOPX + 1);
1328 lp->nrows = MAX(lp->height / lp->ys, ADAM_LOOPX + 1);
1329 lp->xb = (lp->width - lp->xs * lp->ncols) / 2;
1330 lp->yb = (lp->height - lp->ys * lp->nrows) / 2;
1334 lp->bncols = lp->ncols + 2 * lp->bx;
1335 lp->bnrows = lp->nrows + 2 * lp->by;
1339 if (lp->oldcells != NULL) {
1340 (void) free((void *) lp->oldcells);
1341 lp->oldcells = NULL;
1343 if ((lp->oldcells = (unsigned char *) calloc(lp->bncols * lp->bnrows, sizeof (unsigned char))) == NULL) {
1347 if (lp->newcells != NULL) {
1348 (void) free((void *) lp->newcells);
1349 lp->newcells = NULL;
1351 if ((lp->newcells = (unsigned char *) calloc(lp->bncols * lp->bnrows, sizeof (unsigned char))) == NULL) {
1363 draw_loop(ModeInfo * mi)
1365 loopstruct *lp = &loops[MI_SCREEN(mi)];
1366 int offset, i, j, life = 0;
1367 unsigned char *z, *znew;
1369 if (loops == NULL) {
1373 MI_IS_DRAWN(mi) = True;
1375 for (j = lp->minrow; j <= lp->maxrow; j++) {
1376 for (i = lp->mincol; i <= lp->maxcol; i++) {
1377 offset = j * lp->bncols + i;
1378 z = lp->oldcells + offset;
1379 znew = lp->newcells + offset;
1382 addtolist(mi, i - lp->bx, j - lp->by, *znew);
1384 if (i == lp->mincol && i > lp->bx)
1386 if (j == lp->minrow && j > lp->by)
1388 if (i == lp->maxcol && i < lp->bncols - 2 * lp->bx)
1390 if (j == lp->maxrow && j < lp->bnrows - 2 * lp->by)
1395 for (i = 0; i < COLORS; i++)
1397 if (++lp->generation > MI_CYCLES(mi) /* || !life */) {
1403 if (lp->redrawing) {
1404 for (i = 0; i < REDRAWSTEP; i++) {
1405 if ((*(lp->oldcells + lp->redrawpos))) {
1406 drawcell(mi, lp->redrawpos % lp->bncols - lp->bx,
1407 lp->redrawpos / lp->bncols - lp->by,
1408 *(lp->oldcells + lp->redrawpos));
1410 if (++(lp->redrawpos) >= lp->bncols * (lp->bnrows - lp->bx)) {
1419 refresh_loop(ModeInfo * mi)
1421 loopstruct *lp = &loops[MI_SCREEN(mi)];
1423 if (loops == NULL) {
1429 lp->redrawpos = lp->by * lp->ncols + lp->bx;