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