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