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