1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* loop --- Chris Langton's self-producing loops */
3 
4 #if 0
5 static const char sccsid[] = "@(#)loop.c	5.01 2000/03/15 xlockmore";
6 #endif
7 
8 /*-
9  * Copyright (c) 1996 by David Bagley.
10  *
11  * Permission to use, copy, modify, and distribute this software and its
12  * documentation for any purpose and without fee is hereby granted,
13  * provided that the above copyright notice appear in all copies and that
14  * both that copyright notice and this permission notice appear in
15  * supporting documentation.
16  *
17  * This file is provided AS IS with no warranties of any kind.  The author
18  * shall have no liability with respect to the infringement of copyrights,
19  * trade secrets or any patents by this file or any part thereof.  In no
20  * event will the author be liable for any lost revenue or profits or
21  * other special, indirect and consequential damages.
22  *
23  * Revision History:
24  * 15-Mar-2001: Added some flaws, random blue wall spots, to liven it up.
25  *              This mod seems to expose a bug where hexagons are erased
26  *              for no apparent reason.
27  * 01-Nov-2000: Allocation checks
28  * 16-Jun-2000: Fully coded the hexagonal rules.  (Rules that end up in
29  *              state zero were not bothered with since a calloc was used
30  *              to set non-explicit rules to zero.  This allows the
31  *              compile-time option RAND_RULES to work here (at least to
32  *              generation 540).)
33  *              Also added compile-time option DELAYDEBUGLOOP for debugging
34  *              life form.  This also turns off the random initial direction
35  *              of the loop.  Set DELAYDEBUGLOOP to be 10 and use with
36  *              something like this:
37  *       xlock -mode loop -neighbors 6 -size 5 -delay 1 -count 540 -nolock
38  * 18-Oct-1998: Started creating a hexagon version.
39  *              It proved not that difficult because I used Langton's Loop
40  *              as a guide, hexagons have more neighbors so there is more
41  *              freedom to program, and the loop will has six sides to
42  *              store its genes (data).
43  *              (Soon after this a triangular version with neighbors = 6
44  *              was attempted but was unsuccessful).
45  * 10-May-1997: Compatible with xscreensaver
46  * 15-Nov-1995: Coded from Chris Langton's Self-Reproduction in Cellular
47  *              Automata Physica 10D 135-144 1984, also used wire.c as a
48  *              guide.
49  */
50 
51 /*-
52   Grid     Number of Neighbors
53   ----     ------------------
54   Square   4
55   Hexagon  6  (currently in development)
56 */
57 
58 /*-
59  * From Steven Levy's Artificial Life
60  * Chris Langton's cellular automata "loops" reproduce in the spirit of life.
61  * Beginning from a single organism, the loops from a colony.  As the loops
62  * on the outer fringes reproduce, the inner loops -- blocked by their
63  * daughters -- can no longer produce offspring.  These dead progenitors
64  * provide a base for future generations' expansion, much like the formation
65  * of a coral reef.  This self-organizing behavior emerges spontaneously,
66  * from the bottom up -- a key characteristic of artificial life.
67  */
68 
69 /*-
70    Don't Panic  --  When the artificial life tries to leave its petri
71    dish (ie. the screen) it will (usually) die...
72    The loops are short of "real" life because a general purpose Turing
73    machine is not contained in the loop.  This is a simplification of
74    von Neumann and Codd's self-producing Turing machine.
75    The data spinning around could be viewed as both its DNA and its internal
76    clock.  The program can be initalized to have the loop spin both ways...
77    but only one way around will work for a given rule.  An open question (at
78    least to me): Is handedness a requirement for (artificial) life?  Here
79    there is handedness at both the initial condition and the transition rule.
80  */
81 
82 #ifndef HAVE_JWXYZ
83 # define DO_STIPPLE
84 #endif
85 
86 #ifdef STANDALONE
87 # define MODE_loop
88 # define DEFAULTS	"*delay:   100000 \n" \
89 					"*count:   -5     \n" \
90 					"*cycles:  1600   \n" \
91 					"*size:    -12    \n" \
92 					"*ncolors: 15     \n" \
93 					"*fpsSolid: true     \n" \
94 					"*ignoreRotation: True \n" \
95 					".lowrez: True \n" \
96 
97 # define reshape_loop 0
98 # define loop_handle_event 0
99 # define UNIFORM_COLORS
100 # include "xlockmore.h"		/* in xscreensaver distribution */
101 #else /* STANDALONE */
102 # include "xlock.h"		/* in xlockmore distribution */
103 #endif /* STANDALONE */
104 #include "automata.h"
105 
106 #ifdef MODE_loop
107 
108 /*-
109  * neighbors of 0 randomizes between 4 and 6.
110  */
111 #define DEF_NEIGHBORS  "0"      /* choose random value */
112 
113 static int  neighbors;
114 
115 static XrmOptionDescRec opts[] =
116 {
117 	{"-neighbors", ".loop.neighbors", XrmoptionSepArg, 0}
118 };
119 
120 static argtype vars[] =
121 {
122 	{&neighbors, "neighbors", "Neighbors", DEF_NEIGHBORS, t_Int}
123 };
124 
125 static OptionStruct desc[] =
126 {
127 	{"-neighbors num", "squares 4 or hexagons 6"}
128 };
129 
130 ENTRYPOINT ModeSpecOpt loop_opts =
131 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
132 
133 
134 #ifdef USE_MODULES
135 ModStruct   loop_description =
136 {"loop", "init_loop", "draw_loop", "release_loop",
137  "refresh_loop", "init_loop", "free_loop", &loop_opts,
138  100000, 5, 1600, -12, 64, 1.0, "",
139  "Shows Langton's self-producing loops", 0, NULL};
140 
141 #endif
142 
143 #define LOOPBITS(n,w,h)\
144   if ((lp->pixmaps[lp->init_bits]=\
145   XCreatePixmapFromBitmapData(MI_DISPLAY(mi),window,(char *)n,w,h,1,0,1))==None){\
146   free_loop(mi); return;} else {lp->init_bits++;}
147 
148 static int  local_neighbors = 0;
149 
150 #if 0
151 /* Used to fast forward to troubled generations, mainly used for debugging.
152    -delay 1 -count 170 -neighbors 6  # divisions starts
153    540 first cell collision
154    1111 mutant being born from 2 parents
155    1156 mutant born
156  */
157 #define DELAYDEBUGLOOP 10
158 #endif
159 
160 #define COLORS 8
161 #define REALCOLORS (COLORS-2)
162 #define MINLOOPS 1
163 #define REDRAWSTEP 2000		/* How many cells to draw per cycle */
164 #define ADAM_SIZE 8 /* MIN 5 */
165 #if 1
166 #define ADAM_LOOPX  (ADAM_SIZE+2)
167 #define ADAM_LOOPY  (ADAM_SIZE+2)
168 #else
169 #define ADAM_LOOPX 16
170 #define ADAM_LOOPY 10
171 #endif
172 #define MINGRIDSIZE (3*ADAM_LOOPX)
173 #if 0
174 /* TRIA stuff was an attempt to make a triangular lifeform on a
175    hexagonal grid but I got bored.  You may need an additional 7th
176    state for a coherent step by step process of cell separation and
177    initial stem development.
178  */
179 #define TRIA 1
180 #endif
181 #ifdef TRIA
182 #define HEX_ADAM_SIZE 3 /* MIN 3 */
183 #else
184 #define HEX_ADAM_SIZE 5 /* MIN 3 */
185 #endif
186 #if 1
187 #define HEX_ADAM_LOOPX (2*HEX_ADAM_SIZE+1)
188 #define HEX_ADAM_LOOPY (2*HEX_ADAM_SIZE+1)
189 #else
190 #define HEX_ADAM_LOOPX 3
191 #define HEX_ADAM_LOOPY 7
192 #endif
193 #define HEX_MINGRIDSIZE (6*HEX_ADAM_LOOPX)
194 /* #define MINSIZE ((MI_NPIXELS(mi)>=COLORS)?1:(2+(local_neighbors==6))) */
195 #define MINSIZE 5
196 #define NEIGHBORKINDS 2
197 #define ANGLES 360
198 #define MAXNEIGHBORS 6
199 
200 /* Singly linked list */
201 typedef struct _CellList {
202 	XPoint      pt;
203 	struct _CellList *next;
204 } CellList;
205 
206 typedef struct {
207 	int         init_bits;
208 	int         generation;
209 	int         xs, ys;
210 	int         xb, yb;
211 	int         nrows, ncols;
212 	int         bx, by, bnrows, bncols;
213 	int         mincol, minrow, maxcol, maxrow;
214 	int         width, height;
215 	int         redrawing, redrawpos;
216 	Bool        dead, clockwise;
217 	unsigned char *newcells, *oldcells;
218 	int         ncells[COLORS];
219 	CellList   *cellList[COLORS];
220 	unsigned long colors[COLORS];
221 	GC          stippledGC;
222 	Pixmap      pixmaps[COLORS];
223 	union {
224 		XPoint      hexagon[6];
225 	} shape;
226 } loopstruct;
227 
228 static loopstruct *loops = (loopstruct *) NULL;
229 
230 #define TRANSITION(TT,V) V=TT&7;TT>>=3
231 #define FINALTRANSITION(TT,V) V=TT&7
232 #define TABLE(R,T,L,B) (table[((B)<<9)|((L)<<6)|((T)<<3)|(R)])
233 #define HEX_TABLE(R,T,t,l,b,B) (table[((B)<<15)|((b)<<12)|((l)<<9)|((t)<<6)|((T)<<3)|(R)])
234 
235 #if 0
236 /* Instead of setting "unused" state rules to zero it randomizes them.
237    These rules take over when something unexpected happens... like when a
238    cell hits a wall (the end of the screen).
239  */
240 #define RAND_RULES
241 #endif
242 
243 #ifdef RAND_RULES
244 #define TABLE_IN(C,R,T,L,B,I) (TABLE(R,T,L,B)&=~(7<<((C)*3)));\
245 (TABLE(R,T,L,B)|=((I)<<((C)*3)))
246 #define HEX_TABLE_IN(C,R,T,t,l,b,B,I) (HEX_TABLE(R,T,t,l,b,B)&=~(7<<((C)*3)));\
247 (HEX_TABLE(R,T,t,l,b,B)|=((I)<<((C)*3)))
248 #else
249 #define TABLE_IN(C,R,T,L,B,I) (TABLE(R,T,L,B)|=((I)<<((C)*3)))
250 #define HEX_TABLE_IN(C,R,T,t,l,b,B,I) (HEX_TABLE(R,T,t,l,b,B)|=((I)<<((C)*3)))
251 #endif
252 #define TABLE_OUT(C,R,T,L,B) ((TABLE(R,T,L,B)>>((C)*3))&7)
253 #define HEX_TABLE_OUT(C,R,T,t,l,b,B) ((HEX_TABLE(R,T,t,l,b,B)>>((C)*3))&7)
254 
255 static unsigned int *table = (unsigned int *) NULL;
256   /* square:  8*8*8*8     = 2^12 = 2^3^4 = 4096 */
257   /* hexagon: 8*8*8*8*8*8 = 2^18 = 2^3^6 = 262144 = too big? */
258 
259 static char plots[NEIGHBORKINDS] =
260 {
261   4, 6 /* Neighborhoods */
262 };
263 
264 static unsigned int transition_table[] =
265 {				/* Octal  CBLTR->I */
266   /* CBLTRI   CBLTRI   CBLTRI   CBLTRI   CBLTRI */
267     0000000, 0025271, 0113221, 0202422, 0301021,
268     0000012, 0100011, 0122244, 0202452, 0301220,
269     0000020, 0100061, 0122277, 0202520, 0302511,
270     0000030, 0100077, 0122434, 0202552, 0401120,
271     0000050, 0100111, 0122547, 0202622, 0401220,
272     0000063, 0100121, 0123244, 0202722, 0401250,
273     0000071, 0100211, 0123277, 0203122, 0402120,
274     0000112, 0100244, 0124255, 0203216, 0402221,
275     0000122, 0100277, 0124267, 0203226, 0402326,
276     0000132, 0100511, 0125275, 0203422, 0402520,
277     0000212, 0101011, 0200012, 0204222, 0403221,
278     0000220, 0101111, 0200022, 0205122, 0500022,
279     0000230, 0101244, 0200042, 0205212, 0500215,
280     0000262, 0101277, 0200071, 0205222, 0500225,
281     0000272, 0102026, 0200122, 0205521, 0500232,
282     0000320, 0102121, 0200152, 0205725, 0500272,
283     0000525, 0102211, 0200212, 0206222, 0500520,
284     0000622, 0102244, 0200222, 0206722, 0502022,
285     0000722, 0102263, 0200232, 0207122, 0502122,
286     0001022, 0102277, 0200242, 0207222, 0502152,
287     0001120, 0102327, 0200250, 0207422, 0502220,
288     0002020, 0102424, 0200262, 0207722, 0502244,
289     0002030, 0102626, 0200272, 0211222, 0502722,
290     0002050, 0102644, 0200326, 0211261, 0512122,
291     0002125, 0102677, 0200423, 0212222, 0512220,
292     0002220, 0102710, 0200517, 0212242, 0512422,
293     0002322, 0102727, 0200522, 0212262, 0512722,
294     0005222, 0105427, 0200575, 0212272, 0600011,
295     0012321, 0111121, 0200722, 0214222, 0600021,
296     0012421, 0111221, 0201022, 0215222, 0602120,
297     0012525, 0111244, 0201122, 0216222, 0612125,
298     0012621, 0111251, 0201222, 0217222, 0612131,
299     0012721, 0111261, 0201422, 0222272, 0612225,
300     0012751, 0111277, 0201722, 0222442, 0700077,
301     0014221, 0111522, 0202022, 0222462, 0701120,
302     0014321, 0112121, 0202032, 0222762, 0701220,
303     0014421, 0112221, 0202052, 0222772, 0701250,
304     0014721, 0112244, 0202073, 0300013, 0702120,
305     0016251, 0112251, 0202122, 0300022, 0702221,
306     0017221, 0112277, 0202152, 0300041, 0702251,
307     0017255, 0112321, 0202212, 0300076, 0702321,
308     0017521, 0112424, 0202222, 0300123, 0702525,
309     0017621, 0112621, 0202272, 0300421, 0702720,
310     0017721, 0112727, 0202321, 0300622
311 };
312 
313 static unsigned int hex_transition_table[] =
314 {				/* Octal CBbltTR->I */
315   /* CBbltTRI   CBbltTRI   CBbltTRI   CBbltTRI   CBbltTRI */
316 
317 #ifdef TRIA
318     000000000, 000000020, 000000220, 000002220, 000022220,
319     011122121, 011121221, 011122221, 011221221,
320     011222221, 011112121, 011112221,
321     020021122, 020002122, 020211222, 021111222,
322     020221122, 020027122, 020020722, 020021022,
323     001127221,
324     011122727, 011227227, 010122121, 010222211,
325     021117222, 020112272,
326     070221220,
327     001227221,
328     010221121, 011721221, 011222277,
329     020111222, 020221172,
330     070211220,
331     001217221,
332     010212277, 010221221,
333     020122112,
334     070122220,
335     001722221,
336     010221271,
337     020002022, 021122172,
338     070121220,
339     011122277, 011172121,
340     010212177, 011212277,
341     070112220,
342     001772221,
343     021221772,
344     070121270, 070721220,
345     000112721, 000272211,
346     010022211, 012222277,
347     020072272, 020227122, 020217222,
348     010211121,
349     020002727,
350     070222220,
351     001727721,
352     020021072, 020070722,
353     070002072, 070007022,
354     001772721,
355     070002022,
356     000000070, 000000770, 000072220, 000000270,
357     020110222, 020220272, 020220722,
358     070007071, 070002072, 070007022,
359     000000012, 000000122, 000000212, 001277721,
360     020122072, 020202212,
361     010002121,
362     020001122, 020002112,
363     020021722,
364     020122022, 020027022, 020070122, 020020122,
365     010227027,
366     020101222,
367     010227227, 010227277,
368     021722172,
369     001727221,
370     010222277,
371     020702272,
372     070122020,
373     000172721,
374     010022277, 010202177, 010227127,
375 
376     001214221,
377     010202244,
378     020024122, 020020422,
379     040122220,
380     001422221,
381     010221241, 010224224,
382     021122142,
383     040121220,
384     001124221,
385     010224274,
386     020112242, 021422172,
387     040221220,
388     001224221, 001427221,
389     010222244,
390     020227042,
391     040122020,
392     000142721,
393     010022244, 010202144, 010224124,
394     040112220,
395     001442221,
396     021221442,
397     040121240, 040421220,
398     000242211, 000112421,
399     020042242, 020214222, 020021422, 020220242, 020024022,
400     011224224,
401     020224122,
402     020220422,
403     012222244,
404     020002424,
405     040222220,
406     001244421, 000000420, 000000440, 000000240, 000000040,
407     020040121, 020021042,
408     040004022, 040004042, 040002042,
409     010021121,
410     020011122, 020002112,
411     001424421,
412     020040422,
413     001442421,
414     040002022,
415     001724221,
416     010227247,
417     020224072, 021417222,
418     000172421,
419     010021721,
420     020017022,
421     020120212,
422     020271727,
423     070207072, 070701220,
424     000001222,
425     020110122,
426     001277221,
427     001777721,
428     020021222, 020202272, 020120222, 020221722,
429     020027227,
430     070070222,
431     000007220,
432     020101272, 020272172, 020721422, 020721722,
433     020011222, 020202242,
434 #if 0
435               {2,2,0,0,2,7,0},
436              {2,0,2,0,2,0,2},
437             {2,4,1,2,2,1,2},
438            {2,1,2,1,2,1,2},
439           {2,0,2,2,1,1,2},
440          {2,7,1,1,1,1,2},
441         {0,2,2,2,2,2,2},
442               {2,2,0,0,7,7,0},
443              {2,1,2,0,2,0,7},
444             {2,0,1,2,2,1,2},
445            {2,4,2,1,2,1,2},
446           {2,1,2,2,1,1,2},
447          {2,0,7,1,1,1,2},
448         {0,2,2,2,2,2,2},
449 #endif
450 #else
451     000000000, 000000020, 000000220, 000002220,
452     011212121, 011212221, 011221221, 011222221,
453     020002122, 020021122, 020211122,
454 
455     010221221, 010222121,
456     020002022, 020021022, 020020122, 020112022,
457 
458     010202121,
459     020102022, 020202112,
460 
461     000000012, 000000122, 000000212,
462     010002121,
463     020001122, 020002112, 020011122,
464 
465 
466     001227221, 001272221, 001272721,
467     012212277, 011222727, 011212727,
468     020021722, 020027122, 020020722, 020027022,
469     020211722, 020202172, 020120272,
470     020271122, 020202172, 020207122, 020217122,
471     020120272, 020210722, 020270722,
472     070212220, 070221220, 070212120,
473 
474 
475     012222277,
476     020002727,
477     070222220,
478 
479     001277721, 000000070, 000000270, 000000720, 000000770,
480     020070122, 020021072,
481     070002072, 070007022, 070007071,
482 
483     020070722,
484     070002022,
485 
486     010227227, 010222727, 010202727,
487     020172022, 020202712,
488 
489     001224221, 001242221, 001242421,
490     012212244, 011222424, 011212424,
491     020021422, 020024122, 020020422, 020024022,
492     020211422, 020202142, 020120242,
493     020241122, 020202142, 020204122, 020214122,
494     020120242, 020210422, 020240422,
495     040212220, 040221220, 040212120,
496 
497 
498     012222244,
499     020002424,
500     040222220,
501 
502     001244421, 000000040, 000000240, 000000420, 000000440,
503     020040122, 020021042,
504     040002042,
505     040004021, 040004042,
506 
507     020040422,
508     040002022,
509 
510     010224224, 010222424, 010202424,
511     020142022, 020202412,
512     020011722, 020112072, 020172072, 020142072,
513 
514 
515 
516     000210225, 000022015, 000022522,
517     011225521,
518     020120525, 020020152, 020005122, 020214255, 020021152,
519     020255242,
520     050215222, 050225121,
521 
522     000225220, 001254222,
523     010221250, 011221251, 011225221,
524     020025122, 020152152, 020211252, 020214522, 020511125,
525     050212241, 05221120,
526     040521225,
527 
528     000000250, 000000520, 000150220, 000220520, 000222210,
529     001224251,
530     010022152, 010251221, 010522121, 011212151, 011221251,
531     011215221,
532     020000220, 020002152, 020020220, 020022152,
533     020021422, 020022152, 020022522, 020025425, 020050422,
534     020051022, 020051122, 020211122, 020211222, 020215222,
535     020245122,
536     050021125, 050021025, 050011125, 051242221,
537     041225220,
538 
539     000220250, 000220520, 001227521, 001275221,
540     011257227, 011522727,
541     020002052, 020002752, 020021052, 020057125,
542     050020722, 050027125,
543     070215220,
544 
545     070212255,
546     071225220,
547     020275122,
548     051272521,
549     020055725,
550     020021552,
551     012252277,
552     050002521,
553     020005725,
554 
555     050011022,
556     000000155,
557     020050722,
558     001227250,
559     010512727,
560     010002151,
561     020027112,
562     001227251,
563     012227257,
564     050002125,
565     020517122,
566     050002025,
567     020050102,
568     050002725,
569     020570722,
570     001252721,
571     020007051,
572     020102052,
573     020271072,
574     050001122,
575     010002151,
576     011227257,
577     020051722,
578     020057022,
579     020050122,
580 
581 
582     020051422,
583     011224254,
584     012224254,
585 
586     020054022,
587     050002425,
588     040252220,
589     020002454,
590 
591 
592     000000540,
593     001254425,
594     050004024,
595     040004051,
596 
597     000000142,
598     040001522,
599     010002547,
600     020045122,
601     051221240,
602     020002512,
603     020021522,
604 
605 
606     020020022,
607     021125522,
608     020521122,
609     020025022,
610     020025522,
611     020020522,
612 
613     020202222,
614     020212222,
615     021212222,
616     021222722,
617     021222422,
618     020002222,
619     020021222,
620     020022122,
621     020212122,
622     020027222,
623     020024222,
624     020212722,
625     020212422,
626     020202122,
627     001222221,
628     020002522,
629 
630     020017125,
631     010022722,
632     020212052,
633 
634     020205052,
635     070221250,
636 
637     000000050, 000005220, 000002270, 070252220,
638     000000450, 000007220,
639     000220220, 000202220, 000022020, 000020220,
640 
641     000222040,
642     000220440,
643     000022040,
644     000040220,
645 
646     000252220,
647     050221120, 010221520,
648     002222220,
649 
650     000070220, 000220720,
651     000020520, 000070250, 000222070, 000027020,
652     000022070, 000202270, 000024020, 000220420,
653     000220270, 000220240, 000072020, 000042020,
654     000002020, 000002070, 000020270, 000020250,
655     000270270, 000007020, 000040270,
656 
657     /* Collision starts (gen 540), not sure to have rules to save it
658        or depend on calloc to intialize remaining rules to 0 so that
659        the mutant will be born
660      */
661     000050220,
662 #endif
663 };
664 
665 
666 /*-
667 Neighborhoods are read as follows (rotations are not listed):
668     T
669   L C R  ==>  I
670     B
671 
672    t T
673   l C R  ==>  I
674    b B
675  */
676 
677 static unsigned char self_reproducing_loop[ADAM_LOOPY][ADAM_LOOPX] =
678 {
679 /* 10x10 */
680 	{0, 2, 2, 2, 2, 2, 2, 2, 2, 0},
681 	{2, 4, 0, 1, 4, 0, 1, 1, 1, 2},
682 	{2, 1, 2, 2, 2, 2, 2, 2, 1, 2},
683 	{2, 0, 2, 0, 0, 0, 0, 2, 1, 2},
684 	{2, 7, 2, 0, 0, 0, 0, 2, 7, 2},
685 	{2, 1, 2, 0, 0, 0, 0, 2, 0, 2},
686 	{2, 0, 2, 0, 0, 0, 0, 2, 1, 2},
687 	{2, 7, 2, 2, 2, 2, 2, 2, 7, 2},
688 	{2, 1, 0, 6, 1, 0, 7, 1, 0, 2},
689 	{0, 2, 2, 2, 2, 2, 2, 2, 2, 0}
690 };
691 
692 static unsigned char hex_self_reproducing_loop[HEX_ADAM_LOOPY][HEX_ADAM_LOOPX] =
693 {
694 #if 0
695 /* Experimental TRIA5:7x7 */
696 	      {2,2,0,0,0,0,0},
697 	     {2,1,2,0,2,2,0},
698 	    {2,0,4,2,2,0,2},
699 	   {2,7,2,0,2,0,2},
700 	  {2,1,2,2,1,1,2},
701 	 {2,0,7,1,0,7,2},
702 	{0,2,2,2,2,2,2},
703   /* Stem cells, only "5" will fully reproduce itself */
704 /* 3:12x7 */
705 	      {2,2,2,2,0,0,0,0,0,0,0,0},
706 	     {2,1,1,1,2,0,0,0,0,0,0,0},
707 	    {2,1,2,2,1,2,2,2,2,2,2,0},
708 	   {2,1,2,0,2,7,1,1,1,1,1,2},
709 	  {0,2,1,2,2,0,2,2,2,2,2,2},
710 	 {0,0,2,0,4,1,2,0,0,0,0,0},
711 	{0,0,0,2,2,2,2,0,0,0,0,0}
712 /* 4:14x9 */
713 	        {2,2,2,2,2,0,0,0,0,0,0,0,0,0},
714 	       {2,1,1,1,1,2,0,0,0,0,0,0,0,0},
715 	      {2,1,2,2,2,1,2,0,0,0,0,0,0,0},
716 	     {2,1,2,0,0,2,1,2,2,2,2,2,2,0},
717 	    {2,1,2,0,0,0,2,7,1,1,1,1,1,2},
718 	   {0,2,1,2,0,0,2,0,2,2,2,2,2,2},
719 	  {0,0,2,0,2,2,2,1,2,0,0,0,0,0},
720 	 {0,0,0,2,4,1,0,7,2,0,0,0,0,0},
721 	{0,0,0,0,2,2,2,2,2,0,0,0,0,0}
722 /* 5:16x11 */
723 	          {2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0},
724 	         {2,1,1,1,1,1,2,0,0,0,0,0,0,0,0,0},
725 	        {2,1,2,2,2,2,1,2,0,0,0,0,0,0,0,0},
726 	       {2,1,2,0,0,0,2,1,2,0,0,0,0,0,0,0},
727 	      {2,1,2,0,0,0,0,2,1,2,2,2,2,2,2,0},
728 	     {2,1,2,0,0,0,0,0,2,7,1,1,1,1,1,2},
729 	    {0,2,1,2,0,0,0,0,2,0,2,2,2,2,2,2},
730 	   {0,0,2,0,2,0,0,0,2,1,2,0,0,0,0,0},
731 	  {0,0,0,2,4,2,2,2,2,7,2,0,0,0,0,0},
732 	 {0,0,0,0,2,1,0,7,1,0,2,0,0,0,0,0},
733 	{0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0}
734 /* test:3x7  (0,4) is blank  ... very strange.
735           init_adam seems ok something after that I guess */
736 	             {2,2,0},
737 	            {2,0,2},
738 	           {0,2,2},
739 	          {0,0,0},
740 	         {2,2,0},
741 	        {2,1,2},
742 	       {0,2,2},
743 #else /* this might be better for hexagons, spacewise efficient... */
744 #ifdef TRIA
745 /* Experimental TRIA5:7x7 */
746 	      {2,2,0,0,2,2,0},
747 	     {2,4,2,0,2,7,2},
748 	    {2,1,0,2,2,0,2},
749 	   {2,0,2,1,2,1,2},
750 	  {2,7,2,2,7,7,2},
751 	 {2,1,0,7,1,0,2},
752 	{0,2,2,2,2,2,2},
753 #else
754 /* 5:11x11 */
755 	          {2,2,2,2,2,2,0,0,0,0,0},
756 	         {2,1,1,7,0,1,2,0,0,0,0},
757 	        {2,1,2,2,2,2,7,2,0,0,0},
758 	       {2,1,2,0,0,0,2,0,2,0,0},
759 	      {2,1,2,0,0,0,0,2,1,2,0},
760 	     {2,1,2,0,0,0,0,0,2,7,2},
761 	    {0,2,1,2,0,0,0,0,2,0,2},
762 	   {0,0,2,1,2,0,0,0,2,1,2},
763 	  {0,0,0,2,1,2,2,2,2,4,2},
764 	 {0,0,0,0,2,1,1,1,1,5,2},
765 	{0,0,0,0,0,2,2,2,2,2,2}
766 #endif
767 #endif
768 };
769 
770 static void
position_of_neighbor(int dir,int * pcol,int * prow)771 position_of_neighbor(int dir, int *pcol, int *prow)
772 {
773 	int         col = *pcol, row = *prow;
774 
775 	/* NO WRAPING */
776 
777 	if (local_neighbors == 6) {
778 		switch (dir) {
779 			case 0:
780 				col++;
781 				break;
782 			case 60:
783 				col += (row & 1);
784 				row--;
785 				break;
786 			case 120:
787 				col -= !(row & 1);
788 				row--;
789 				break;
790 			case 180:
791 				col--;
792 				break;
793 			case 240:
794 				col -= !(row & 1);
795 				row++;
796 				break;
797 			case 300:
798 				col += (row & 1);
799 				row++;
800 				break;
801 			default:
802 				(void) fprintf(stderr, "wrong direction %d\n", dir);
803 		}
804 	} else {
805 		switch (dir) {
806 			case 0:
807 				col++;
808 				break;
809 			case 90:
810 				row--;
811 				break;
812 			case 180:
813 				col--;
814 				break;
815 			case 270:
816 				row++;
817 				break;
818 			default:
819 				(void) fprintf(stderr, "wrong direction %d\n", dir);
820 		}
821 	}
822 	*pcol = col;
823 	*prow = row;
824 }
825 
826 static      Bool
withinBounds(loopstruct * lp,int col,int row)827 withinBounds(loopstruct * lp, int col, int row)
828 {
829 	return (row >= 1 && row < lp->bnrows - 1 &&
830 		col >= 1 && col < lp->bncols - 1 - (local_neighbors == 6 && (row % 2)));
831 }
832 
833 static void
fillcell(ModeInfo * mi,GC gc,int col,int row)834 fillcell(ModeInfo * mi, GC gc, int col, int row)
835 {
836 	loopstruct *lp = &loops[MI_SCREEN(mi)];
837 
838 	if (local_neighbors == 6) {
839 		int         ccol = 2 * col + !(row & 1), crow = 2 * row;
840 
841 		lp->shape.hexagon[0].x = lp->xb + ccol * lp->xs;
842 		lp->shape.hexagon[0].y = lp->yb + crow * lp->ys;
843 		if (lp->xs == 1 && lp->ys == 1)
844 			XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
845 				lp->shape.hexagon[0].x, lp->shape.hexagon[0].y);
846 		else
847 			XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
848 				lp->shape.hexagon, 6, Convex, CoordModePrevious);
849 	} else {
850 		XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), gc,
851 			lp->xb + lp->xs * col, lp->yb + lp->ys * row,
852 			lp->xs - (lp->xs > 3), lp->ys - (lp->ys > 3));
853 	}
854 }
855 
856 static void
drawcell(ModeInfo * mi,int col,int row,int state)857 drawcell(ModeInfo * mi, int col, int row, int state)
858 {
859 	loopstruct *lp = &loops[MI_SCREEN(mi)];
860 	XGCValues   gcv;
861 	GC          gc;
862 
863 	if (MI_NPIXELS(mi) >= COLORS) {
864 		gc = MI_GC(mi);
865 		XSetForeground(MI_DISPLAY(mi), gc, lp->colors[state]);
866 	} else {
867 #ifdef DO_STIPPLE
868 		gcv.stipple = lp->pixmaps[state];
869 #endif /* DO_STIPPLE */
870 		gcv.foreground = MI_WHITE_PIXEL(mi);
871 		gcv.background = MI_BLACK_PIXEL(mi);
872 		XChangeGC(MI_DISPLAY(mi), lp->stippledGC,
873 #ifdef DO_STIPPLE
874 			  GCStipple |
875 #endif /* DO_STIPPLE */
876                           GCForeground | GCBackground, &gcv);
877 		gc = lp->stippledGC;
878 	}
879 	fillcell(mi, gc, col, row);
880 }
881 
882 #ifdef DEBUG
883 static void
print_state(ModeInfo * mi,int state)884 print_state(ModeInfo * mi, int state)
885 {
886 	loopstruct *lp = &loops[MI_SCREEN(mi)];
887 	CellList   *locallist = lp->cellList[state];
888 	int         i = 0;
889 
890 	(void) printf("state %d\n", state);
891 	while (locallist) {
892 		(void) printf("%d x %d, y %d\n", i,
893 			      locallist->pt.x, locallist->pt.y);
894 		locallist = locallist->next;
895 		i++;
896 	}
897 }
898 
899 #endif
900 
901 static void
free_state(loopstruct * lp,int state)902 free_state(loopstruct * lp, int state)
903 {
904 	CellList   *current;
905 
906 	while (lp->cellList[state]) {
907 		current = lp->cellList[state];
908 		lp->cellList[state] = lp->cellList[state]->next;
909 		(void) free((void *) current);
910 	}
911 	lp->ncells[state] = 0;
912 }
913 
914 static void
free_list(loopstruct * lp)915 free_list(loopstruct * lp)
916 {
917 	int         state;
918 
919 	for (state = 0; state < COLORS; state++)
920 		free_state(lp, state);
921 }
922 
923 ENTRYPOINT void
free_loop(ModeInfo * mi)924 free_loop(ModeInfo * mi)
925 {
926 	Display    *display = MI_DISPLAY(mi);
927 	loopstruct *lp = &loops[MI_SCREEN(mi)];
928 	int         shade;
929 
930 	for (shade = 0; shade < lp->init_bits; shade++)
931 		if (lp->pixmaps[shade] != None) {
932 			XFreePixmap(display, lp->pixmaps[shade]);
933 			lp->pixmaps[shade] = None;
934 		}
935 	if (lp->stippledGC != None) {
936 		XFreeGC(display, lp->stippledGC);
937 		lp->stippledGC = None;
938 	}
939 	if (lp->oldcells != NULL) {
940 		(void) free((void *) lp->oldcells);
941 		lp->oldcells = (unsigned char *) NULL;
942 	}
943 	if (lp->newcells != NULL) {
944 		(void) free((void *) lp->newcells);
945 		lp->newcells = (unsigned char *) NULL;
946 	}
947 	free_list(lp);
948 }
949 
950 static Bool
addtolist(ModeInfo * mi,int col,int row,unsigned char state)951 addtolist(ModeInfo * mi, int col, int row, unsigned char state)
952 {
953 	loopstruct *lp = &loops[MI_SCREEN(mi)];
954 	CellList   *current = lp->cellList[state];
955 
956 	if ((lp->cellList[state] = (CellList *) malloc(sizeof (CellList))) ==
957 			NULL) {
958 		lp->cellList[state] = current;
959 		free_loop(mi);
960 		return False;
961 	}
962 	lp->cellList[state]->pt.x = col;
963 	lp->cellList[state]->pt.y = row;
964 	lp->cellList[state]->next = current;
965 	lp->ncells[state]++;
966 	return True;
967 }
968 
969 static Bool
draw_state(ModeInfo * mi,int state)970 draw_state(ModeInfo * mi, int state)
971 {
972 	loopstruct *lp = &loops[MI_SCREEN(mi)];
973 	Display    *display = MI_DISPLAY(mi);
974 	GC          gc;
975 	XGCValues   gcv;
976 	CellList   *current = lp->cellList[state];
977 
978 	if (MI_NPIXELS(mi) >= COLORS) {
979 		gc = MI_GC(mi);
980 		XSetForeground(display, gc, lp->colors[state]);
981 	} else {
982 #ifdef DO_STIPPLE
983 		gcv.stipple = lp->pixmaps[state];
984 #endif /* DO_STIPPLE */
985 		gcv.foreground = MI_WHITE_PIXEL(mi);
986 		gcv.background = MI_BLACK_PIXEL(mi);
987 		XChangeGC(display, lp->stippledGC,
988 #ifdef DO_STIPPLE
989 			  GCStipple |
990 #endif /* DO_STIPPLE */
991                           GCForeground | GCBackground, &gcv);
992 		gc = lp->stippledGC;
993 	}
994 
995 	if (local_neighbors == 6) {       /* Draw right away, slow */
996 		while (current) {
997 			int	 col, row, ccol, crow;
998 
999 			col = current->pt.x;
1000 			row = current->pt.y;
1001 			ccol = 2 * col + !(row & 1), crow = 2 * row;
1002 			lp->shape.hexagon[0].x = lp->xb + ccol * lp->xs;
1003 			lp->shape.hexagon[0].y = lp->yb + crow * lp->ys;
1004 			if (lp->xs == 1 && lp->ys == 1)
1005 				XDrawPoint(display, MI_WINDOW(mi), gc,
1006 					lp->shape.hexagon[0].x, lp->shape.hexagon[0].y);
1007 			else
1008 				XFillPolygon(display, MI_WINDOW(mi), gc,
1009 				  	lp->shape.hexagon, 6, Convex, CoordModePrevious);
1010 			current = current->next;
1011 		}
1012 	} else {
1013 		/* Take advantage of XFillRectangles */
1014 		XRectangle *rects;
1015 		int         nrects = 0;
1016 
1017 		/* Create Rectangle list from part of the cellList */
1018 		if ((rects = (XRectangle *) malloc(lp->ncells[state] *
1019 				sizeof (XRectangle))) == NULL) {
1020 			return False;
1021 		}
1022 
1023 		while (current) {
1024 			rects[nrects].x = lp->xb + current->pt.x * lp->xs;
1025 			rects[nrects].y = lp->yb + current->pt.y * lp->ys;
1026 			rects[nrects].width = lp->xs - (lp->xs > 3);
1027 			rects[nrects].height = lp->ys - (lp->ys > 3);
1028 			current = current->next;
1029 			nrects++;
1030 		}
1031 		/* Finally get to draw */
1032 		XFillRectangles(display, MI_WINDOW(mi), gc, rects, nrects);
1033 		/* Free up rects list and the appropriate part of the cellList */
1034 		(void) free((void *) rects);
1035 	}
1036 	free_state(lp, state);
1037 	return True;
1038 }
1039 
1040 static Bool
init_table(void)1041 init_table(void)
1042 {
1043 	if (table == NULL) {
1044 		int mult = 1;
1045 		unsigned int tt, c, n[MAXNEIGHBORS], i;
1046 		int         j, k;
1047 		int  size_transition_table = sizeof (transition_table) /
1048 			sizeof (unsigned int);
1049 		int  size_hex_transition_table = sizeof (hex_transition_table) /
1050 			sizeof (unsigned int);
1051 
1052 		for (j = 0; j < local_neighbors; j++)
1053 			mult *= 8;
1054 
1055 		if ((table = (unsigned int *) calloc(mult, sizeof (unsigned int))) == NULL) {
1056 			return False;
1057 		}
1058 
1059 
1060 #ifdef RAND_RULES
1061 		/* Here I was interested to see what happens when it hits a wall....
1062 		   Rules not normally used take over... takes too much time though */
1063 		/* Each state = 3 bits */
1064 		if (MAXRAND < 16777216.0) {
1065 			for (j = 0; j < mult; j++) {
1066 				table[j] = (unsigned int) ((NRAND(4096) << 12) & NRAND(4096));
1067 			}
1068 		} else {
1069 			for  (j = 0; j < mult; j++) {
1070 				table[j] = (unsigned int) (NRAND(16777216));
1071 			}
1072 		}
1073 #endif
1074 		if (local_neighbors == 6) {
1075 			for (j = 0; j < size_hex_transition_table; j++) {
1076 				tt = hex_transition_table[j];
1077 				TRANSITION(tt, i);
1078 				for (k = 0; k < local_neighbors; k++) {
1079 					TRANSITION(tt, n[k]);
1080 				}
1081 				FINALTRANSITION(tt, c);
1082 				HEX_TABLE_IN(c, n[0], n[1], n[2], n[3], n[4], n[5], i);
1083 				HEX_TABLE_IN(c, n[1], n[2], n[3], n[4], n[5], n[0], i);
1084 				HEX_TABLE_IN(c, n[2], n[3], n[4], n[5], n[0], n[1], i);
1085 				HEX_TABLE_IN(c, n[3], n[4], n[5], n[0], n[1], n[2], i);
1086 				HEX_TABLE_IN(c, n[4], n[5], n[0], n[1], n[2], n[3], i);
1087 				HEX_TABLE_IN(c, n[5], n[0], n[1], n[2], n[3], n[4], i);
1088 			}
1089 		} else {
1090 			for (j = 0; j < size_transition_table; j++) {
1091 				tt = transition_table[j];
1092 				TRANSITION(tt, i);
1093 				for (k = 0; k < local_neighbors; k++) {
1094 					TRANSITION(tt, n[k]);
1095 				}
1096 				FINALTRANSITION(tt, c);
1097 				TABLE_IN(c, n[0], n[1], n[2], n[3], i);
1098 				TABLE_IN(c, n[1], n[2], n[3], n[0], i);
1099 				TABLE_IN(c, n[2], n[3], n[0], n[1], i);
1100 				TABLE_IN(c, n[3], n[0], n[1], n[2], i);
1101 			}
1102 		}
1103 	}
1104 	return True;
1105 }
1106 
1107 static void
init_flaw(ModeInfo * mi)1108 init_flaw(ModeInfo * mi)
1109 {
1110 	loopstruct *lp = &loops[MI_SCREEN(mi)];
1111 	int a, b;
1112 
1113 #define	BLUE 2
1114 	if (lp->bncols <= 3 || lp->bnrows <= 3)
1115 		return;
1116 	a = MIN(lp->bncols - 3, 2 * ((local_neighbors == 6) ?
1117 		 HEX_MINGRIDSIZE : MINGRIDSIZE));
1118 	a = NRAND(a) + (lp->bncols - a) / 2;
1119 	b = MIN(lp->bnrows - 3, 2 * ((local_neighbors == 6) ?
1120 		 HEX_MINGRIDSIZE : MINGRIDSIZE));
1121 	b = NRAND(b) + (lp->bnrows - b) / 2;
1122 	if (lp->mincol > a)
1123 		lp->mincol = a;
1124 	if (lp->minrow > b)
1125 		lp->minrow = b;
1126 	if (lp->maxcol < a + 2)
1127 		lp->maxcol = a + 2;
1128 	if (lp->maxrow < b + 2)
1129 		lp->maxrow = b + 2;
1130 
1131 	if (local_neighbors == 6) {
1132 		lp->newcells[b * lp->bncols + a + !(b % 2) ] = BLUE;
1133 		lp->newcells[b * lp->bncols + a + 1 + !(b % 2)] = BLUE;
1134 		lp->newcells[(b + 1) * lp->bncols + a] = BLUE;
1135 		lp->newcells[(b + 1) * lp->bncols + a + 2] = BLUE;
1136 		lp->newcells[(b + 2) * lp->bncols + a + !(b % 2)] = BLUE;
1137 		lp->newcells[(b + 2) * lp->bncols + a + 1 + !(b % 2)] = BLUE;
1138 	} else {
1139 		int orient = NRAND(4);
1140 		lp->newcells[lp->bncols * (b + 1) + a + 1] = BLUE;
1141 		if (orient == 0 || orient == 1) {
1142 			lp->newcells[lp->bncols * b + a + 1] = BLUE;
1143 		}
1144 		if (orient == 1 || orient == 2) {
1145 			lp->newcells[lp->bncols * (b + 1) + a + 2] = BLUE;
1146 		}
1147 		if (orient == 2 || orient == 3) {
1148 			lp->newcells[lp->bncols * (b + 2) + a + 1] = BLUE;
1149 		}
1150 		if (orient == 3 || orient == 0) {
1151 			lp->newcells[lp->bncols * (b + 1) + a] = BLUE;
1152 		}
1153 	}
1154 }
1155 
1156 static void
init_adam(ModeInfo * mi)1157 init_adam(ModeInfo * mi)
1158 {
1159 	loopstruct *lp = &loops[MI_SCREEN(mi)];
1160 	XPoint      start = { 0, 0 }, dirx = { 0, 0 }, diry = { 0, 0 };
1161 	int         i, j, dir;
1162 
1163 #ifdef DELAYDEBUGLOOP
1164 	lp->clockwise = 0;
1165 	if (!MI_COUNT(mi)) /* Probably doing testing so do not confuse */
1166 #endif
1167 	lp->clockwise = (Bool) (LRAND() & 1);
1168 #ifdef DELAYDEBUGLOOP
1169 	dir = 0;
1170 	if (!MI_COUNT(mi)) /* Probably doing testing so do not confuse */
1171 #endif
1172 	dir = NRAND(local_neighbors);
1173 	if (local_neighbors == 6) {
1174 		int k;
1175 
1176 		switch (dir) {
1177 			case 0:
1178 				start.x = (lp->bncols - HEX_ADAM_LOOPX / 2) / 2;
1179 				start.y = (lp->bnrows - HEX_ADAM_LOOPY) / 2;
1180 				if (lp->mincol > start.x - 2)
1181 					lp->mincol = start.x - 2;
1182 				if (lp->minrow > start.y - 1)
1183 					lp->minrow = start.y - 1;
1184 				if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1)
1185 					lp->maxcol = start.x + HEX_ADAM_LOOPX + 1;
1186 				if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1)
1187 					lp->maxrow = start.y + HEX_ADAM_LOOPY + 1;
1188 				for (j = 0; j < HEX_ADAM_LOOPY; j++) {
1189 					for (i = 0; i < HEX_ADAM_LOOPX; i++) {
1190 						k = (((lp->bnrows / 2 + HEX_ADAM_LOOPY / 2) % 2) ? -j / 2 : -(j + 1) / 2);
1191 						lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] =
1192 		 					(lp->clockwise) ?
1193 					hex_self_reproducing_loop[i][j] :
1194 					hex_self_reproducing_loop[j][i];
1195 					}
1196 				}
1197 				break;
1198 			case 1:
1199 				start.x = (lp->bncols - (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) / 2;
1200 				start.y = (lp->bnrows - HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2;
1201 				if (lp->mincol > start.x - 1)
1202 					lp->mincol = start.x - 1;
1203 				if (lp->minrow > start.y - HEX_ADAM_LOOPX)
1204 					lp->minrow = start.y - HEX_ADAM_LOOPX;
1205 				if (lp->maxcol < start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1)
1206 					lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1;
1207 				if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1)
1208 					lp->maxrow = start.y + HEX_ADAM_LOOPY + 1;
1209 				for (j = 0; j < HEX_ADAM_LOOPY; j++) {
1210 					for (i = 0; i < HEX_ADAM_LOOPX; i++) {
1211 						k = (((lp->bnrows / 2 + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) % 2)
1212               ? -(i + j + 1) / 2 : -(i + j) / 2);
1213 						lp->newcells[(start.y + j - i) * lp->bncols + start.x + i + j + k] =
1214 		 					(lp->clockwise) ?
1215 		 					hex_self_reproducing_loop[i][j] :
1216 		 					hex_self_reproducing_loop[j][i];
1217 					}
1218 				}
1219 				break;
1220 			case 2:
1221 				start.x = (lp->bncols - HEX_ADAM_LOOPY / 2) / 2;
1222 				start.y = (lp->bnrows - HEX_ADAM_LOOPX) / 2;
1223 				if (lp->mincol > start.x - 2)
1224 					lp->mincol = start.x - 2;
1225 				if (lp->minrow > start.y - 1)
1226 					lp->minrow = start.y - 1;
1227 				if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1)
1228 					lp->maxcol = start.x + HEX_ADAM_LOOPX + 1;
1229 				if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1)
1230 					lp->maxrow = start.y + HEX_ADAM_LOOPY + 1;
1231 				for (j = 0; j < HEX_ADAM_LOOPX; j++) {
1232 					for (i = 0; i < HEX_ADAM_LOOPY; i++) {
1233 						k = (((lp->bnrows / 2 + HEX_ADAM_LOOPX / 2) % 2) ? -(HEX_ADAM_LOOPX - j - 1) / 2 : -(HEX_ADAM_LOOPX - j) / 2);
1234 						lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] =
1235 		 					(lp->clockwise) ?
1236 		 					hex_self_reproducing_loop[j][HEX_ADAM_LOOPX - i - 1] :
1237 		 					hex_self_reproducing_loop[i][HEX_ADAM_LOOPY - j - 1];
1238 					}
1239 				}
1240 				break;
1241 			case 3:
1242 				start.x = (lp->bncols - HEX_ADAM_LOOPX / 2) / 2;
1243 				start.y = (lp->bnrows - HEX_ADAM_LOOPY) / 2;
1244 				if (lp->mincol > start.x - 1)
1245 					lp->mincol = start.x - 1;
1246 				if (lp->minrow > start.y - 1)
1247 					lp->minrow = start.y - 1;
1248 				if (lp->maxcol < start.x + HEX_ADAM_LOOPX + 1)
1249 					lp->maxcol = start.x + HEX_ADAM_LOOPX + 1;
1250 				if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1)
1251 					lp->maxrow = start.y + HEX_ADAM_LOOPY + 1;
1252 				for (j = 0; j < HEX_ADAM_LOOPY; j++) {
1253 					for (i = 0; i < HEX_ADAM_LOOPX; i++) {
1254 						k = (((lp->bnrows / 2 + HEX_ADAM_LOOPY / 2) % 2) ? -j / 2 : -(j + 1) / 2);
1255 						lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] =
1256 		 					(lp->clockwise) ?
1257 		 					hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][HEX_ADAM_LOOPY - j - 1] :
1258 		 					hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1];
1259 					}
1260 				}
1261 				break;
1262 			case 4:
1263 				start.x = (lp->bncols - (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) / 2;
1264 				start.y = (lp->bnrows - HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2;
1265 				if (lp->mincol > start.x - 1)
1266 					lp->mincol = start.x - 1;
1267 				if (lp->minrow > start.y - HEX_ADAM_LOOPX)
1268 					lp->minrow = start.y - HEX_ADAM_LOOPX;
1269 				if (lp->maxcol < start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1)
1270 					lp->maxcol = start.x + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2 + 1;
1271 				if (lp->maxrow < start.y + HEX_ADAM_LOOPY + 1)
1272 					lp->maxrow = start.y + HEX_ADAM_LOOPY + 1;
1273 				for (j = 0; j < HEX_ADAM_LOOPY; j++) {
1274 					for (i = 0; i < HEX_ADAM_LOOPX; i++) {
1275 						k = (((lp->bnrows / 2 + (HEX_ADAM_LOOPX + HEX_ADAM_LOOPY) / 2) % 2)
1276               ? -(i + j + 1) / 2 : -(i + j) / 2);
1277 						lp->newcells[(start.y + j - i) * lp->bncols + start.x + i + j + k] =
1278 		 					(lp->clockwise) ?
1279 		 					hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][HEX_ADAM_LOOPY - j - 1] :
1280 		 					hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][HEX_ADAM_LOOPX - i - 1];
1281 					}
1282 				}
1283 				break;
1284 			case 5:
1285 				start.x = (lp->bncols - HEX_ADAM_LOOPY / 2) / 2;
1286 				start.y = (lp->bnrows - HEX_ADAM_LOOPX) / 2;
1287 				if (lp->mincol > start.x - 2)
1288 					lp->mincol = start.x - 2;
1289 				if (lp->minrow > start.y - 1)
1290 					lp->minrow = start.y - 1;
1291 				if (lp->maxcol < start.x + HEX_ADAM_LOOPY + 1)
1292 					lp->maxcol = start.x + HEX_ADAM_LOOPY + 1;
1293 				if (lp->maxrow < start.y + HEX_ADAM_LOOPX + 1)
1294 					lp->maxrow = start.y + HEX_ADAM_LOOPX + 1;
1295 				for (j = 0; j < HEX_ADAM_LOOPX; j++) {
1296 					for (i = 0; i < HEX_ADAM_LOOPY; i++) {
1297 						k = (((lp->bnrows / 2 + HEX_ADAM_LOOPX / 2) % 2) ? -(HEX_ADAM_LOOPX - j - 1) / 2 : -(HEX_ADAM_LOOPX - j) / 2);
1298 						lp->newcells[(start.y + j) * lp->bncols + start.x + i + k] =
1299 		 					(lp->clockwise) ?
1300 		 					hex_self_reproducing_loop[HEX_ADAM_LOOPY - j - 1][i] :
1301 		 					hex_self_reproducing_loop[HEX_ADAM_LOOPX - i - 1][j];
1302 					}
1303 				}
1304 				break;
1305 		}
1306 #if DEBUGTEST
1307 				/* (void) printf ("s %d  s %d \n", start.x, start.y); */
1308 		(void) printf ("%d %d %d %d %d\n",
1309      start.x + i + ((lp->bnrows / 2 % 2) ? -j / 2 : -(j + 1) / 2) - lp->bx,
1310 		 start.y + j - lp->by, i, j, hex_self_reproducing_loop[j][i]);
1311 		/* Draw right away */
1312 		drawcell(mi, start.x + i + ((lp->bnrows / 2 % 2) ? -j / 2 : -(j + 1) / 2) - lp->bx,
1313 		 start.y + j - lp->by,
1314 		 hex_self_reproducing_loop[j][i]);
1315 #endif
1316   } else {
1317 		switch (dir) {
1318 			case 0:
1319 				start.x = (lp->bncols - ADAM_LOOPX) / 2;
1320 				start.y = (lp->bnrows - ADAM_LOOPY) / 2;
1321 				dirx.x = 1, dirx.y = 0;
1322 				diry.x = 0, diry.y = 1;
1323 				if (lp->mincol > start.x)
1324 					lp->mincol = start.x;
1325 				if (lp->minrow > start.y)
1326 					lp->minrow = start.y;
1327 				if (lp->maxcol < start.x + ADAM_LOOPX)
1328 					lp->maxcol = start.x + ADAM_LOOPX;
1329 				if (lp->maxrow < start.y + ADAM_LOOPY)
1330 					lp->maxrow = start.y + ADAM_LOOPY;
1331 				break;
1332 			case 1:
1333 				start.x = (lp->bncols + ADAM_LOOPY) / 2;
1334 				start.y = (lp->bnrows - ADAM_LOOPX) / 2;
1335 				dirx.x = 0, dirx.y = 1;
1336 				diry.x = -1, diry.y = 0;
1337 				if (lp->mincol > start.x - ADAM_LOOPY)
1338 					lp->mincol = start.x - ADAM_LOOPY;
1339 				if (lp->minrow > start.y)
1340 					lp->minrow = start.y;
1341 				if (lp->maxcol < start.x)
1342 					lp->maxcol = start.x;
1343 				if (lp->maxrow < start.y + ADAM_LOOPX)
1344 					lp->maxrow = start.y + ADAM_LOOPX;
1345 				break;
1346 			case 2:
1347 				start.x = (lp->bncols + ADAM_LOOPX) / 2;
1348 				start.y = (lp->bnrows + ADAM_LOOPY) / 2;
1349 				dirx.x = -1, dirx.y = 0;
1350 				diry.x = 0, diry.y = -1;
1351 				if (lp->mincol > start.x - ADAM_LOOPX)
1352 					lp->mincol = start.x - ADAM_LOOPX;
1353 				if (lp->minrow > start.y - ADAM_LOOPY)
1354 					lp->minrow = start.y - ADAM_LOOPY;
1355 				if (lp->maxcol < start.x)
1356 					lp->maxcol = start.x;
1357 				if (lp->maxrow < start.y)
1358 					lp->maxrow = start.y;
1359 				break;
1360 			case 3:
1361 				start.x = (lp->bncols - ADAM_LOOPY) / 2;
1362 				start.y = (lp->bnrows + ADAM_LOOPX) / 2;
1363 				dirx.x = 0, dirx.y = -1;
1364 				diry.x = 1, diry.y = 0;
1365 				if (lp->mincol > start.x)
1366 					lp->mincol = start.x;
1367 				if (lp->minrow > start.y - ADAM_LOOPX)
1368 					lp->minrow = start.y - ADAM_LOOPX;
1369 				if (lp->maxcol < start.x + ADAM_LOOPX)
1370 					lp->maxcol = start.x + ADAM_LOOPX;
1371 				if (lp->maxrow < start.y)
1372 					lp->maxrow = start.y;
1373 				break;
1374 		}
1375 		for (j = 0; j < ADAM_LOOPY; j++)
1376 			for (i = 0; i < ADAM_LOOPX; i++)
1377 			  lp->newcells[lp->bncols * (start.y + dirx.y * i + diry.y * j) +
1378 			    start.x + dirx.x * i + diry.x * j] =
1379 			    (lp->clockwise) ?
1380 			      self_reproducing_loop[j][ADAM_LOOPX - i - 1] :
1381 			      self_reproducing_loop[j][i];
1382 #if DEBUG
1383 		/* Draw right away */
1384 		drawcell(mi, start.x + dirx.x * i + diry.x * j - lp->bx,
1385 		 start.y + dirx.y * i + diry.y * j - lp->by,
1386 		 (lp->clockwise) ? self_reproducing_loop[j][ADAM_LOOPX - i - i] : self_reproducing_loop[j][i]);
1387 #endif
1388 	}
1389 }
1390 
1391 
1392 static void
do_gen(loopstruct * lp)1393 do_gen(loopstruct * lp)
1394 {
1395 	int         i, j, k;
1396 	unsigned char *z;
1397 	unsigned int n[MAXNEIGHBORS];
1398 	unsigned int c;
1399 
1400 #define LOC(X, Y) (*(lp->oldcells + (X) + ((Y) * lp->bncols)))
1401 
1402 	for (j = lp->minrow; j <= lp->maxrow; j++) {
1403 		for (i = lp->mincol; i <= lp->maxcol; i++) {
1404 			z = lp->newcells + i + j * lp->bncols;
1405 			c = LOC(i, j);
1406 			for (k = 0; k < local_neighbors; k++) {
1407 				int         newi = i, newj = j;
1408 
1409 				position_of_neighbor(k * ANGLES / local_neighbors, &newi, &newj);
1410 				n[k] = 0;
1411 		    if (withinBounds(lp, newi, newj)) {
1412 					n[k] = LOC(newi, newj);
1413 				}
1414 			}
1415 			if (local_neighbors == 6) {
1416 				*z = (lp->clockwise) ?
1417 					HEX_TABLE_OUT(c, n[5], n[4], n[3], n[2], n[1], n[0]) :
1418 					HEX_TABLE_OUT(c, n[0], n[1], n[2], n[3], n[4], n[5]);
1419 			} else {
1420 				*z = (lp->clockwise) ?
1421 					TABLE_OUT(c, n[3], n[2], n[1], n[0]) :
1422 					TABLE_OUT(c, n[0], n[1], n[2], n[3]);
1423 			}
1424 		}
1425 	}
1426 }
1427 
1428 ENTRYPOINT void
release_loop(ModeInfo * mi)1429 release_loop (ModeInfo * mi)
1430 {
1431 	if (table != NULL) {
1432 		(void) free((void *) table);
1433 		table = (unsigned int *) NULL;
1434 	}
1435 }
1436 
1437 static void *stop_warning_about_triangleUnit_already;
1438 
1439 
1440 ENTRYPOINT void
init_loop(ModeInfo * mi)1441 init_loop (ModeInfo * mi)
1442 {
1443 	int         i, size = MI_SIZE(mi);
1444 	loopstruct *lp;
1445 
1446     stop_warning_about_triangleUnit_already = (void *) &triangleUnit;
1447 
1448 	MI_INIT (mi, loops);
1449 	lp = &loops[MI_SCREEN(mi)];
1450 
1451 	lp->redrawing = 0;
1452 
1453     if (MI_WIDTH(mi) < 100 || MI_HEIGHT(mi) < 100)  /* tiny window */
1454       size = MIN(MI_WIDTH(mi), MI_HEIGHT(mi));
1455 
1456 #ifdef DO_STIPPLE
1457 	if ((MI_NPIXELS(mi) < COLORS) && (lp->init_bits == 0)) {
1458           Window      window = MI_WINDOW(mi);
1459           XGCValues   gcv;
1460         if (lp->stippledGC == None) {
1461 			gcv.fill_style = FillOpaqueStippled;
1462 			if ((lp->stippledGC = XCreateGC(MI_DISPLAY(mi), window,
1463 				 GCFillStyle, &gcv)) == None) {
1464 				free_loop(mi);
1465 				return;
1466 			}
1467 		}
1468 		LOOPBITS(stipples[0], STIPPLESIZE, STIPPLESIZE);
1469 		LOOPBITS(stipples[2], STIPPLESIZE, STIPPLESIZE);
1470 		LOOPBITS(stipples[3], STIPPLESIZE, STIPPLESIZE);
1471 		LOOPBITS(stipples[4], STIPPLESIZE, STIPPLESIZE);
1472 		LOOPBITS(stipples[6], STIPPLESIZE, STIPPLESIZE);
1473 		LOOPBITS(stipples[7], STIPPLESIZE, STIPPLESIZE);
1474 		LOOPBITS(stipples[8], STIPPLESIZE, STIPPLESIZE);
1475 		LOOPBITS(stipples[10], STIPPLESIZE, STIPPLESIZE);
1476 	}
1477 #endif /* DO_STIPPLE */
1478 	if (MI_NPIXELS(mi) >= COLORS) {
1479 		/* Maybe these colors should be randomized */
1480 		lp->colors[0] = MI_BLACK_PIXEL(mi);
1481 		lp->colors[1] = MI_PIXEL(mi, 0);	/* RED */
1482 		lp->colors[5] = MI_PIXEL(mi, MI_NPIXELS(mi) / REALCOLORS);	/* YELLOW */
1483 		lp->colors[4] = MI_PIXEL(mi, 2 * MI_NPIXELS(mi) / REALCOLORS);	/* GREEN */
1484 		lp->colors[6] = MI_PIXEL(mi, 3 * MI_NPIXELS(mi) / REALCOLORS);	/* CYAN */
1485 		lp->colors[2] = MI_PIXEL(mi, 4 * MI_NPIXELS(mi) / REALCOLORS);	/* BLUE */
1486 		lp->colors[3] = MI_PIXEL(mi, 5 * MI_NPIXELS(mi) / REALCOLORS);	/* MAGENTA */
1487 		lp->colors[7] = MI_WHITE_PIXEL(mi);
1488 	}
1489 	free_list(lp);
1490 	lp->generation = 0;
1491 	lp->width = MI_WIDTH(mi);
1492 	lp->height = MI_HEIGHT(mi);
1493 
1494 	if (!local_neighbors) {
1495 		for (i = 0; i < NEIGHBORKINDS; i++) {
1496 			if (neighbors == plots[i]) {
1497 				local_neighbors = neighbors;
1498 				break;
1499 			}
1500 			if (i == NEIGHBORKINDS - 1) {
1501 #if 1
1502 				local_neighbors = plots[NRAND(NEIGHBORKINDS)];
1503 #else
1504 				local_neighbors = 4;
1505 #endif
1506 				break;
1507 			}
1508 		}
1509 	}
1510 
1511 
1512   if (local_neighbors == 6) {
1513     int         nccols, ncrows;
1514 
1515     if (lp->width < 8)
1516       lp->width = 8;
1517     if (lp->height < 8)
1518       lp->height = 8;
1519     if (size < -MINSIZE) {
1520       lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) /
1521               HEX_MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1522     } else if (size < MINSIZE) {
1523       if (!size)
1524         lp->ys = MAX(MINSIZE, MIN(lp->width, lp->height) / HEX_MINGRIDSIZE);
1525       else
1526         lp->ys = MINSIZE;
1527     } else
1528       lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) /
1529                  HEX_MINGRIDSIZE));
1530     lp->xs = lp->ys;
1531     nccols = MAX(lp->width / lp->xs - 2, HEX_MINGRIDSIZE);
1532     ncrows = MAX(lp->height / lp->ys - 1, HEX_MINGRIDSIZE);
1533     lp->ncols = nccols / 2;
1534     lp->nrows = ncrows / 2;
1535     lp->nrows -= !(lp->nrows & 1);  /* Must be odd */
1536     lp->xb = (lp->width - lp->xs * nccols) / 2 + lp->xs;
1537     lp->yb = (lp->height - lp->ys * ncrows) / 2 + lp->ys;
1538     for (i = 0; i < 6; i++) {
1539       lp->shape.hexagon[i].x = (lp->xs - 1) * hexagonUnit[i].x;
1540       lp->shape.hexagon[i].y = ((lp->ys - 1) * hexagonUnit[i].y / 2) * 4 / 3;
1541     }
1542   } else {
1543 		if (size < -MINSIZE)
1544 			lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) /
1545 					      MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1546 		else if (size < MINSIZE) {
1547 			if (!size)
1548 				lp->ys = MAX(MINSIZE, MIN(lp->width, lp->height) / MINGRIDSIZE);
1549 			else
1550 				lp->ys = MINSIZE;
1551 		} else
1552 			lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) /
1553 					       MINGRIDSIZE));
1554 		lp->xs = lp->ys;
1555 		lp->ncols = MAX(lp->width / lp->xs, ADAM_LOOPX + 1);
1556 		lp->nrows = MAX(lp->height / lp->ys, ADAM_LOOPX + 1);
1557 		lp->xb = (lp->width - lp->xs * lp->ncols) / 2;
1558 		lp->yb = (lp->height - lp->ys * lp->nrows) / 2;
1559 	}
1560 	lp->bx = 1;
1561 	lp->by = 1;
1562 	lp->bncols = lp->ncols + 2 * lp->bx;
1563 	lp->bnrows = lp->nrows + 2 * lp->by;
1564 
1565 	MI_CLEARWINDOW(mi);
1566 
1567 	if (lp->oldcells != NULL) {
1568 		(void) free((void *) lp->oldcells);
1569 		lp->oldcells = (unsigned char *) NULL;
1570 	}
1571 	if ((lp->oldcells = (unsigned char *) calloc(lp->bncols * lp->bnrows,
1572 			sizeof (unsigned char))) == NULL) {
1573 		free_loop(mi);
1574 		return;
1575 	}
1576 	if (lp->newcells != NULL) {
1577 		(void) free((void *) lp->newcells);
1578 		lp->newcells = (unsigned char *) NULL;
1579 	}
1580 	if ((lp->newcells = (unsigned char *) calloc(lp->bncols * lp->bnrows,
1581 			sizeof (unsigned char))) == NULL) {
1582 		free_loop(mi);
1583 		return;
1584 	}
1585 	if (!init_table()) {
1586 		release_loop(mi);
1587 		return;
1588 	}
1589 	lp->mincol = lp->bncols - 1;
1590 	lp->minrow = lp->bnrows - 1;
1591 	lp->maxcol = 0;
1592 	lp->maxrow = 0;
1593 #ifndef DELAYDEBUGLOOP
1594 	{
1595 		int flaws = MI_COUNT(mi);
1596 
1597 		if (flaws < 0)
1598 			flaws = NRAND(-MI_COUNT(mi) + 1);
1599 		for (i = 0; i < flaws; i++) {
1600 			init_flaw(mi);
1601 		}
1602 		/* actual flaws might be less since the adam loop done next */
1603 	}
1604 #endif
1605 	init_adam(mi);
1606 }
1607 
1608 ENTRYPOINT void
draw_loop(ModeInfo * mi)1609 draw_loop (ModeInfo * mi)
1610 {
1611 	int         offset, i, j;
1612 	unsigned char *z, *znew;
1613 	loopstruct *lp;
1614 
1615 	if (loops == NULL)
1616 		return;
1617 	lp = &loops[MI_SCREEN(mi)];
1618 	if (lp->newcells == NULL)
1619 		return;
1620 
1621 	MI_IS_DRAWN(mi) = True;
1622 	lp->dead = True;
1623 #ifdef DELAYDEBUGLOOP
1624 	if (MI_COUNT(mi) && lp->generation > MI_COUNT(mi)) {
1625 		(void) sleep(DELAYDEBUGLOOP);
1626 	}
1627 #endif
1628 
1629 	for (j = lp->minrow; j <= lp->maxrow; j++) {
1630 		for (i = lp->mincol; i <= lp->maxcol; i++) {
1631 			offset = j * lp->bncols + i;
1632 			z = lp->oldcells + offset;
1633 			znew = lp->newcells + offset;
1634 			if (*z != *znew) {
1635 				lp->dead = False;
1636 				*z = *znew;
1637 				if (!addtolist(mi, i - lp->bx, j - lp->by, *znew))
1638 					return;
1639 				if (i == lp->mincol && i > lp->bx)
1640 					lp->mincol--;
1641 				if (j == lp->minrow && j > lp->by)
1642 					lp->minrow--;
1643 				if (i == lp->maxcol && i < lp->bncols - 2 * lp->bx)
1644 					lp->maxcol++;
1645 				if (j == lp->maxrow && j < lp->bnrows - 2 * lp->by)
1646 					lp->maxrow++;
1647 			}
1648 		}
1649 	}
1650 	for (i = 0; i < COLORS; i++)
1651 		if (!draw_state(mi, i)) {
1652 			free_loop(mi);
1653 			return;
1654 		}
1655 	if (++lp->generation > MI_CYCLES(mi) || lp->dead) {
1656 		init_loop(mi);
1657 		return;
1658 	} else
1659 		do_gen(lp);
1660 
1661 	if (lp->redrawing) {
1662 		for (i = 0; i < REDRAWSTEP; i++) {
1663 			if ((*(lp->oldcells + lp->redrawpos))) {
1664 				drawcell(mi, lp->redrawpos % lp->bncols - lp->bx,
1665 					 lp->redrawpos / lp->bncols - lp->by,
1666 					 *(lp->oldcells + lp->redrawpos));
1667 			}
1668 			if (++(lp->redrawpos) >= lp->bncols * (lp->bnrows - lp->bx)) {
1669 				lp->redrawing = 0;
1670 				break;
1671 			}
1672 		}
1673 	}
1674 }
1675 
1676 #ifndef STANDALONE
1677 ENTRYPOINT void
refresh_loop(ModeInfo * mi)1678 refresh_loop (ModeInfo * mi)
1679 {
1680 	loopstruct *lp;
1681 
1682 	if (loops == NULL)
1683 		return;
1684 	lp = &loops[MI_SCREEN(mi)];
1685 
1686 	MI_CLEARWINDOW(mi);
1687 	lp->redrawing = 1;
1688 	lp->redrawpos = lp->by * lp->ncols + lp->bx;
1689 }
1690 #endif
1691 
1692 XSCREENSAVER_MODULE ("Loop", loop)
1693 
1694 #endif /* MODE_loop */
1695