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