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