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