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