source: trunk/third/xscreensaver/hacks/loop.c @ 20148

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