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