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