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