1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* life --- Conway's game of Life */
3
4 #if 0
5 static const char sccsid[] = "@(#)life.c 5.24 2007/01/18 xlockmore";
6
7 #endif
8
9 /*-
10 * Copyright (c) 1991 by Patrick J. Naughton.
11 * Copyright (c) 1997 by David Bagley.
12 *
13 * Permission to use, copy, modify, and distribute this software and its
14 * documentation for any purpose and without fee is hereby granted,
15 * provided that the above copyright notice appear in all copies and that
16 * both that copyright notice and this permission notice appear in
17 * supporting documentation.
18 *
19 * This file is provided AS IS with no warranties of any kind. The author
20 * shall have no liability with respect to the infringement of copyrights,
21 * trade secrets or any patents by this file or any part thereof. In no
22 * event will the author be liable for any lost revenue or profits or
23 * other special, indirect and consequential damages.
24 *
25 * Revision History:
26 * 18-Jan-2007: Added vertical option.
27 * 01-Mar-2003: Added shooters for triangular life.
28 * 26-Feb-2003: Added LWSS, MWSS, HWSS in shooter.
29 * 25-Feb-2003: Randomly rotate trilife
30 * 25-Jan-2003: Spawned a life.h
31 * 23-Jan-2003: Added life from Stephen Silver's Life Lexicon
32 * http://www.argentum.freeserve.co.uk/lex_home.htm
33 * 23-Jan-2003: Tri life from Carter Bays. Added B45/S34 which I use as
34 * the true trilife, also available B456/S45 & B45/S23.
35 * Right now the glider for trilife is not integrated into
36 * the "shooter" part of the program.
37 * Other neat ones are B4/S456, B46/S24, B4/S35, B456/S12,
38 * B3/S23, & B4/S46. See:
39 * http://www.cse.sc.edu/~bays/trilife3/home.html
40 * 15-Jan-2003: Moves on if screen blank or static
41 * 15-Jan-2003: Alternate life rules from Nathan Thompson's "HighLife"
42 * B36/S23 and "Day and Night" B3678/S34678 with
43 * discoveries by David I. Bell.
44 * See http://www.tip.net.au/~dbell/
45 * Other rules that may be neat:
46 * http://entropymine.com/jason/life/alt/
47 * "Diamoeba" B35678/S5678, "Move" B36(8)/S245
48 * 01-Nov-2000: Allocation checks
49 * 03-Oct-2000: Added more randomness in pattern 90 degree orientation and
50 * mirror image.
51 * 08-Dec-1997: Paul Callahan's B2o/S2m34 rule added.
52 * Described on the news site for cellular-automata.
53 * <ppc997@aber.ac.uk>
54 * http://www.cs.jhu.edu/~callahan/lifepage.html
55 * http://www.cs.jhu.edu/~callahan/hexrule.txt
56 * B2o/S2m34: Birth of x if 2o,
57 * Survival of x if 2m, 3, or 4 neighbors
58 * Assume symmetry.
59 * (2o, 2m, 2p)
60 * O O O . O .
61 * 2o: . x . 2m: . x O 2p: . x .
62 * . . . . . O
63 * Also Bob Andreen's rule (my own notation for consistency)
64 * B2o3o4m/S2om4o (original notation: 234'B/22'4S)
65 * <andreen@msmc.edu>
66 * O O O O O .
67 * 3o: . x O 3m: . x . 3p: . x O
68 * . . . O O .
69 *
70 * O O O O O O
71 * 4o: . x O 4m: . x O 4p: . x .
72 * . O O . O O
73 * Some other rules
74 * B2o3mp5/S12mp3o4mp6
75 * B23op4mp6/S12mp3p4o56
76 * B2o2c6/S13m
77 * 27-Oct-1997: xpm and ras capability added.
78 * 04-Jun-1997: Removed old algorithm, now use wator's. I could not
79 * understand it and had trouble adding more features.
80 * New algorithm is more efficient iff there lots of blank
81 * areas (ptr loop rather than a double array loop)
82 * 10-May-1997: Compatible with xscreensaver
83 * 07-May-1997: life neighbor option. Still have to fix -neighbors 3
84 * 07-Jan-1995: life now has a random soup pattern.
85 * 07-Dec-1994: life now has new organisms. They are now better centered.
86 * Some of the nonperiodic forms were removed. New life
87 * forms were taken from xlife (an AMAZING collection of life
88 * forms). life's gliders now come from the edge of the screen
89 * except when generated by a life form.
90 * 23-Nov-1994: Bug fix for different iconified window sizes
91 * 21-Jul-1994: Took out bzero & bcopy since memset & memcpy is more portable
92 * 10-Jun-1994: Changed name of function 'kill', which is a libc function on
93 * many systems from Victor Langeveld <vic@mbfys.kun.nl>
94 * Changes in original xlock
95 * 24-May-1991: Added wraparound code from johnson@bugs.comm.mot.com.
96 * Made old cells stay blue.
97 * Made batchcount control the number of generations until restart.
98 * 29-Jul-1990: support for multiple screens.
99 * 07-Feb-1990: remove bogus semi-colon after #include line.
100 * 15-Dec-1989: Fix for proper skipping of {White,Black}Pixel() in colors.
101 * 08-Oct-1989: Moved seconds() to an extern.
102 * 20-Sep-1989: Written, life algorithm courtesy of Jim Graham <flar@sun.com>
103 *
104 *
105 * References:
106 * Bays, Carter, "Cellular Automata in the Triangular Tessellation",
107 * 1994, Complex Systems 8 127-150
108 * Bays, Carter, "A Note on the Game of Life in Hexagonal and Pentagonal
109 * Tesselations", 2005, Complex Systems 15 245-252
110 */
111
112 /*-
113 Grid Number of Neighbors
114 ---- ------------------
115 Square 4 or 8
116 Hexagon 6
117 Triangle 3, 9, or 12
118 Pentagon 5 or 7
119
120 Conway's Life: -neighbors 8 -rule B3/S23 LIFE, CONWAY
121 Other things to try:
122 -neighbors 8 -rule B36/S23 <HIGHLIFE, BELL>
123 -neighbors 8 -rule B3678/S34678 <DAY_NIGHT, THOMPSON>
124 -neighbors 4 -rule B2/S234
125 -neighbors 6 -rule B3/S23
126 -neighbors 3 -rule B23/S12
127 -neighbors 6 -rule B2o/S2m34 <CALLAHAN>
128 -neighbors 6 -rule B2o3o4m/S2om4o <ANDREEN>
129 -neighbors 6 -rule B2/S35 <BAYS>
130 -neighbors 12 -rule B45/S34 <TRILIFE, BAYS>
131 -neighbors 12 -rule B456/S45 <TRILIFE1, BAYS>
132 -neighbors 12 -rule B45/S23 <TRILIFE2, BAYS>
133 -neighbors 5 -rule B2S24
134 -neighbors 7 -rule B346/S23
135 -neighbors 9 -rule B34/S3
136 */
137
138 #ifdef STANDALONE
139 #define MODE_life
140 #define DEFAULTS "*delay: 750000 \n" \
141 "*count: 40 \n" \
142 "*cycles: 140 \n" \
143 "*size: 0 \n" \
144 "*ncolors: 200 \n" \
145 "*bitmap: \n" \
146 "*verbose: False \n" \
147
148 # define reshape_life 0
149 # define life_handle_event 0
150 #define UNIFORM_COLORS
151 #include "xlockmore.h" /* in xscreensaver distribution */
152 #else /* STANDALONE */
153 #include "xlock.h" /* in xlockmore distribution */
154 #include "color.h"
155 #define DO_STIPPLE
156 #include "iostuff.h"
157 #endif /* STANDALONE */
158 #include "automata.h"
159
160 #ifdef MODE_life
161 #define LIFE_NAMES 1
162 #include "life.h"
163
164 #ifdef LIFE_NAMES
165 #define DEF_LABEL "True"
166 #define FONT_HEIGHT 19
167 #define FONT_WIDTH 15
168 #endif
169 #define DEF_DRAW "True"
170 #define DEF_NEIGHBORS "0" /* choose best value (8) */
171 #define DEF_SERIAL "False"
172 #define DEF_REPEAT "0" /* Frequently 2, 12 */
173
174 #if 1
175 #define DEF_RULE "G" /* All rules with known gliders */
176 #else
177 #define DEF_RULE "P" /* All rules with known patterns, currently G==P */
178 #define DEF_RULE "B3/S23" /* LIFE */
179 #define DEF_RULE "B36/S23" /* HIGHLIFE */
180 #define DEF_RULE "B3678/S34678" /* "B3678/S34678" DAY_NIGHT*/
181 #define DEF_RULE "B2o/S2m34" /* CALLAHAN */
182 #define DEF_RULE "B2m3o4m/S2om4o" /* ANDREEN */
183 #define DEF_RULE "B2/S35" /* BAYS */
184 #define DEF_RULE "B45/S34" /* TRILIFE */
185 #define DEF_RULE "B456/S45" /* TRILIFE1 */
186 #define DEF_RULE "B45/S23" /* TRILIFE2 */
187 #endif
188
189 #define DEF_VERTICAL "False"
190 #define DEF_GLIDERSEARCH "False"
191 #define DEF_PATTERNSEARCH "False"
192 #define DEF_NONTOT "False"
193 #define DEF_CONWAY "False"
194 #define DEF_HIGHLIFE "False"
195 #define DEF_DAY_NIGHT "False"
196 #define DEF_CALLAHAN "False"
197 #define DEF_ANDREEN "False"
198 #define DEF_BAYS "False"
199 #define DEF_TRILIFE "False"
200 #define DEF_TRILIFE1 "False"
201 #define DEF_TRILIFE2 "False"
202 #define DEF_PENT "False" /* 5 neighbors */
203 #define DEF_PENT2 "False" /* 7 neighbors */
204 /* calling Bays' rule pent2 as its easier to remember, but found first */
205
206 #ifdef LIFE_NAMES
207 static Bool label;
208 #endif
209 static Bool draw;
210 static int neighbors;
211 static int repeat;
212 static char *rule;
213 static char *lifefile;
214 static Bool serial;
215 static Bool vertical;
216 static Bool glidersearch;
217 static Bool patternsearch;
218 static Bool nontot;
219 static Bool conway;
220 static Bool highlife;
221 static Bool daynight;
222 static Bool callahan;
223 static Bool andreen;
224 static Bool bays;
225 static Bool trilife;
226 static Bool trilife1;
227 static Bool trilife2;
228 static Bool pent;
229 static Bool pent2;
230
231 static XrmOptionDescRec opts[] =
232 {
233 #ifdef LIFE_NAMES
234 {(char *) "-label", (char *) ".life.label", XrmoptionNoArg, (caddr_t) "on"},
235 {(char *) "+label", (char *) ".life.label", XrmoptionNoArg, (caddr_t) "off"},
236 #endif
237 {(char *) "-draw", (char *) ".life.draw", XrmoptionNoArg, (caddr_t) "on"},
238 {(char *) "+draw", (char *) ".life.draw", XrmoptionNoArg, (caddr_t) "off"},
239 {(char *) "-neighbors", (char *) ".life.neighbors", XrmoptionSepArg, (caddr_t) NULL},
240 {(char *) "-repeat", (char *) ".life.repeat", XrmoptionSepArg, (caddr_t) NULL},
241 {(char *) "-rule", (char *) ".life.rule", XrmoptionSepArg, (caddr_t) NULL},
242 {(char *) "-lifefile", (char *) ".life.lifefile", XrmoptionSepArg, (caddr_t) NULL},
243 {(char *) "-serial", (char *) ".life.serial", XrmoptionNoArg, (caddr_t) "on"},
244 {(char *) "+serial", (char *) ".life.serial", XrmoptionNoArg, (caddr_t) "off"},
245 {(char *) "-vertical", (char *) ".life.vertical", XrmoptionNoArg, (caddr_t) "on"},
246 {(char *) "+vertical", (char *) ".life.vertical", XrmoptionNoArg, (caddr_t) "off"},
247 {(char *) "-glidersearch", (char *) ".life.glidersearch", XrmoptionNoArg, (caddr_t) "on"},
248 {(char *) "+glidersearch", (char *) ".life.glidersearch", XrmoptionNoArg, (caddr_t) "off"},
249 {(char *) "-patternsearch", (char *) ".life.patternsearch", XrmoptionNoArg, (caddr_t) "on"},
250 {(char *) "+patternsearch", (char *) ".life.patternsearch", XrmoptionNoArg, (caddr_t) "off"},
251 {(char *) "-nontot", (char *) ".life.nontot", XrmoptionNoArg, (caddr_t) "on"},
252 {(char *) "+nontot", (char *) ".life.nontot", XrmoptionNoArg, (caddr_t) "off"},
253 {(char *) "-conway", (char *) ".life.conway", XrmoptionNoArg, (caddr_t) "on"},
254 {(char *) "+conway", (char *) ".life.conway", XrmoptionNoArg, (caddr_t) "off"},
255 {(char *) "-highlife", (char *) ".life.highlife", XrmoptionNoArg, (caddr_t) "on"},
256 {(char *) "+highlife", (char *) ".life.highlife", XrmoptionNoArg, (caddr_t) "off"},
257 {(char *) "-daynight", (char *) ".life.daynight", XrmoptionNoArg, (caddr_t) "on"},
258 {(char *) "+daynight", (char *) ".life.daynight", XrmoptionNoArg, (caddr_t) "off"},
259 {(char *) "-callahan", (char *) ".life.callahan", XrmoptionNoArg, (caddr_t) "on"},
260 {(char *) "+callahan", (char *) ".life.callahan", XrmoptionNoArg, (caddr_t) "off"},
261 {(char *) "-andreen", (char *) ".life.andreen", XrmoptionNoArg, (caddr_t) "on"},
262 {(char *) "+andreen", (char *) ".life.andreen", XrmoptionNoArg, (caddr_t) "off"},
263 {(char *) "-bays", (char *) ".life.bays", XrmoptionNoArg, (caddr_t) "on"},
264 {(char *) "+bays", (char *) ".life.bays", XrmoptionNoArg, (caddr_t) "off"},
265 {(char *) "-trilife", (char *) ".life.trilife", XrmoptionNoArg, (caddr_t) "on"},
266 {(char *) "+trilife", (char *) ".life.trilife", XrmoptionNoArg, (caddr_t) "off"},
267 {(char *) "-trilife1", (char *) ".life.trilife1", XrmoptionNoArg, (caddr_t) "on"},
268 {(char *) "+trilife1", (char *) ".life.trilife1", XrmoptionNoArg, (caddr_t) "off"},
269 {(char *) "-trilife2", (char *) ".life.trilife2", XrmoptionNoArg, (caddr_t) "on"},
270 {(char *) "+trilife2", (char *) ".life.trilife2", XrmoptionNoArg, (caddr_t) "off"},
271 {(char *) "-pent", (char *) ".life.pent", XrmoptionNoArg, (caddr_t) "on"},
272 {(char *) "+pent", (char *) ".life.pent", XrmoptionNoArg, (caddr_t) "off"},
273 {(char *) "-pent2", (char *) ".life.pent2", XrmoptionNoArg, (caddr_t) "on"},
274 {(char *) "+pent2", (char *) ".life.pent2", XrmoptionNoArg, (caddr_t) "off"}
275 };
276 static argtype vars[] =
277 {
278 #ifdef LIFE_NAMES
279 {(void *) & label, (char *) "label", (char *) "Label", (char *) DEF_LABEL, t_Bool},
280 #endif
281 {(void *) & draw, (char *) "draw", (char *) "Draw", (char *) DEF_DRAW, t_Bool},
282 {(void *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
283 {(void *) & repeat, (char *) "repeat", (char *) "Repeat", (char *) DEF_REPEAT, t_Int},
284 {(void *) & rule, (char *) "rule", (char *) "Rule", (char *) DEF_RULE, t_String},
285 #ifdef STANDALONE
286 {(void *) & lifefile, (char *) "lifefile", (char *) "LifeFile", (char *) "/dev/null", t_String},
287 #else
288 {(void *) & lifefile, (char *) "lifefile", (char *) "LifeFile", (char *) "", t_String},
289 #endif
290 {(void *) & serial, (char *) "serial", (char *) "Serial", (char *) DEF_SERIAL, t_Bool},
291 {(void *) & vertical, (char *) "vertical", (char *) "Vertical", (char *) DEF_VERTICAL, t_Bool},
292 {(void *) & glidersearch, (char *) "glidersearch", (char *) "GliderSearch", (char *) DEF_GLIDERSEARCH, t_Bool},
293 {(void *) & patternsearch, (char *) "patternsearch", (char *) "PatternSearch", (char *) DEF_PATTERNSEARCH, t_Bool},
294 {(void *) & nontot, (char *) "nontot", (char *) "Nontot", (char *) DEF_NONTOT, t_Bool},
295 {(void *) & conway, (char *) "conway", (char *) "Conway", (char *) DEF_CONWAY, t_Bool},
296 {(void *) & highlife, (char *) "highlife", (char *) "HighLife", (char *) DEF_HIGHLIFE, t_Bool},
297 {(void *) & daynight, (char *) "daynight", (char *) "DayNight", (char *) DEF_DAY_NIGHT, t_Bool},
298 {(void *) & callahan, (char *) "callahan", (char *) "Callahan", (char *) DEF_CALLAHAN, t_Bool},
299 {(void *) & andreen, (char *) "andreen", (char *) "Andreen", (char *) DEF_ANDREEN, t_Bool},
300 {(void *) & bays, (char *) "bays", (char *) "Bays", (char *) DEF_BAYS, t_Bool},
301 {(void *) & trilife, (char *) "trilife", (char *) "TriLife", (char *) DEF_TRILIFE, t_Bool},
302 {(void *) & trilife1, (char *) "trilife1", (char *) "TriLife1", (char *) DEF_TRILIFE1, t_Bool},
303 {(void *) & trilife2, (char *) "trilife2", (char *) "TriLife2", (char *) DEF_TRILIFE2, t_Bool},
304 {(void *) & pent, (char *) "pent", (char *) "Pent", (char *) DEF_PENT, t_Bool},
305 {(void *) & pent2, (char *) "pent2", (char *) "Pent2", (char *) DEF_PENT2, t_Bool}
306 };
307 static OptionStruct desc[] =
308 {
309 #ifdef LIFE_NAMES
310 {(char *) "-/+label", (char *) "turn on/off name labeling"},
311 #endif
312 {(char *) "-/+draw", (char *) "turn on/off drawing to speed search"},
313 {(char *) "-neighbors num", (char *) "squares 4 or 8, hexagons 6, triangles 3, 9 or 12, pentagons 5 or 7"},
314 {(char *) "-repeat num", (char *) "repeat for period to exclude in search"}, /* this is not as good as Bays' signature idea */
315 {(char *) "-rule string", (char *) "B<birth_neighborhood>/S<survival_neighborhood> parameters"},
316 {(char *) "-lifefile file", (char *) "life file"},
317 {(char *) "-/+serial", (char *) "turn on/off picking of sequential patterns"},
318 {(char *) "-/+vertical", (char *) "change orientation for hexagons and triangles"},
319 {(char *) "-/+glidersearch", (char *) "search for gliders"},
320 {(char *) "-/+patternsearch", (char *) "search for patterns"},
321 {(char *) "-/+nontot", (char *) "turn on/off nontotalistic rule B3/S2ckan3 (known as Rule 3/2ab3)"},
322 {(char *) "-/+conway", (char *) "turn on/off Conway's original Life rule B3/S23"},
323 {(char *) "-/+highlife", (char *) "turn on/off Thompson's HighLife rule B36/S23"},
324 {(char *) "-/+daynight", (char *) "turn on/off Thompson's Day and Night rule B3678/S34678"},
325 {(char *) "-/+callahan", (char *) "turn on/off Callahan's hex rule B2o/S2m34"},
326 {(char *) "-/+andreen", (char *) "turn on/off Andreen's hex rule B2o3o4m/S2om4o"},
327 {(char *) "-/+bays", (char *) "turn on/off Bays' hex rule B2/S35"},
328 {(char *) "-/+trilife", (char *) "turn on/off Bays' tri rule B45/S34"},
329 {(char *) "-/+trilife1", (char *) "turn on/off Bays' tri rule B456/S45"},
330 {(char *) "-/+trilife2", (char *) "turn on/off Bays' tri rule B45/S23"},
331 {(char *) "-/+pent", (char *) "turn on/off Bagley's pentagon rule B2/S24"},
332 {(char *) "-/+pent2", (char *) "turn on/off Bays' pentagon rule B346/S23"}
333 };
334
335 ENTRYPOINT ModeSpecOpt life_opts =
336 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
337
338 #ifdef USE_MODULES
339 ModStruct life_description =
340 {"life", "init_life", "draw_life", "release_life",
341 "refresh_life", "change_life", "free_life", &life_opts,
342 750000, 40, 140, 0, 64, 1.0, "",
343 "Shows Conway's game of Life", 0, NULL};
344
345 #endif
346
347 #ifndef STANDALONE
348 /* aliases for vars defined in the bitmap file */
349 #define CELL_WIDTH image_width
350 #define CELL_HEIGHT image_height
351 #define CELL_BITS image_bits
352
353 #include "life.xbm"
354 #ifdef XBM_GRELB
355 #include "life2.xbm"
356 #define CELL2_WIDTH image2_width
357 #define CELL2_HEIGHT image2_height
358 #define CELL2_BITS image2_bits
359 static XImage bimage =
360 {
361 0, 0, 0, XYBitmap, 0, LSBFirst, 8, LSBFirst, 8, 1
362 };
363 #endif
364
365 #ifdef HAVE_XPM
366 #define CELL_NAME image_name
367 #if 1
368 static char *image_name[] =
369 {(char *) ""};
370 #else
371 /* Kind of boring... */
372 #include "life.xpm"
373 #endif
374 #define DEFAULT_XPM 0
375 #endif
376 #endif
377
378 #define REDRAWSTEP 2000 /* How many cells to draw per cycle */
379 #define MINGRIDSIZE 20
380 #define MINSIZE 4
381 #define DEAD 0
382 #define LIVE 1
383 #define STATES 2
384 #define SOUPPERCENT 30
385 #define SOUPSIZE(s) MAX(s/4,10)
386 #define SetListFromGet(c,r) if (!setcell(mi,c,r,LIVE)) return
387 /* Triangles are stored left/right not up/down */
388 #define SetList(c,r) if (lp->polygon == 3) { \
389 if (!setcell(mi,r,c,LIVE)) return; \
390 } else \
391 if (!setcell(mi,c,r,LIVE)) return
392
393 typedef struct {
394 long position;
395 unsigned short age;
396 unsigned char state;
397 unsigned char toggle;
398 } cellstruct;
399
400 /* Doubly linked list */
401 typedef struct _CellList {
402 cellstruct info;
403 struct _CellList *previous, *next;
404 } CellList;
405
406 typedef struct {
407 Bool painted, vertical;
408 paramstruct param;
409 int pattern, patterned_rule;
410 int pixelmode;
411 int generation;
412 int xs, ys, xb, yb; /* cell size, grid border */
413 int nrows, ncols, npositions;
414 int width, height;
415 int state;
416 int noChangeCount;
417 int redrawing, redrawpos;
418 int ncells[STATES];
419 CellList *last[STATES], *first[STATES];
420 CellList **arr;
421 union {
422 XPoint hexagon[6];
423 XPoint triangle[2][3];
424 XPoint pentagon[4][5];
425 } shape;
426 XImage *logo;
427 #ifdef XBM_GRELB
428 XImage *logo2;
429 #endif
430 Colormap cmap;
431 unsigned long black;
432 int graphics_format;
433 GC backGC;
434 int neighbors, polygon;
435 int nontot, conway, highlife, daynight, callahan, andreen, bays;
436 int trilife, trilife1, trilife2, pent, pent2;
437 int allPatterns, allGliders;
438 paramstruct input_param;
439 int labelOffsetX, labelOffsetY;
440 Bool foundBirth, foundSurvival;
441 char ruleString[80], nameString[80];
442 } lifestruct;
443
444 static lifestruct *lifes = (lifestruct *) NULL;
445
446 static char *filePattern = (char *) NULL;
447
448 static char hexagonalNontot[] = {'o', 'm', 'p'};
449 static char mooreNontot[] = {'c', 'e', 'k', 'a', 'i', 'n',
450 'y', 'q', 'j', 'r', 't', 'w', 'z', 'f'};
451
452 static int
invplot(int local_neighbors)453 invplot(int local_neighbors)
454 {
455 switch (local_neighbors) {
456 case 3:
457 return 0;
458 case 4:
459 return 1;
460 case 5:
461 return 2;
462 case 6:
463 return 3;
464 case 7:
465 return 4;
466 case 8:
467 return 5;
468 case 9:
469 return 6;
470 case 12:
471 return 7;
472 default:
473 (void) fprintf(stderr, "no neighborhood like %d known\n",
474 local_neighbors);
475 return 3;
476 }
477 }
478
nontotToIndex(char letter)479 static int nontotToIndex(char letter)
480 {
481 switch (letter) { /* take advantage that there is no overlap */
482 case 'c':
483 case 'o':
484 return 0;
485 case 'e':
486 case 'm':
487 return 1;
488 case 'k':
489 case 'p':
490 return 2;
491 case 'a':
492 return 3;
493 case 'i':
494 return 4;
495 case 'n':
496 return 5;
497 case 'y':
498 return 6;
499 case 'q':
500 return 7;
501 case 'j':
502 return 8;
503 case 'r':
504 return 9;
505 case 't':
506 return 10;
507 case 'w':
508 return 11;
509 case 'z':
510 return 12;
511 case 'f':
512 return 13;
513 default:
514 return 14;
515 }
516 }
517
518 static int
codeToPatternedRule(int local_neighbors,paramstruct param)519 codeToPatternedRule(int local_neighbors, paramstruct param)
520 {
521 unsigned int i;
522 int g, neighborKind;
523
524 neighborKind = invplot(local_neighbors);
525 switch (local_neighbors) {
526 case 5:
527 for (i = 0; i < LIFE_5RULES; i++)
528 if (param_5rules[i].birth == param.birth &&
529 param_5rules[i].survival == param.survival) {
530 for (g = 0; g < maxgroups[neighborKind]; g++) {
531 if (param_5rules[i].birthGroup[g] !=
532 param.birthGroup[g] ||
533 param_5rules[i].survivalGroup[g] !=
534 param.survivalGroup[g]) {
535 break;
536 }
537 }
538 if (g == maxgroups[neighborKind])
539 return i;
540 }
541 return LIFE_5RULES;
542 case 6:
543 for (i = 0; i < LIFE_6RULES; i++)
544 if (param_6rules[i].birth == param.birth &&
545 param_6rules[i].survival == param.survival) {
546 for (g = 0; g < maxgroups[neighborKind]; g++) {
547 if (param_6rules[i].birthGroup[g] !=
548 param.birthGroup[g] ||
549 param_6rules[i].survivalGroup[g] !=
550 param.survivalGroup[g]) {
551 break;
552 }
553 }
554 if (g == maxgroups[neighborKind])
555 return i;
556 }
557 return LIFE_6RULES;
558 case 7:
559 for (i = 0; i < LIFE_7RULES; i++)
560 if (param_7rules[i].birth == param.birth &&
561 param_7rules[i].survival == param.survival) {
562 for (g = 0; g < maxgroups[neighborKind]; g++) {
563 if (param_7rules[i].birthGroup[g] !=
564 param.birthGroup[g] ||
565 param_7rules[i].survivalGroup[g] !=
566 param.survivalGroup[g]) {
567 break;
568 }
569 }
570 if (g == maxgroups[neighborKind])
571 return i;
572 }
573 return LIFE_7RULES;
574 case 8:
575 for (i = 0; i < LIFE_8RULES; i++)
576 if (param_8rules[i].birth == param.birth &&
577 param_8rules[i].survival == param.survival) {
578 for (g = 0; g < maxgroups[neighborKind]; g++) {
579 if (param_8rules[i].birthGroup[g] !=
580 param.birthGroup[g] ||
581 param_8rules[i].survivalGroup[g] !=
582 param.survivalGroup[g]) {
583 break;
584 }
585 }
586 if (g == maxgroups[neighborKind])
587 return i;
588 }
589 return LIFE_8RULES;
590 case 9:
591 for (i = 0; i < LIFE_9RULES; i++)
592 if (param_9rules[i].birth == param.birth &&
593 param_9rules[i].survival == param.survival) {
594 for (g = 0; g < maxgroups[neighborKind]; g++) {
595 if (param_9rules[i].birthGroup[g] !=
596 param.birthGroup[g] ||
597 param_9rules[i].survivalGroup[g] !=
598 param.survivalGroup[g]) {
599 break;
600 }
601 }
602 if (g == maxgroups[neighborKind])
603 return i;
604 }
605 return LIFE_9RULES;
606 case 12:
607 for (i = 0; i < LIFE_12RULES; i++)
608 if (param_12rules[i].birth == param.birth &&
609 param_12rules[i].survival == param.survival) {
610 for (g = 0; g < maxgroups[neighborKind]; g++) {
611 if (param_12rules[i].birthGroup[g] !=
612 param.birthGroup[g] ||
613 param_12rules[i].survivalGroup[g] !=
614 param.survivalGroup[g]) {
615 break;
616 }
617 }
618 if (g == maxgroups[neighborKind])
619 return i;
620 }
621 return LIFE_12RULES;
622 }
623 return 0;
624 }
625
626 static void
copyFromPatternedRule(int local_neighbors,paramstruct * param,int patterned_rule)627 copyFromPatternedRule(int local_neighbors, paramstruct * param,
628 int patterned_rule)
629 {
630 int i, neighborKind;
631
632 neighborKind = invplot(local_neighbors);
633 switch (local_neighbors) {
634 case 5:
635 param->birth = param_5rules[patterned_rule].birth;
636 param->survival = param_5rules[patterned_rule].survival;
637 for (i = 0; i < maxgroups[neighborKind]; i++) {
638 param->birthGroup[i] =
639 param_5rules[patterned_rule].birthGroup[i];
640 param->survivalGroup[i] =
641 param_5rules[patterned_rule].survivalGroup[i];
642 }
643 break;
644 case 6:
645 param->birth = param_6rules[patterned_rule].birth;
646 param->survival = param_6rules[patterned_rule].survival;
647 for (i = 0; i < maxgroups[neighborKind]; i++) {
648 param->birthGroup[i] =
649 param_6rules[patterned_rule].birthGroup[i];
650 param->survivalGroup[i] =
651 param_6rules[patterned_rule].survivalGroup[i];
652 }
653 break;
654 case 7:
655 param->birth = param_7rules[patterned_rule].birth;
656 param->survival = param_7rules[patterned_rule].survival;
657 for (i = 0; i < maxgroups[neighborKind]; i++) {
658 param->birthGroup[i] =
659 param_7rules[patterned_rule].birthGroup[i];
660 param->survivalGroup[i] =
661 param_7rules[patterned_rule].survivalGroup[i];
662 }
663 break;
664 case 8:
665 param->birth = param_8rules[patterned_rule].birth;
666 param->survival = param_8rules[patterned_rule].survival;
667 for (i = 0; i < maxgroups[neighborKind]; i++) {
668 param->birthGroup[i] =
669 param_8rules[patterned_rule].birthGroup[i];
670 param->survivalGroup[i] =
671 param_8rules[patterned_rule].survivalGroup[i];
672 }
673 break;
674 case 9:
675 param->birth = param_9rules[patterned_rule].birth;
676 param->survival = param_9rules[patterned_rule].survival;
677 for (i = 0; i < maxgroups[neighborKind]; i++) {
678 param->birthGroup[i] =
679 param_9rules[patterned_rule].birthGroup[i];
680 param->survivalGroup[i] =
681 param_9rules[patterned_rule].survivalGroup[i];
682 }
683 break;
684 case 12:
685 param->birth = param_12rules[patterned_rule].birth;
686 param->survival = param_12rules[patterned_rule].survival;
687 for (i = 0; i < maxgroups[neighborKind]; i++) {
688 param->birthGroup[i] =
689 param_12rules[patterned_rule].birthGroup[i];
690 param->survivalGroup[i] =
691 param_12rules[patterned_rule].survivalGroup[i];
692 }
693 break;
694 }
695 }
696
697 static char
getNontot(int neighbors,int offset)698 getNontot(int neighbors, int offset) {
699 if (neighbors == 6 && offset >= 0 && offset < 3)
700 return hexagonalNontot[offset];
701 else if (neighbors == 8 && offset >= 0 && offset < 14)
702 return mooreNontot[offset];
703 else
704 return 'a' + offset; /* do something */
705 }
706
707 static void
printRule(int local_neighbors,char * string,paramstruct param,Bool verbose)708 printRule(int local_neighbors, char * string, paramstruct param, Bool verbose)
709 {
710 int i = 1, l, g, neighborKind;
711 Bool found;
712
713 string[0] = 'B';
714 if (verbose)
715 (void) fprintf(stdout,
716 "rule (Birth/Survival %d neighborhood): ",
717 local_neighbors);
718 neighborKind = invplot(local_neighbors);
719 for (l = 0; l <= local_neighbors && l < 10; l++) {
720 int bPlaced = -1;
721 if ((param.birth & (1 << l)) != 0) {
722 (void) sprintf(&(string[i]), "%d", l);
723 i++;
724 } else if (l >= FIRSTGROUP && l < FIRSTGROUP + maxgroups[neighborKind]) {
725 for (g = 0; g < groupnumber[neighborKind][l - FIRSTGROUP]; g++) {
726 if (param.birthGroup[l - FIRSTGROUP] & (1 << g)) {
727 if (bPlaced != l) {
728 (void) sprintf(&(string[i]), "%d", l);
729 bPlaced = l;
730 i++;
731 }
732
733 (void) sprintf(&(string[i]), "%c",
734 getNontot(local_neighbors, g));
735 i++;
736 }
737 }
738 }
739 }
740 (void) sprintf(&(string[i]), "/S");
741 i += 2;
742 for (l = 0; l <= local_neighbors && l < 10; l++) {
743 int sPlaced = -1;
744 if ((param.survival & (1 << l)) != 0) {
745 (void) sprintf(&(string[i]), "%d", l);
746 i++;
747 } else if (l >= FIRSTGROUP && l < FIRSTGROUP + maxgroups[neighborKind]) {
748 for (g = 0; g < groupnumber[neighborKind][l - FIRSTGROUP]; g++) {
749 if (param.survivalGroup[l - FIRSTGROUP] & (1 << g)) {
750 if (sPlaced != l) {
751 (void) sprintf(&(string[i]), "%d", l);
752 sPlaced = l;
753 i++;
754 }
755
756 (void) sprintf(&(string[i]), "%c",
757 getNontot(local_neighbors, g));
758 i++;
759 }
760 }
761 }
762 }
763 string[i] = '\0';
764 found = False;
765 for (l = 0; l < maxgroups[neighborKind]; l++) {
766 if (param.birthGroup[l] || param.survivalGroup[l]) {
767 found = True;
768 break;
769 }
770 }
771 if (verbose) {
772 (void) fprintf(stdout, "%s\nbinary rule%s: Birth 0x%X, Survival 0x%X\n",
773 string, ((found) ? " (nongroup)" : ""),
774 param.birth, param.survival);
775 if (found) {
776 for (l = 0; l < maxgroups[neighborKind]; l++) {
777 (void) fprintf(stdout,
778 "groups in neighborhood %d: Birth 0x%X, Survival 0x%X\n",
779 l + FIRSTGROUP, param.birthGroup[l], param.survivalGroup[l]);
780 }
781 }
782 }
783 }
784
785 static int
positionOfNeighbor(lifestruct * lp,int n,int col,int row)786 positionOfNeighbor(lifestruct * lp, int n, int col, int row)
787 {
788 int dir = n * (360 / lp->neighbors);
789
790 if (lp->polygon == 4 || lp->polygon == 6) {
791 switch (dir) {
792 case 0:
793 col = (col + 1 == lp->ncols) ? 0 : col + 1;
794 break;
795 case 45:
796 col = (col + 1 == lp->ncols) ? 0 : col + 1;
797 row = (!row) ? lp->nrows - 1 : row - 1;
798 break;
799 case 60:
800 if (!(row & 1))
801 col = (col + 1 == lp->ncols) ? 0 : col + 1;
802 row = (!row) ? lp->nrows - 1 : row - 1;
803 break;
804 case 90:
805 row = (!row) ? lp->nrows - 1 : row - 1;
806 break;
807 case 120:
808 if (row & 1)
809 col = (!col) ? lp->ncols - 1 : col - 1;
810 row = (!row) ? lp->nrows - 1 : row - 1;
811 break;
812 case 135:
813 col = (!col) ? lp->ncols - 1 : col - 1;
814 row = (!row) ? lp->nrows - 1 : row - 1;
815 break;
816 case 180:
817 col = (!col) ? lp->ncols - 1 : col - 1;
818 break;
819 case 225:
820 col = (!col) ? lp->ncols - 1 : col - 1;
821 row = (row + 1 == lp->nrows) ? 0 : row + 1;
822 break;
823 case 240:
824 if (row & 1)
825 col = (!col) ? lp->ncols - 1 : col - 1;
826 row = (row + 1 == lp->nrows) ? 0 : row + 1;
827 break;
828 case 270:
829 row = (row + 1 == lp->nrows) ? 0 : row + 1;
830 break;
831 case 300:
832 if (!(row & 1))
833 col = (col + 1 == lp->ncols) ? 0 : col + 1;
834 row = (row + 1 == lp->nrows) ? 0 : row + 1;
835 break;
836 case 315:
837 col = (col + 1 == lp->ncols) ? 0 : col + 1;
838 row = (row + 1 == lp->nrows) ? 0 : row + 1;
839 break;
840 default:
841 (void) fprintf(stderr, "wrong direction %d\n", dir);
842 }
843 } else if (lp->polygon == 3) {
844 if ((col + row) & 1) { /* right */
845 switch (dir) {
846 case 0:
847 col = (!col) ? lp->ncols - 1 : col - 1;
848 break;
849 case 30:
850 case 40:
851 col = (!col) ? lp->ncols - 1 : col - 1;
852 row = (row + 1 == lp->nrows) ? 0 : row + 1;
853 break;
854 case 60:
855 col = (!col) ? lp->ncols - 1 : col - 1;
856 if (row + 1 == lp->nrows)
857 row = 1;
858 else if (row + 2 == lp->nrows)
859 row = 0;
860 else
861 row = row + 2;
862 break;
863 case 80:
864 case 90:
865 if (row + 1 == lp->nrows)
866 row = 1;
867 else if (row + 2 == lp->nrows)
868 row = 0;
869 else
870 row = row + 2;
871 break;
872 case 120:
873 row = (row + 1 == lp->nrows) ? 0 : row + 1;
874 break;
875 case 150:
876 case 160:
877 col = (col + 1 == lp->ncols) ? 0 : col + 1;
878 row = (row + 1 == lp->nrows) ? 0 : row + 1;
879 break;
880 case 180:
881 col = (col + 1 == lp->ncols) ? 0 : col + 1;
882 break;
883 case 200:
884 case 210:
885 col = (col + 1 == lp->ncols) ? 0 : col + 1;
886 row = (!row) ? lp->nrows - 1 : row - 1;
887 break;
888 case 240:
889 row = (!row) ? lp->nrows - 1 : row - 1;
890 break;
891 case 270:
892 case 280:
893 if (!row)
894 row = lp->nrows - 2;
895 else if (!(row - 1))
896 row = lp->nrows - 1;
897 else
898 row = row - 2;
899 break;
900 case 300:
901 col = (!col) ? lp->ncols - 1 : col - 1;
902 if (!row)
903 row = lp->nrows - 2;
904 else if (!(row - 1))
905 row = lp->nrows - 1;
906 else
907 row = row - 2;
908 break;
909 case 320:
910 case 330:
911 col = (!col) ? lp->ncols - 1 : col - 1;
912 row = (!row) ? lp->nrows - 1 : row - 1;
913 break;
914 default:
915 (void) fprintf(stderr, "wrong direction %d\n",
916 dir);
917 }
918 } else { /* left */
919 switch (dir) {
920 case 0:
921 col = (col + 1 == lp->ncols) ? 0 : col + 1;
922 break;
923 case 30:
924 case 40:
925 col = (col + 1 == lp->ncols) ? 0 : col + 1;
926 row = (!row) ? lp->nrows - 1 : row - 1;
927 break;
928 case 60:
929 col = (col + 1 == lp->ncols) ? 0 : col + 1;
930 if (!row)
931 row = lp->nrows - 2;
932 else if (row == 1)
933 row = lp->nrows - 1;
934 else
935 row = row - 2;
936 break;
937 case 80:
938 case 90:
939 if (!row)
940 row = lp->nrows - 2;
941 else if (row == 1)
942 row = lp->nrows - 1;
943 else
944 row = row - 2;
945 break;
946 case 120:
947 row = (!row) ? lp->nrows - 1 : row - 1;
948 break;
949 case 150:
950 case 160:
951 col = (!col) ? lp->ncols - 1 : col - 1;
952 row = (!row) ? lp->nrows - 1 : row - 1;
953 break;
954 case 180:
955 col = (!col) ? lp->ncols - 1 : col - 1;
956 break;
957 case 200:
958 case 210:
959 col = (!col) ? lp->ncols - 1 : col - 1;
960 row = (row + 1 == lp->nrows) ? 0 : row + 1;
961 break;
962 case 240:
963 row = (row + 1 == lp->nrows) ? 0 : row + 1;
964 break;
965 case 270:
966 case 280:
967 if (row + 1 == lp->nrows)
968 row = 1;
969 else if (row + 2 == lp->nrows)
970 row = 0;
971 else
972 row = row + 2;
973 break;
974 case 300:
975 col = (col + 1 == lp->ncols) ? 0 : col + 1;
976 if (row + 1 == lp->nrows)
977 row = 1;
978 else if (row + 2 == lp->nrows)
979 row = 0;
980 else
981 row = row + 2;
982 break;
983 case 320:
984 case 330:
985 col = (col + 1 == lp->ncols) ? 0 : col + 1;
986 row = (row + 1 == lp->nrows) ? 0 : row + 1;
987 break;
988 default:
989 (void) fprintf(stderr, "wrong direction %d\n",
990 dir);
991 }
992 }
993 } else {
994 int orient = ((row & 1) * 2 + col) % 4;
995 switch (orient) { /* up, down, left, right */
996 case 0:
997 switch (dir) {
998 case 0:
999 col++;
1000 break;
1001 case 51: /* 5 */
1002 case 72: /* 7 */
1003 col = (col + 2 >= lp->ncols) ? 0 : col + 2;
1004 break;
1005 case 102: /* 7 corner */
1006 col = (col + 3 >= lp->ncols) ? 1 : col + 3;
1007 row = (row == 0) ? lp->nrows - 1 : row - 1;
1008 break;
1009 case 144: /* 5 */
1010 case 153: /* 7 */
1011 col++;
1012 row = (row == 0) ? lp->nrows - 1 : row - 1;
1013 break;
1014 case 204: /* 5 */
1015 case 216: /* 7 */
1016 row = (row == 0) ? lp->nrows - 1 : row - 1;
1017 break;
1018 case 255: /* 7 */
1019 col = (col == 0) ? lp->ncols - 1 : col - 1;
1020 row = (row == 0) ? lp->nrows - 1 : row - 1;
1021 break;
1022 case 288: /* 5 */
1023 case 306: /* 7 */
1024 col = (col == 0) ? lp->ncols - 1 : col - 1;
1025 break;
1026 default:
1027 (void) fprintf(stderr, "wrong direction %d\n",
1028 dir);
1029 }
1030 break;
1031 case 1:
1032 switch (dir) {
1033 case 0:
1034 col--;
1035 break;
1036 case 51: /* 7 */
1037 case 72: /* 5 */
1038 col = (col == 1) ? lp->ncols - 1 : col - 2;
1039 break;
1040 case 102: /* 7 */
1041 col = (col == 1) ? lp->ncols - 2 : col - 3;
1042 row = (row + 1 == lp->nrows) ? 0 : row + 1;
1043 break;
1044 case 144: /* 7 */
1045 case 153: /* 5 */
1046 col--;
1047 row = (row + 1 == lp->nrows) ? 0 : row + 1;
1048 break;
1049 case 204: /* 7 */
1050 case 216: /* 5 */
1051 row = (row + 1 == lp->nrows) ? 0 : row + 1;
1052 break;
1053 case 255: /* 7 */
1054 col = (col + 1 >= lp->ncols) ? 0 : col + 1;
1055 row = (row + 1 == lp->nrows) ? 0 : row + 1;
1056 break;
1057 case 288: /* 7 */
1058 case 306: /* 5 */
1059 col = (col + 1 >= lp->ncols) ? 0 : col + 1;
1060 break;
1061 default:
1062 (void) fprintf(stderr, "wrong direction %d\n",
1063 dir);
1064 }
1065 break;
1066 case 2:
1067 switch (dir) {
1068 case 0:
1069 col = (col + 1 >= lp->ncols) ? 0 : col + 1;
1070 break;
1071 case 51: /* 7 */
1072 case 72: /* 5 */
1073 row = (row == 0) ? lp->nrows - 1 : row - 1;
1074 col++;
1075 break;
1076 case 102: /* 7 */
1077 col = (col == 0) ? lp->ncols - 1 : col - 1;
1078 row = (row == 0) ? lp->nrows - 1 : row - 1;
1079 break;
1080 case 144: /* 5 */
1081 case 153: /* 7 */
1082 col = (col == 0) ? lp->ncols - 2 : col - 2;
1083 break;
1084 case 204: /* 7 */
1085 case 216: /* 5 */
1086 col = (col == 0) ? lp->ncols - 1 : col - 1;
1087 break;
1088 case 255: /* 7 */
1089 row = (row + 1 == lp->nrows) ? 0 : row + 1;
1090 col = (col == 0) ? lp->ncols - 1 : col - 1;
1091 break;
1092 case 288: /* 5 */
1093 case 306: /* 7 */
1094 row = (row + 1 == lp->nrows) ? 0 : row + 1;
1095 break;
1096 default:
1097 (void) fprintf(stderr, "wrong direction %d\n",
1098 dir);
1099 }
1100 break;
1101 case 3:
1102 switch (dir) {
1103 case 0:
1104 col--;
1105 break;
1106 case 51: /* 7 */
1107 case 72: /* 5 */
1108 col = (col == 0) ? lp->ncols - 1 : col - 1;
1109 row = (row + 1 == lp->nrows) ? 0 : row + 1;
1110 break;
1111 case 102: /* 7 */
1112 col = (col + 1 >= lp->ncols) ? 0 : col + 1;
1113 row = (row + 1 == lp->nrows) ? 0 : row + 1;
1114 break;
1115 case 144: /* 5 */
1116 case 153: /* 7 */
1117 col = (col + 2 >= lp->ncols) ? 1 : col + 2;
1118 break;
1119 case 204: /* 7 */
1120 case 216: /* 5 */
1121 col = (col + 1 >= lp->ncols) ? 0 : col + 1;
1122 break;
1123 case 255: /* 7 */
1124 col = (col + 1 >= lp->ncols) ? 0 : col + 1;
1125 row = (row == 0) ? lp->nrows - 1 : row - 1;
1126 break;
1127 case 288: /* 5 */
1128 case 306: /* 7 */
1129 row = (row == 0) ? lp->nrows - 1 : row - 1;
1130 break;
1131 default:
1132 (void) fprintf(stderr, "wrong direction %d\n",
1133 dir);
1134 }
1135 break;
1136 default:
1137 (void) fprintf(stderr, "wrong orient %d\n",
1138 orient);
1139 }
1140 }
1141 return (row * lp->ncols + col);
1142 }
1143
1144 static void
parseRule(ModeInfo * mi,char * string)1145 parseRule(ModeInfo * mi, char * string)
1146 {
1147 lifestruct *lp = &lifes[MI_SCREEN(mi)];
1148 int n, g = 0, l = 0, neighborKind, lifeRule = 0;
1149 char serving = 0;
1150
1151 if (lp->foundBirth && lp->foundSurvival)
1152 return;
1153 lp->foundBirth = lp->foundSurvival = False;
1154 lp->input_param.birth = lp->input_param.survival = 0;
1155 for (n = 0; n < MAXGROUPS; n++) {
1156 lp->input_param.birthGroup[n] =
1157 lp->input_param.survivalGroup[n] = 0;
1158 }
1159 /* 8 is first so it will default to this */
1160 if (lp->nontot || lp->conway || lp->highlife || lp->daynight) {
1161 lp->neighbors = 8;
1162 lp->polygon = 4;
1163 neighborKind = invplot(lp->neighbors);
1164 lp->foundBirth = lp->foundSurvival = !MI_IS_FULLRANDOM(mi);
1165 if (lp->nontot)
1166 lifeRule = LIFE_8B3S2ckan3;
1167 else if (lp->conway)
1168 lifeRule = LIFE_8B3S23;
1169 else if (lp->highlife)
1170 lifeRule = LIFE_8B36S23;
1171 else if (lp->daynight)
1172 lifeRule = LIFE_8B3678S34678;
1173 lp->input_param.birth = param_8rules[lifeRule].birth;
1174 lp->input_param.survival = param_8rules[lifeRule].survival;
1175 for (n = 0; n < maxgroups[neighborKind]; n++) {
1176 lp->input_param.birthGroup[n] =
1177 param_8rules[lifeRule].birthGroup[n];
1178 lp->input_param.survivalGroup[n] =
1179 param_8rules[lifeRule].survivalGroup[n];
1180 }
1181 return;
1182 } else if (lp->callahan || lp->andreen || lp->bays) {
1183 lp->neighbors = 6;
1184 lp->polygon = 6;
1185 neighborKind = invplot(lp->neighbors);
1186 lp->foundBirth = lp->foundSurvival = !MI_IS_FULLRANDOM(mi);
1187 if (lp->callahan)
1188 lifeRule = LIFE_6B2oS2m34;
1189 else if (lp->andreen)
1190 lifeRule = LIFE_6B2o3o4mS2om4o;
1191 else if (lp->bays)
1192 lifeRule = LIFE_6B2S35;
1193 lp->input_param.birth = param_6rules[lifeRule].birth;
1194 lp->input_param.survival = param_6rules[lifeRule].survival;
1195 for (n = 0; n < maxgroups[neighborKind]; n++) {
1196 lp->input_param.birthGroup[n] =
1197 param_6rules[lifeRule].birthGroup[n];
1198 lp->input_param.survivalGroup[n] =
1199 param_6rules[lifeRule].survivalGroup[n];
1200 }
1201 return;
1202 } else if (lp->pent) {
1203 lp->neighbors = 5;
1204 lp->polygon = 5;
1205 neighborKind = invplot(lp->neighbors);
1206 lp->foundBirth = lp->foundSurvival = !MI_IS_FULLRANDOM(mi);
1207 lifeRule = LIFE_5B2S24;
1208 lp->input_param.birth = param_5rules[lifeRule].birth;
1209 lp->input_param.survival = param_5rules[lifeRule].survival;
1210 for (n = 0; n < maxgroups[neighborKind]; n++) {
1211 lp->input_param.birthGroup[n] =
1212 param_5rules[lifeRule].birthGroup[n];
1213 lp->input_param.survivalGroup[n] =
1214 param_5rules[lifeRule].survivalGroup[n];
1215 }
1216 return;
1217 } else if (lp->pent2) {
1218 lp->neighbors = 7;
1219 lp->polygon = 5;
1220 neighborKind = invplot(lp->neighbors);
1221 lp->foundBirth = lp->foundSurvival = !MI_IS_FULLRANDOM(mi);
1222 lifeRule = LIFE_7B346S23;
1223 lp->input_param.birth = param_7rules[lifeRule].birth;
1224 lp->input_param.survival = param_7rules[lifeRule].survival;
1225 for (n = 0; n < maxgroups[neighborKind]; n++) {
1226 lp->input_param.birthGroup[n] =
1227 param_7rules[lifeRule].birthGroup[n];
1228 lp->input_param.survivalGroup[n] =
1229 param_7rules[lifeRule].survivalGroup[n];
1230 }
1231 return;
1232 } else if (lp->trilife || lp->trilife1 || lp->trilife2) {
1233 lp->neighbors = 12;
1234 lp->polygon = 3;
1235 neighborKind = invplot(lp->neighbors);
1236 lp->foundBirth = lp->foundSurvival = !MI_IS_FULLRANDOM(mi);
1237 if (lp->trilife)
1238 lifeRule = LIFE_12B45S34;
1239 else if (lp->trilife1)
1240 lifeRule = LIFE_12B456S45;
1241 else if (lp->trilife2)
1242 lifeRule = LIFE_12B45S23;
1243 lp->input_param.birth = param_12rules[lifeRule].birth;
1244 lp->input_param.survival = param_12rules[lifeRule].survival;
1245 for (n = 0; n < maxgroups[neighborKind]; n++) {
1246 lp->input_param.birthGroup[n] =
1247 param_12rules[lifeRule].birthGroup[n];
1248 lp->input_param.survivalGroup[n] =
1249 param_12rules[lifeRule].survivalGroup[n];
1250 }
1251 return;
1252 }
1253 if (!lp->neighbors) {
1254 for (n = 0; n < NEIGHBORKINDS; n++) {
1255 if (neighbors == plots[n]) {
1256 lp->neighbors = neighbors;
1257 break;
1258 }
1259 if (n == NEIGHBORKINDS - 1) {
1260 #if 0
1261 lp->neighbors = plots[NRAND(NEIGHBORKINDS)];
1262 lp->neighbors = (LRAND() & 1) ? 4 : 8;
1263 lp->polygon = 4;
1264 #else
1265 lp->neighbors = 8;
1266 lp->polygon = 4;
1267 #endif
1268 break;
1269 }
1270 }
1271 }
1272 if (lp->neighbors == 6) {
1273 lp->polygon = 6;
1274 } else if (lp->neighbors % 3 == 0) { /* TRI */
1275 lp->polygon = 3;
1276 } else if (lp->neighbors == 5 || lp->neighbors == 7) {
1277 lp->polygon = 5;
1278 } else /* if (lp->neighbors == 4 || lp->neighbors == 8) */ {
1279 lp->polygon = 4;
1280 }
1281 neighborKind = invplot(lp->neighbors);
1282 if (rule) {
1283 n = 0;
1284 while (rule[n]) {
1285 if (rule[n] == 'P') {
1286 lp->allPatterns = True;
1287 lp->foundBirth = lp->foundSurvival = True;
1288 if (MI_IS_VERBOSE(mi))
1289 (void) fprintf(stdout,
1290 "rule: All rules with known patterns\n");
1291 return;
1292 } else if (rule[n] == 'G') {
1293 lp->allGliders = True;
1294 lp->foundBirth = lp->foundSurvival = True;
1295 if (MI_IS_VERBOSE(mi))
1296 (void) fprintf(stdout,
1297 "rule: All rules with known gliders\n");
1298 return;
1299 } else if (rule[n] == 'B' || rule[n] == 'F' || rule[n] == 'K') {
1300 /* lower case is used in groups */
1301 serving = 'B';
1302 } else if (rule[n] == 'S' || rule[n] == 'E' || rule[n] == 'L') {
1303 serving = 'S';
1304 } else if (rule[n] >= '0' && rule[n] <= '9') {
1305 int found = 0;
1306 if (l >= 0 && l <= 9 && l <= lp->neighbors) /* no 10, 11, 12 */
1307 l = rule[n] - '0';
1308 while (rule[n + 1] >= 'a' && rule[n + 1] <= 'z') {
1309 n++;
1310 g = nontotToIndex(rule[n]);
1311 if (l >= FIRSTGROUP && l < FIRSTGROUP + maxgroups[neighborKind] &&
1312 g >= 0 && g < groupnumber[neighborKind][l - FIRSTGROUP]) { /* Groupings */
1313 found++;
1314 if (serving == 'B') {
1315 lp->foundBirth = True;
1316 lp->input_param.birthGroup[l - FIRSTGROUP] |= (1 << g);
1317 } else if (serving == 'S') {
1318 lp->foundSurvival = True;
1319 lp->input_param.survivalGroup[l - FIRSTGROUP] |= (1 << g);
1320 }
1321 }
1322 }
1323 if (found == 0) {
1324 if (serving == 'B') {
1325 lp->foundBirth = True;
1326 lp->input_param.birth |= (1 << l);
1327 } else if (serving == 'S') {
1328 lp->foundSurvival = True;
1329 lp->input_param.survival |= (1 << l);
1330 }
1331 }
1332 }
1333 n++;
1334 }
1335 }
1336 if (!lp->foundBirth || !lp->foundSurvival) {
1337 /* Default to known interesting rules if rule does not make sense */
1338 lp->allGliders = True;
1339 lp->foundBirth = lp->foundSurvival = !MI_IS_FULLRANDOM(mi);
1340 if (MI_IS_VERBOSE(mi))
1341 (void) fprintf(stdout,
1342 "rule: Defaulting to all rules with known gliders\n");
1343 return;
1344 }
1345 }
1346
1347 #ifndef STANDALONE
1348 static void
parseFile(ModeInfo * mi)1349 parseFile(ModeInfo *mi)
1350 {
1351 FILE *file;
1352 static Bool done = False;
1353 int firstx, x = 0, y = 0, i = 0;
1354 int l;
1355 int found = 0;
1356 int c, size;
1357 char line[256];
1358 #define LIVE_CHARS 8
1359 char liveChar[LIVE_CHARS] = {'*', '0', 'O', 'o', 'A', 'V', 'J', 'D'};
1360
1361 if (done)
1362 return;
1363 done = True;
1364 if (MI_IS_FULLRANDOM(mi) || !lifefile || !*lifefile)
1365 return;
1366 if ((file = my_fopenSize(lifefile, "r", &size)) == NULL) {
1367 (void) fprintf(stderr, "could not read file \"%s\"\n", lifefile);
1368 return;
1369 }
1370 for (;;) {
1371 if (!fgets(line, 256, file)) {
1372 (void) fprintf(stderr, "could not read header of file \"%s\"\n",
1373 lifefile);
1374 (void) fclose(file);
1375 return;
1376 }
1377 if (strncmp(line, "#P", (size_t) 2) == 0 &&
1378 sscanf(line, "#P %d %d", &x, &y) == 2)
1379 break;
1380 }
1381 c = getc(file);
1382 while (c != EOF && !(c == '.')) {
1383 found = 0;
1384 for (l = 0; l < LIVE_CHARS; l++) {
1385 if (c == liveChar[l]) {
1386 found = 1;
1387 break;
1388 }
1389 }
1390 if (found)
1391 break;
1392 c = getc(file);
1393 }
1394 if (c == EOF || x <= -127 || y <= -127 || x >= 127 || y >= 127) {
1395 (void) fprintf(stderr, "corrupt file \"%s\" or file to large\n",
1396 lifefile);
1397 (void) fclose(file);
1398 return;
1399 }
1400 firstx = x;
1401 if ((filePattern = (char *) malloc((2 * size) *
1402 sizeof (char))) == NULL) {
1403 (void) fprintf(stderr, "not enough memory\n");
1404 (void) fclose(file);
1405 return;
1406 }
1407
1408 while (c != EOF && x < 127 && y < 127 && i < 2 * size) {
1409 found = 0;
1410 for (l = 0; l < LIVE_CHARS; l++) {
1411 if (c == liveChar[l]) {
1412 filePattern[i++] = x++;
1413 filePattern[i++] = y;
1414 found = 1;
1415 break;
1416 }
1417 }
1418 if (!found) {
1419 if (c == '.') {
1420 x++;
1421 } else if (c == '\n') {
1422 x = firstx;
1423 y++;
1424 }
1425 }
1426 c = getc(file);
1427 }
1428 (void) fclose(file);
1429 filePattern[i] = 127;
1430 }
1431 #endif
1432
1433 static Bool
initList(lifestruct * lp,int state)1434 initList(lifestruct * lp, int state)
1435 {
1436 /* Waste some space at the beginning and end of list
1437 so we do not have to complicated checks against falling off the ends. */
1438 if ((lp->last[state] = (CellList *) malloc(sizeof (CellList))) == NULL) {
1439 return False;
1440 }
1441 if ((lp->first[state] = (CellList *) malloc(sizeof (CellList))) == NULL) {
1442 free(lp->last[state]);
1443 lp->last[state] = (CellList *) NULL;
1444 return False;
1445 }
1446 lp->first[state]->previous = lp->last[state]->next =
1447 (struct _CellList *) NULL;
1448 lp->first[state]->next = lp->last[state]->previous =
1449 (struct _CellList *) NULL;
1450 lp->first[state]->next = lp->last[state];
1451 lp->last[state]->previous = lp->first[state];
1452 return True;
1453 }
1454
1455 static Bool
addToList(lifestruct * lp,int state,cellstruct info)1456 addToList(lifestruct * lp, int state, cellstruct info)
1457 {
1458 CellList *curr;
1459
1460 if ((curr = (CellList *) malloc(sizeof (CellList))) == NULL)
1461 return False;
1462 lp->last[state]->previous->next = curr;
1463 curr->previous = lp->last[state]->previous;
1464 curr->next = lp->last[state];
1465 lp->last[state]->previous = curr;
1466 curr->info = info;
1467 if (info.position >= 0) {
1468 lp->arr[info.position] = curr;
1469 lp->ncells[state]++;
1470 }
1471 return True;
1472 }
1473
1474 static void
removeFromList(lifestruct * lp,int state,CellList * curr)1475 removeFromList(lifestruct * lp, int state, CellList * curr)
1476 {
1477 curr->previous->next = curr->next;
1478 curr->next->previous = curr->previous;
1479 if (curr->info.position >= 0) {
1480 lp->arr[curr->info.position] = (CellList *) NULL;
1481 lp->ncells[state]--;
1482 }
1483 free(curr);
1484 }
1485
1486 #ifdef DEBUG
1487 static void
printState(ModeInfo * mi,int state)1488 printState(ModeInfo * mi, int state)
1489 {
1490 lifestruct *lp = &lifes[MI_SCREEN(mi)];
1491 CellList *curr;
1492 int i = 0;
1493
1494 curr = lp->first[state]->next;
1495 (void) printf("state %d\n", state);
1496 while (curr != lp->last[state]) {
1497 (void) printf("%d: position %ld, age %d, state %d, toggle %d\n",
1498 i, curr->info.position, curr->info.age,
1499 curr->info.state, curr->info.toggle);
1500 curr = curr->next;
1501 i++;
1502 }
1503 }
1504
1505 #endif
1506
1507 static void
printList(lifestruct * lp,int i)1508 printList(lifestruct * lp, int i)
1509 {
1510 /* did not make this hack multiscreen ready */
1511 static int tcol[2], trow[2], tcol2[2], trow2[2], tcount[2];
1512
1513 tcol[i] = 0;
1514 trow[i] = 0;
1515 tcol2[i] = 0;
1516 trow2[i] = 0;
1517 tcount[i] = lp->ncells[LIVE];
1518 if ((glidersearch || patternsearch) && tcount[0] < 72) {
1519 CellList *curr = lp->last[LIVE]->previous;
1520
1521 while (curr != lp->first[LIVE]) {
1522 int col, row;
1523
1524 if (lp->polygon == 4) {
1525
1526 col = (curr->info.position % lp->ncols) - (lp->ncols / 2);
1527 row = (curr->info.position / lp->ncols) - (lp->nrows / 2);
1528 } else if (lp->polygon == 6) {
1529 col = (curr->info.position % lp->ncols) - 2 * (lp->ncols / 4);
1530 row = (curr->info.position / lp->ncols) - 2 * (lp->nrows / 4) - 1;
1531 if (row < 0)
1532 col += ((lp->nrows / 2) & 1) ? row / 2 :
1533 (row - 1) / 2;
1534 else
1535 col += ((lp->nrows / 2) & 1) ? (row + 1) / 2 :
1536 row / 2;
1537 } else {
1538 col = (curr->info.position % lp->ncols) - 2 * (lp->ncols / 4) - 1;
1539 row = (curr->info.position / lp->ncols) - 2 * (lp->nrows / 4);
1540 }
1541 (void) printf("%d, %d,\n", col, row);
1542 /* fudging a signature */
1543 tcol[i] += col;
1544 trow[i] += row;
1545 tcol2[i] += col * col;
1546 trow2[i] += row * row;
1547 curr = curr->previous;
1548 }
1549 (void) printf("%d#%d, pos_sum %d %d %d %d\n",
1550 i, tcount[i], tcol[i], trow[i], tcol2[i], trow2[i]);
1551 if (i == 1 && (tcount[0] <= NUMPTS || tcount[1] <= NUMPTS) &&
1552 (tcount[0] != tcount[1] ||
1553 tcol[0] != tcol[1] || trow[0] != trow[1] ||
1554 tcol2[0] != tcol2[1] || trow2[0] != trow2[1]))
1555 (void) printf("found\n");
1556 }
1557 }
1558
1559 static void
flushList(lifestruct * lp,int state)1560 flushList(lifestruct * lp, int state)
1561 {
1562 while (lp->last[state]->previous != lp->first[state]) {
1563 CellList *curr = lp->last[state]->previous;
1564
1565 curr->previous->next = lp->last[state];
1566 lp->last[state]->previous = curr->previous;
1567 free(curr);
1568 }
1569 lp->ncells[state] = 0;
1570 }
1571
1572 /*static void
1573 drawPolygon(Display *display, Window window, XPoint points, int size) {
1574 int i = 0;
1575
1576 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
1577 for (i = 0; i < size - 1; i++) {
1578 XDrawLine(points[i].x, points[i].y,
1579 points[i + 1].x, points[i + 1].y);
1580 XDrawLine(points[size - 1].x, points[size - 1].y,
1581 points[0].x, points[0].y);
1582 }*/
1583
1584 static void
drawCell(ModeInfo * mi,cellstruct info)1585 drawCell(ModeInfo * mi, cellstruct info)
1586 {
1587 Display *display = MI_DISPLAY(mi);
1588 lifestruct *lp = &lifes[MI_SCREEN(mi)];
1589 GC gc = lp->backGC;
1590 int col, row;
1591
1592 if (!draw)
1593 return;
1594 col = (int) (info.position % lp->ncols);
1595 row = (int) (info.position / lp->ncols);
1596 if (info.state == LIVE) {
1597 if (MI_NPIXELS(mi) > 2)
1598 XSetForeground(display, gc, MI_PIXEL(mi, info.age));
1599 else
1600 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
1601 } else
1602 XSetForeground(display, gc, lp->black);
1603
1604 if (lp->polygon == 3) {
1605 int orient = (col + row) & 1; /* O left 1 right */
1606 #ifdef WIN32
1607 int offset = 2;
1608 #else
1609 int offset = 1;
1610 #endif
1611
1612 if (lp->vertical) {
1613 lp->shape.triangle[orient][0].x = lp->xb + col * lp->xs;
1614 lp->shape.triangle[orient][0].y = lp->yb + row * lp->ys;
1615 } else {
1616 lp->shape.triangle[orient][0].y = lp->xb + col * lp->xs;
1617 lp->shape.triangle[orient][0].x = lp->yb + row * lp->ys;
1618 }
1619 if (lp->xs <= 3 || lp->ys <= 3)
1620 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), lp->backGC,
1621 ((orient) ? -1 : 1) + lp->shape.triangle[orient][0].x,
1622 lp->shape.triangle[orient][0].y);
1623 else {
1624 if (lp->vertical) {
1625 if (orient)
1626 lp->shape.triangle[orient][0].x += (lp->xs / 2 - offset);
1627 else
1628 lp->shape.triangle[orient][0].x -= (lp->xs / 2 - offset);
1629
1630 } else {
1631 if (orient)
1632 lp->shape.triangle[orient][0].y += (lp->xs / 2 - offset);
1633 else
1634 lp->shape.triangle[orient][0].y -= (lp->xs / 2 - offset);
1635 }
1636 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), lp->backGC,
1637 lp->shape.triangle[orient], 3, Convex, CoordModePrevious);
1638 /*drawPolygon(MI_DISPLAY(mi), MI_WINDOW(mi),
1639 lp->shape.triangle[orient], 3);*/
1640 }
1641 } else if (lp->polygon == 4) {
1642 if (lp->pixelmode || info.state == DEAD)
1643 XFillRectangle(display, MI_WINDOW(mi), gc,
1644 lp->xb + lp->xs * col, lp->yb + lp->ys * row,
1645 lp->xs - (lp->xs > 3 && lp->pixelmode),
1646 lp->ys - (lp->ys > 3 && lp->pixelmode));
1647 else {
1648 /*-
1649 * PURIFY 4.0.1 on SunOS4 and on Solaris 2 reports a 132 byte memory leak on
1650 * the next line */
1651 #ifdef XBM_GRELB
1652 if (lp->logo2) {
1653 (void) XPutImage(display, MI_WINDOW(mi), gc,
1654 (LRAND() & 1) ? lp->logo : lp->logo2,
1655 0, 0, lp->xb + lp->xs * col, lp->yb + lp->ys * row,
1656 lp->logo->width, lp->logo->height);
1657 } else
1658 #endif
1659 {
1660 (void) XPutImage(display, MI_WINDOW(mi), gc, lp->logo,
1661 0, 0, lp->xb + lp->xs * col, lp->yb + lp->ys * row,
1662 lp->logo->width, lp->logo->height);
1663 }
1664 }
1665 } else if (lp->polygon == 5) {
1666 int map[4] = {2, 0, 1, 3};
1667 int orient = ((row & 1) * 2 + col) % 4;
1668 int offsetX = 0, offsetY = 0;
1669 switch (orient) {
1670 case 0: /* up */
1671 offsetX = lp->xs;
1672 break;
1673 case 1: /* down */
1674 offsetY = 3 * lp->ys / 2 - 1;
1675 break;
1676 case 2: /* left */
1677 offsetX = -lp->xs / 2;
1678 offsetY = 3 * lp->ys / 4;
1679 break;
1680 case 3: /* right */
1681 offsetX = 3 * lp->xs / 2 - 1;
1682 offsetY = 3 * lp->ys / 4;
1683 break;
1684 default:
1685 (void) printf("wrong orient %d\n", orient);
1686 }
1687 orient = map[orient];
1688 lp->shape.pentagon[orient][0].x = lp->xb +
1689 col * lp->xs + offsetX;
1690 lp->shape.pentagon[orient][0].y = lp->yb +
1691 row * lp->ys + offsetY;
1692 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), lp->backGC,
1693 lp->shape.pentagon[orient], 5, Convex, CoordModePrevious);
1694 /*drawPolygon(MI_DISPLAY(mi), MI_WINDOW(mi),
1695 lp->shape.pentagon[orient], 5);*/
1696 } else if (lp->polygon == 6) {
1697 int ccol = 2 * col + !(row & 1), crow = 2 * row;
1698
1699 if (lp->vertical) {
1700 lp->shape.hexagon[0].x = lp->xb + ccol * lp->xs;
1701 lp->shape.hexagon[0].y = lp->yb + crow * lp->ys;
1702 } else {
1703 lp->shape.hexagon[0].y = lp->xb + ccol * lp->xs;
1704 lp->shape.hexagon[0].x = lp->yb + crow * lp->ys;
1705 }
1706 if (lp->xs == 1 && lp->ys == 1)
1707 XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), lp->backGC,
1708 lp->shape.hexagon[0].x, lp->shape.hexagon[0].y);
1709 else {
1710 XFillPolygon(MI_DISPLAY(mi), MI_WINDOW(mi), lp->backGC,
1711 lp->shape.hexagon, 6, Convex, CoordModePrevious);
1712 /*drawPolygon(MI_DISPLAY(mi), MI_WINDOW(mi),
1713 lp->shape.hexagon, 6);*/
1714 }
1715 }
1716 }
1717
1718 static void
setcelltoggles(ModeInfo * mi,int col,int row)1719 setcelltoggles(ModeInfo * mi, int col, int row)
1720 {
1721 lifestruct *lp = &lifes[MI_SCREEN(mi)];
1722 int position;
1723 CellList *curr;
1724
1725 position = row * lp->ncols + col;
1726 curr = lp->arr[position];
1727 if (!curr) {
1728 (void) fprintf(stderr, "state toggling but not on list\n");
1729 return;
1730 }
1731 curr->info.toggle = True;
1732 }
1733
1734 static void
free_cells(lifestruct * lp)1735 free_cells(lifestruct * lp)
1736 {
1737 if (lp->arr != NULL) {
1738 free(lp->arr);
1739 lp->arr = (CellList **) NULL;
1740 }
1741 }
1742
1743 static void
free_stuff(Display * display,lifestruct * lp)1744 free_stuff(Display * display, lifestruct * lp)
1745 {
1746 if (lp->cmap != None) {
1747 XFreeColormap(display, lp->cmap);
1748 if (lp->backGC != None) {
1749 XFreeGC(display, lp->backGC);
1750 lp->backGC = None;
1751 }
1752 lp->cmap = None;
1753 } else
1754 lp->backGC = None;
1755 }
1756
1757 static void
free_life_screen(Display * display,lifestruct * lp)1758 free_life_screen(Display * display, lifestruct * lp)
1759 {
1760 int state;
1761
1762 if (lp == NULL) {
1763 return;
1764 }
1765 for (state = 0; state < STATES; state++) {
1766 if (lp->first[state])
1767 flushList(lp, state);
1768 if (lp->last[state])
1769 free(lp->last[state]);
1770 lp->last[state] = (CellList *) NULL;
1771 if (lp->first[state])
1772 free(lp->first[state]);
1773 lp->first[state] = (CellList *) NULL;
1774 }
1775 free_cells(lp);
1776 free_stuff(display, lp);
1777 #ifndef STANDALONE
1778 /* this used to work there I think */
1779
1780 if (lp->logo != None) {
1781 destroyImage(&lp->logo, &lp->graphics_format);
1782 lp->logo = None;
1783 }
1784 #endif
1785 lp = NULL;
1786 }
1787
1788 ENTRYPOINT void
free_life(ModeInfo * mi)1789 free_life(ModeInfo * mi)
1790 {
1791 free_life_screen(MI_DISPLAY(mi), &lifes[MI_SCREEN(mi)]);
1792 }
1793
1794 static Bool
setcellfromtoggle(ModeInfo * mi,int col,int row)1795 setcellfromtoggle(ModeInfo * mi, int col, int row)
1796 {
1797 lifestruct *lp = &lifes[MI_SCREEN(mi)];
1798 int neighbor, n, position;
1799 cellstruct info;
1800 CellList *curr, *currn;
1801
1802 position = row * lp->ncols + col;
1803 curr = lp->arr[position];
1804 if (!curr)
1805 return True;
1806 if ((curr->info.state == DEAD && curr->info.toggle) ||
1807 (curr->info.state == LIVE && !curr->info.toggle)) {
1808 for (n = 0; n < lp->neighbors; n++) {
1809 neighbor = positionOfNeighbor(lp, n, col, row);
1810 currn = lp->arr[neighbor];
1811 if (!currn) {
1812 info.position = neighbor;
1813 info.age = 0;
1814 info.state = DEAD;
1815 info.toggle = False;
1816 if (!addToList(lp, DEAD, info)) {
1817 free_life_screen(MI_DISPLAY(mi), lp);
1818 return False;
1819 }
1820 }
1821 }
1822 }
1823 if (curr->info.state == DEAD && curr->info.toggle) {
1824 removeFromList(lp, DEAD, curr);
1825 if (!patternsearch || /* throws away stuff over border */
1826 (position % lp->ncols != 0 &&
1827 position / lp->ncols != 0)) {
1828 info.age = 0;
1829 info.position = position;
1830 info.toggle = False;
1831 info.state = LIVE;
1832 if (!addToList(lp, LIVE, info)) {
1833 free_life_screen(MI_DISPLAY(mi), lp);
1834 return False;
1835 }
1836 drawCell(mi, info);
1837 }
1838 } else if (curr->info.state == LIVE && !curr->info.toggle) {
1839 info = curr->info;
1840 /* if we aren't up to blue yet, then keep aging the cell. */
1841 if ((MI_NPIXELS(mi) > 2) &&
1842 (info.age < (unsigned short) (MI_NPIXELS(mi) * 0.7))) {
1843 ++(info.age);
1844 /* cc: error 1405: "/opt/ansic/lbin/ccom"
1845 terminated abnormally with signal 11.
1846 *** Error exit code 9 */
1847 /* Next 2 line trips up HP cc -g -O, remove a flag */
1848 curr->info.age = info.age;
1849 drawCell(mi, info);
1850 }
1851 else if (glidersearch) {
1852 /* Aging out of static blocks, not good in general, use wisely. */
1853 if (info.age < 64) {
1854 ++(info.age);
1855 curr->info.age = info.age;
1856 } else
1857 curr->info.state = DEAD;
1858 }
1859 }
1860 return True;
1861 }
1862
1863 static Bool
setcell(ModeInfo * mi,int col,int row,int state)1864 setcell(ModeInfo * mi, int col, int row, int state)
1865 {
1866 lifestruct *lp = &lifes[MI_SCREEN(mi)];
1867 int neighbor, n, position;
1868 cellstruct info;
1869 CellList *curr, *currn;
1870
1871 if (col < 0 || row < 0 || col >= lp->ncols || row >= lp->nrows) {
1872 #ifdef DEBUG
1873 (void) printf("col %d, row %d outside grid\n", col, row);
1874 #endif
1875 return True; /* Actually its a 3rd case */
1876 }
1877
1878 position = row * lp->ncols + col;
1879 curr = lp->arr[position];
1880 /* cc: error 1405: "/opt/ansic/lbin/ccom"
1881 terminated abnormally with signal 11.
1882 *** Error exit code 9 */
1883 /* Following lines trip up HP cc -g -O, remove a flag */
1884 if (state == LIVE) {
1885 if (curr && curr->info.state == DEAD) {
1886 removeFromList(lp, DEAD, curr);
1887 curr = (CellList *) NULL;
1888 }
1889 if (!curr) {
1890 for (n = 0; n < lp->neighbors; n++) {
1891 neighbor = positionOfNeighbor(lp, n, col, row);
1892 currn = lp->arr[neighbor];
1893 if (!currn) {
1894 info.age = 0;
1895 info.position = neighbor;
1896 info.state = DEAD;
1897 info.toggle = False;
1898 if (!addToList(lp, DEAD, info)) {
1899 free_life_screen(MI_DISPLAY(mi), lp);
1900 return False;
1901 }
1902 }
1903 }
1904 info.age = 0;
1905 info.position = position;
1906 info.state = LIVE;
1907 info.toggle = False;
1908 if (!addToList(lp, LIVE, info)) {
1909 free_life_screen(MI_DISPLAY(mi), lp);
1910 return False;
1911 }
1912 drawCell(mi, info);
1913 } else {
1914 info = curr->info;
1915 info.age = 0;
1916 drawCell(mi, info);
1917 }
1918 } else if (curr && curr->info.state == LIVE) {
1919 info.age = 0;
1920 info.position = position;
1921 info.state = DEAD;
1922 info.toggle = False;
1923 removeFromList(lp, LIVE, curr); /* Just in case... */
1924 if (!addToList(lp, DEAD, info)) {
1925 free_life_screen(MI_DISPLAY(mi), lp);
1926 return False;
1927 }
1928 drawCell(mi, info);
1929 }
1930 return True;
1931 }
1932
1933 #if 0
1934 static int
n_neighbors(lifestruct * lp,CellList * curr)1935 n_neighbors(lifestruct * lp, CellList * curr)
1936 {
1937 int col, row, n, p, count = 0;
1938
1939 col = curr->info.position % lp->ncols;
1940 row = curr->info.position / lp->ncols;
1941 for (n = 0; n < lp->neighbors; n++) {
1942 p = positionOfNeighbor(lp, n, col, row);
1943 if (lp->arr[p] && lp->arr[p]->info.state == LIVE) {
1944 count++;
1945 }
1946 }
1947 return count;
1948 }
1949 #endif
1950
1951 /* make work with negative x */
1952 #define MOD(x,y) ((x)<0)?((y)-((-x)%(y)))%(y):(x)%(y)
1953 #define DIV(x,y) ((x)<0)?((x)+1)/(y)-1:(x)/(y)
1954 #define CEIL(z) ((z)+(((z)>=0)?1:0))/2
1955
1956 static int
ng_neighbors(lifestruct * lp,CellList * curr,int * group)1957 ng_neighbors(lifestruct * lp, CellList * curr, int *group)
1958 {
1959 int col, row, n, p, count = 0, gcount = 0;
1960
1961 col = (int) (curr->info.position % lp->ncols);
1962 row = (int) (curr->info.position / lp->ncols);
1963 for (n = 0; n < lp->neighbors; n++) {
1964 p = positionOfNeighbor(lp, n, col, row);
1965 gcount <<= 1;
1966 if (lp->arr[p] && lp->arr[p]->info.state == LIVE) {
1967 count++;
1968 gcount++;
1969 }
1970 }
1971 *group = gcount;
1972 return count;
1973 }
1974
1975 static void
RandomSoup(ModeInfo * mi,int symmetryIndex,int percent,int fieldX,int fieldY)1976 RandomSoup(ModeInfo * mi, int symmetryIndex, int percent, int fieldX, int fieldY)
1977 {
1978 lifestruct *lp = &lifes[MI_SCREEN(mi)];
1979 int col, row;
1980 int halfcols = lp->ncols / 2;
1981 int halfrows = lp->nrows / 2;
1982 int vx = fieldX / 2 + 1;
1983 int vy = fieldY / 2 + 1;
1984 int even = NRAND(2);
1985 int yEven = NRAND(2);
1986
1987 if (lp->polygon == 3) {
1988 /* Triangles are stored left/right not up/down */
1989 halfcols = lp->nrows / 2;
1990 halfrows = lp->ncols / 2;
1991 vx = fieldY / 2;
1992 vy = fieldX / 2;
1993 }
1994 if (vx < 1)
1995 vx = 1;
1996 if (vy < 1)
1997 vy = 1;
1998 switch (symmetryIndex) {
1999 case 0: /* Full Random */
2000 for (row = halfrows - vy; row < halfrows + vy; ++row) {
2001 for (col = halfcols - vx; col < halfcols + vx; ++col) {
2002 if (NRAND(100) < percent) {
2003 SetList(col, row);
2004 }
2005 }
2006 }
2007 (void) strcpy(lp->nameString, "Full Random");
2008 break;
2009 case 1: /* Sym X Random */
2010 for (row = halfrows - vy; row < halfrows + vy; ++row) {
2011 for (col = halfcols; col < halfcols + vx; ++col) {
2012 if (NRAND(100) < percent) {
2013 if (lp->polygon != 5) {
2014 SetList(col, row);
2015 }
2016 if (lp->polygon == 3) {
2017 SetList(2 * halfcols - col, row);
2018 } else if (lp->polygon == 4) {
2019 SetList(2 * halfcols - col - even, row);
2020 } else if (lp->polygon == 5) {
2021 int tcol = 2 * halfcols - col;
2022 int mod = (col + 2 * row) % 4;
2023
2024 if (mod == 2 && col == halfcols)
2025 continue;
2026 SetList(col, row);
2027 if (mod == 1)
2028 tcol += 2;
2029 else if (mod == 2 || mod == 3)
2030 tcol++;
2031 SetList(tcol, row);
2032 } else if (lp->polygon == 6) {
2033 SetList(2 * halfcols - col - (((row & 1) == 1) ? 0 : 1), row);
2034 }
2035 }
2036 }
2037 }
2038 (void) strcpy(lp->nameString, "Sym X Random");
2039 break;
2040 case 2: /* Sym Y Random */
2041 for (row = halfrows; row < halfrows + vy; ++row) {
2042 for (col = halfcols - vx; col < halfcols + vx; ++col) {
2043 if (NRAND(100) < percent) {
2044 if (lp->polygon != 5) {
2045 SetList(col, row);
2046 }
2047 if (lp->polygon == 3) {
2048 SetList(col, 2 * halfrows - row - 1);
2049 } else if (lp->polygon == 4) {
2050 SetList(col, 2 * halfrows - row - even);
2051 } else if (lp->polygon == 5) {
2052 int mod = (col + 2 * row) % 4;
2053 int tcol = col;
2054 int trow = 2 * halfrows - row;
2055
2056 if (mod == 1 && row == halfrows)
2057 continue;
2058 SetList(col, row);
2059 if (mod == 0)
2060 tcol++;
2061 else if (mod == 1)
2062 tcol--;
2063 SetList(tcol, trow);
2064 } else if (lp->polygon == 6) {
2065 SetList(col, 2 * halfrows - row);
2066 }
2067 }
2068 }
2069 }
2070 (void) strcpy(lp->nameString, "Sym Y Random");
2071 break;
2072 case 3: /* Sym XY Random */
2073 for (row = halfrows; row < halfrows + vy; ++row) {
2074 for (col = halfcols; col < halfcols + vx; ++col) {
2075 if (NRAND(100) < percent) {
2076 if (lp->polygon != 5) {
2077 SetList(col, row);
2078 }
2079 if (lp->polygon == 3) {
2080 SetList(col, 2 * halfrows - row - 1);
2081 SetList(2 * halfcols - col, row);
2082 SetList(2 * halfcols - col, 2 * halfrows - row - 1);
2083 } else if (lp->polygon == 4) {
2084 SetList(col, 2 * halfrows - row - yEven);
2085 SetList(2 * halfcols - col - even, row);
2086 SetList(2 * halfcols - col - even, 2 * halfrows - row - yEven);
2087 } else if (lp->polygon == 5) {
2088 int tcol = 2 * halfcols - col;
2089 int trow = 2 * halfrows - row;
2090 int mod = (col + 2 * row) % 4;
2091
2092 if ((mod == 2 && col == halfcols) ||
2093 (mod == 1 && row == halfrows))
2094 continue;
2095 SetList(col, row);
2096 if (mod == 1)
2097 tcol += 2;
2098 else if (mod == 2 || mod == 3)
2099 tcol++;
2100 SetList(tcol, row);
2101 tcol = col;
2102 if (mod == 0)
2103 tcol++;
2104 else if (mod == 1)
2105 tcol--;
2106 SetList(tcol, trow);
2107 tcol = 2 * halfcols - col + 1;
2108 SetList(tcol, trow);
2109 } else if (lp->polygon == 6) {
2110 SetList(col, 2 * halfrows - row);
2111 SetList(2 * halfcols - col - (((row & 1) == 1) ? 0 : 1), row);
2112 SetList(2 * halfcols - col - (((row & 1) == 1) ? 0 : 1), 2 * halfrows - row);
2113 }
2114 }
2115 }
2116 }
2117 (void) strcpy(lp->nameString, "Sym XY Random");
2118 break;
2119 case 4: /* Antisym X Random */
2120 for (row = halfrows - vy; row < halfrows + vy; ++row) {
2121 for (col = halfcols; col < halfcols + vx; ++col) {
2122 if (NRAND(100) < percent) {
2123 if (lp->polygon != 5) {
2124 SetList(col, row);
2125 }
2126 if (lp->polygon == 3) {
2127 SetList(2 * halfcols - col, 2 * halfrows - row - 1);
2128 } else if (lp->polygon == 4) {
2129 SetList(2 * halfcols - col, 2 * halfrows - row - even);
2130 } else if (lp->polygon == 5) {
2131 int tcol = 2 * halfcols - col - even;
2132 int trow = 2 * halfrows - row - even;
2133 int mod = (col + 2 * row) % 4;
2134
2135 if (even == 0 && mod == 2 && col == halfcols)
2136 continue;
2137 SetList(col, row);
2138 if (even == 1) {
2139 SetList(tcol, trow);
2140 } else {
2141 SetList(tcol + 1, trow);
2142 }
2143 } else if (lp->polygon == 6) {
2144 SetList(2 * halfcols - col, 2 * halfrows - row - 1);
2145 }
2146 }
2147 }
2148 }
2149 (void) strcpy(lp->nameString, "Antisym X Random");
2150 break;
2151 case 5: /* Antisym Y Random */
2152 for (row = halfrows; row < halfrows + vy; ++row) {
2153 for (col = halfcols - vx; col < halfcols + vx; ++col) {
2154 if (NRAND(100) < percent) {
2155 if (lp->polygon != 5) {
2156 SetList(col, row);
2157 }
2158 if (lp->polygon == 3) {
2159 SetList(2 * halfcols - col - 1, 2 * halfrows - row);
2160 } else if (lp->polygon == 4) {
2161 SetList(2 * halfcols - col - 1, 2 * halfrows - row - even);
2162 } else if (lp->polygon == 5) {
2163 int tcol = 2 * halfcols - col - even;
2164 int trow = 2 * halfrows - row - even;
2165 int mod = (col + 2 * row) % 4;
2166
2167 if (even == 0 && mod == 0 && row == halfrows)
2168 continue;
2169 SetList(col, row);
2170 if (even == 1) {
2171 SetList(tcol, trow);
2172 } else {
2173 SetList(tcol + 1, trow);
2174 }
2175 } else if (lp->polygon == 6) {
2176 SetList(2 * halfcols - col - 1, 2 * halfrows - row - 1);
2177 }
2178 }
2179 }
2180 }
2181 (void) strcpy(lp->nameString, "Antisym Y Random");
2182 break;
2183 case 6: /* Half Antisym Random */
2184 /* Diagonal, Triangular (on face, on corner) */
2185 if (lp->polygon == 3) {
2186 int odd = (halfcols + halfrows) % 2;
2187
2188 if (even == 1) {
2189 vx = vy = (vx + vy) / 3;
2190 for (row = 0; row < vy; ++row) {
2191 for (col = 0; col < 2 * row + 1; ++col) {
2192 if (NRAND(100) < percent) {
2193 SetList(halfcols + col - row, halfrows - row - 1 + odd);
2194 SetList(halfcols - (col + 1) / 2 + 2 * row + 1, halfrows + col / 2 + odd);
2195 SetList(halfcols - col / 2 - row - 1, halfrows + row - (col + 1) / 2 + odd);
2196 }
2197 if (NRAND(100) < percent) {
2198 SetList(halfcols - col + row, halfrows + row + odd);
2199 SetList(halfcols + (col + 1) / 2 - 2 * row - 1, halfrows - col / 2 - 1 + odd);
2200 SetList(halfcols + col / 2 + row + 1, halfrows - row + (col + 1) / 2 - 1 + odd);
2201 }
2202 }
2203 }
2204 } else {
2205 vx = vy = (vx + vy) / 4;
2206 for (row = 0; row < vy; ++row) {
2207 for (col = 0; col < 6 * row + 5; ++col) {
2208 if (NRAND(100) < percent) {
2209 SetList(halfcols + col / 2, halfrows + (col + 1) / 2 - 2 * row - 2 + odd);
2210 SetList(halfcols + (col + 1) / 2 - 3 * row - 3, halfrows + row + 2 - col / 2 - 1 + odd);
2211 SetList(halfcols - col + 3 * row + 3, halfrows + row + 1 + odd);
2212 }
2213 }
2214 }
2215 if (NRAND(100) < percent) {
2216 /* center triangle */
2217 SetList(halfcols, halfrows + odd);
2218 }
2219 }
2220 } else if (lp->polygon == 4) {
2221 vx = vy = (vx + vy) / 2;
2222 for (row = -vy; row < vy; ++row) {
2223 for (col = row; col < vx; ++col) {
2224 if (NRAND(100) < percent) {
2225 if (even == 1) {
2226 SetList(col + halfcols, row + halfrows);
2227 SetList(row + halfcols, col + halfrows);
2228 } else {
2229 SetList(-col + halfcols, row + halfrows);
2230 SetList(-row + halfcols, col + halfrows);
2231 }
2232 }
2233 }
2234 }
2235 } else if (lp->polygon == 5) {
2236 for (row = halfrows; row < halfrows + vy; ++row) {
2237 for (col = halfcols; col < halfcols + 2 * vy; ++col) {
2238 if (NRAND(100) < percent) {
2239 int tcol = 2 * halfcols - col - 1;
2240 int trow = 2 * halfrows - row - 1;
2241 int mod = (col + 2 * row) % 4;
2242
2243 SetList(col, row);
2244 SetList(tcol, trow);
2245 tcol = (row - halfrows) * 2 + halfcols;
2246 trow = (col - halfcols) / 2 + halfrows;
2247 if (mod == 1 || mod == 2)
2248 tcol++;
2249 SetList(2 * halfcols - tcol - 1, trow);
2250 SetList(tcol, 2 * halfrows - trow - 1);
2251 }
2252 }
2253 }
2254 } else if (lp->polygon == 6) {
2255 if (even == 1) {
2256 vx = vy = 2 * (vx + vy) / 3;
2257 for (row = 0; row < vy; ++row) {
2258 for (col = 0; col < row; ++col) {
2259 if (NRAND(100) < percent) {
2260 SetList(halfcols - col + (row + (halfrows + 1) % 2) / 2, halfrows + row);
2261 SetList(halfcols + (col + row + halfrows % 2) / 2 - halfrows % 2, halfrows - row + col + 1);
2262 SetList(halfcols - row + (col + halfrows % 2) / 2 + (halfrows + 1) % 2, halfrows - col + 1);
2263 }
2264 }
2265 }
2266 for (row = 0; row < vy; ++row) {
2267 for (col = 0; col < row - 1; ++col) {
2268 if (NRAND(100) < percent) {
2269 SetList(halfcols + row - (col + (halfrows + 1) % 2) / 2 - halfrows % 2, halfrows + col + 1);
2270 SetList(halfcols + col - (row + (halfrows + 1) % 2) / 2 + (halfrows + 1) % 2, halfrows - row + 1);
2271 SetList(halfcols - (col + row + halfrows % 2) / 2, halfrows + row - col);
2272 }
2273 }
2274 }
2275 } else {
2276 vx = vy = 2 * (vx + vy) / 3;
2277 for (row = 0; row < vy; ++row) {
2278 for (col = 0; col < row; ++col) {
2279 if (NRAND(100) < percent) {
2280 SetList(halfcols - col + (row + (halfrows + 1) % 2) / 2, halfrows + row);
2281 SetList(halfcols + (col + row + (halfrows + 1) % 2) / 2, halfrows - row + col);
2282 SetList(halfcols - row + (col + (halfrows + 1) % 2) / 2, halfrows - col);
2283 }
2284 if (NRAND(100) < percent) {
2285 SetList(halfcols + row - (col + halfrows % 2) / 2, halfrows + col);
2286 SetList(halfcols + col - (row + halfrows % 2) / 2, halfrows - row);
2287 SetList(halfcols - (col + row + halfrows % 2) / 2, halfrows + row - col);
2288 }
2289 }
2290 }
2291 if (NRAND(100) < percent) {
2292 SetList(halfcols, halfrows);
2293 }
2294 }
2295 }
2296 (void) strcpy(lp->nameString, "Half Antisym Random");
2297 break;
2298 case 7: /* Half Sym Random */
2299 /* Diagonal, Triangular (on face, on corner) */
2300 if (lp->polygon == 3) {
2301 int odd = (halfcols + halfrows) % 2;
2302
2303 if (even == 1) {
2304 vx = vy = (vx + vy) / 3;
2305 for (row = 0; row < vy; ++row) {
2306 for (col = 0; col < 2 * row + 1; ++col) {
2307 if (NRAND(100) < percent) {
2308 SetList(halfcols + col - row, halfrows - row - 1 + odd);
2309 SetList(halfcols - (col + 1) / 2 + 2 * row + 1, halfrows - col / 2 - 1 + odd);
2310 SetList(halfcols - col / 2 - row - 1, halfrows + row - (col + 1) / 2 + odd);
2311 SetList(halfcols + col - row, halfrows + row + odd);
2312 SetList(halfcols - (col + 1) / 2 + 2 * row + 1, halfrows + col / 2 + odd);
2313 SetList(halfcols - col / 2 - row - 1, halfrows - row + (col + 1) / 2 - 1 + odd);
2314 }
2315 }
2316 }
2317 } else {
2318 vx = vy = (vx + vy) / 4;
2319 for (row = 0; row < vy; ++row) {
2320 for (col = 0; col < 3 * row + 4; ++col) {
2321 if (NRAND(100) < percent) {
2322 SetList(halfcols + col / 2, halfrows + (col + 1) / 2 - 2 * row - 2 + odd);
2323 SetList(halfcols - col / 2, halfrows + (col + 1) / 2 - 2 * row - 2 + odd);
2324 SetList(halfcols + (col + 1) / 2 - 3 * row - 3, halfrows + row + 2 - col / 2 - 1 + odd);
2325 SetList(halfcols - (col + 1) / 2 + 3 * row + 3, halfrows + row + 2 - col / 2 - 1 + odd);
2326 SetList(halfcols - col + 3 * row + 3, halfrows + row + 1 + odd);
2327 SetList(halfcols + col - 3 * row - 3, halfrows + row + 1 + odd);
2328 }
2329 }
2330 }
2331 if (NRAND(100) < percent) {
2332 /* center triangle */
2333 SetList(halfcols, halfrows + odd);
2334 }
2335 }
2336 } else if (lp->polygon == 4) {
2337 vx = vy = (vx + vy) / 2;
2338 for (row = -vy; row < 0; ++row) {
2339 for (col = row; col < vx; ++col) {
2340 if (NRAND(100) < percent) {
2341 SetList(col + halfcols, row + halfrows);
2342 SetList(row + halfcols, col + halfrows);
2343 SetList(-col + halfcols, -row + halfrows);
2344 SetList(-row + halfcols, -col + halfrows);
2345 }
2346 }
2347 }
2348 } else if (lp->polygon == 6) {
2349 if (even == 1) {
2350 vx = vy = 2 * (vx + vy) / 3;
2351 for (row = 0; row < vy; ++row) {
2352 for (col = 0; col < row / 2 + 1; ++col) { /* 2 6 10 */
2353 if (NRAND(100) < percent) {
2354 SetList(halfcols + (col + row + (halfrows + 1) % 2) / 2 - 1 + halfrows % 2, halfrows - row + col + 2);
2355 SetList(halfcols + row - (col + (halfrows + 1) % 2) / 2 - 1, halfrows - col + 1);
2356 SetList(halfcols - col + (row + halfrows % 2) / 2, halfrows + row - 1);
2357 SetList(halfcols + col - (row + (halfrows + 1) % 2) / 2 + 1, halfrows + row - 1);
2358 SetList(halfcols - row + (col + halfrows % 2) / 2 + 2, halfrows - col + 1);
2359 SetList(halfcols - (col + row + halfrows % 2) / 2 + 1 + halfrows % 2, halfrows - row + col + 2);
2360 }
2361 }
2362 }
2363 for (row = 0; row < vy; ++row) {
2364 for (col = 0; col < row / 2; ++col) {
2365 if (NRAND(100) < percent) { /* 0 4 8 */
2366 SetList(halfcols + col - (row + halfrows % 2) / 2 + 1 + halfrows % 2, halfrows - row + 2);
2367 SetList(halfcols - col + (row + (halfrows + 1) % 2) / 2 + halfrows % 2 - 1, halfrows - row + 2);
2368 SetList(halfcols + row - (col + (halfrows + 1) % 2) / 2 - 1, halfrows + col + 1);
2369 SetList(halfcols + (col + row + halfrows % 2) / 2, halfrows + row - col - 1);
2370 SetList(halfcols - (col + row + (halfrows + 1) % 2) / 2 + 1, halfrows + row - col - 1);
2371 SetList(halfcols - row + (col + halfrows % 2) / 2 + 2, halfrows + col + 1);
2372 }
2373 }
2374 }
2375 } else {
2376 vx = vy = 2 * (vx + vy) / 3;
2377 for (row = 0; row < vy; ++row) {
2378 for (col = 0; col <= row; ++col) {
2379 if (NRAND(100) < percent) {
2380 SetList(halfcols + col - (row + halfrows % 2) / 2, halfrows + row);
2381 SetList(halfcols + row - (col + halfrows % 2) / 2, halfrows - col);
2382 SetList(halfcols - (col + row + halfrows % 2) / 2, halfrows - row + col);
2383 SetList(halfcols + row - (col + halfrows % 2) / 2, halfrows + col);
2384 SetList(halfcols + col - (row + halfrows % 2) / 2, halfrows - row);
2385 SetList(halfcols - (col + row + halfrows % 2) / 2, halfrows + row - col);
2386 }
2387 }
2388 }
2389 if (NRAND(100) < percent) {
2390 SetList(halfcols, halfrows);
2391 }
2392 }
2393 }
2394 (void) strcpy(lp->nameString, "Half Sym Random");
2395 break;
2396 case 8: /* Full Antisym Random */
2397 /* Square, Hexagonal (on face hex, on corner tri) */
2398 if (lp->polygon == 3) {
2399 int odd = (halfcols + halfrows) % 2;
2400
2401 vx = vy = (vx + vy) / 3;
2402 for (row = 0; row < vy; ++row) {
2403 for (col = 0; col < 2 * row + 1; ++col) {
2404 if (NRAND(100) < percent) {
2405 SetList(halfcols + col - row, halfrows - row - 1 + odd);
2406 SetList(halfcols - (col + 1) / 2 + 2 * row + 1, halfrows + col / 2 + odd);
2407 SetList(halfcols - col / 2 - row - 1, halfrows + row - (col + 1) / 2 + odd);
2408 SetList(halfcols - col + row, halfrows + row + odd);
2409 SetList(halfcols + (col + 1) / 2 - 2 * row - 1, halfrows - col / 2 - 1 + odd);
2410 SetList(halfcols + col / 2 + row + 1, halfrows - row + (col + 1) / 2 - 1 + odd);
2411 }
2412 }
2413 }
2414 } else if (lp->polygon == 4) {
2415 vx = vy = (vx + vy) / 2;
2416 for (row = -vy; row < 0; ++row) {
2417 for (col = row; col < vx; ++col) {
2418 if (NRAND(100) < percent) {
2419 SetList(col + halfcols + even, row + halfrows + even);
2420 SetList(row + halfcols + even, -col + halfrows);
2421 SetList(-col + halfcols, -row + halfrows);
2422 SetList(-row + halfcols, col + halfrows + even);
2423 }
2424 }
2425 }
2426 if (even == 0 && NRAND(100) < percent) {
2427 SetList(halfcols, halfrows);
2428 }
2429 } else if (lp->polygon == 6) {
2430 vx = vy = 2 * (vx + vy) / 3;
2431 for (row = 0; row < vy; ++row) {
2432 for (col = 0; col < row; ++col) {
2433 if (NRAND(100) < percent) {
2434 SetList(halfcols - col + (row + (halfrows + 1) % 2) / 2, halfrows + row);
2435 SetList(halfcols + (col + row + (halfrows + 1) % 2) / 2, halfrows - row + col);
2436 SetList(halfcols - row + (col + (halfrows + 1) % 2) / 2, halfrows - col);
2437 SetList(halfcols + row - (col + halfrows % 2) / 2, halfrows + col);
2438 SetList(halfcols + col - (row + halfrows % 2) / 2, halfrows - row);
2439 SetList(halfcols - (col + row + halfrows % 2) / 2, halfrows + row - col);
2440 }
2441 }
2442 }
2443 if (NRAND(100) < percent) {
2444 SetList(halfcols, halfrows);
2445 }
2446 }
2447 (void) strcpy(lp->nameString, "Full Antisym Random");
2448 break;
2449 case 9: /* Full Sym Random */
2450 /* Square, Hexagonal (on face hex, on corner tri) */
2451 if (lp->polygon == 3) {
2452 int odd = (halfcols + halfrows) % 2;
2453
2454 vx = vy = (vx + vy) / 3;
2455 for (row = 0; row < vy; ++row) {
2456 for (col = 0; col < row + 1; ++col) {
2457 if (NRAND(100) < percent) {
2458 SetList(halfcols - col + row, halfrows - row - 1 + odd); /* 0 */
2459 SetList(halfcols + col / 2 + row + 1, halfrows - row + (col + 1) / 2 - 1 + odd); /* 1 */
2460 SetList(halfcols + (col + 1) / 2 - 2 * row - 1, halfrows + col / 2 + odd); /* 2 */
2461 SetList(halfcols - (col + 1) / 2 + 2 * row + 1, halfrows + col / 2 + odd); /* 3 */
2462 SetList(halfcols - col / 2 - row - 1, halfrows - row + (col + 1) / 2 - 1 + odd); /* 4 */
2463 SetList(halfcols - col + row, halfrows + row + odd); /* 5 */
2464 SetList(halfcols + col - row, halfrows + row + odd); /* 6 */
2465 SetList(halfcols - col / 2 - row - 1, halfrows + row - (col + 1) / 2 + odd); /* 7 */
2466 SetList(halfcols - (col + 1) / 2 + 2 * row + 1, halfrows - col / 2 - 1 + odd); /* 8 */
2467 SetList(halfcols + (col + 1) / 2 - 2 * row - 1, halfrows - col / 2 - 1 + odd); /* 9 */
2468 SetList(halfcols + col / 2 + row + 1, halfrows + row - (col + 1) / 2 + odd); /* 10 */
2469 SetList(halfcols + col - row, halfrows - row - 1 + odd); /* 11 */
2470 }
2471 }
2472 }
2473 } else if (lp->polygon == 4) {
2474 vx = vy = (vx + vy) / 2;
2475 for (row = -vy; row < 0; ++row) {
2476 for (col = row; col <= 0; ++col) {
2477 if (NRAND(100) < percent) {
2478 SetList(col + halfcols + even, row + halfrows + even);
2479 SetList(row + halfcols + even, -col + halfrows);
2480 SetList(-col + halfcols, -row + halfrows);
2481 SetList(-row + halfcols, col + halfrows + even);
2482 SetList(-col + halfcols, row + halfrows + even);
2483 SetList(-row + halfcols, -col + halfrows);
2484 SetList(col + halfcols + even, -row + halfrows);
2485 SetList(row + halfcols + even, col + halfrows + even);
2486 }
2487 }
2488 }
2489 if (even == 0 && NRAND(100) < percent) {
2490 SetList(halfcols, halfrows);
2491 }
2492 } else if (lp->polygon == 6) {
2493 vx = vy = 2 * (vx + vy) / 3;
2494 for (row = 0; row < vy; ++row) {
2495 for (col = 0; col <= row / 2; ++col) {
2496 if (NRAND(100) < percent) {
2497 SetList(halfcols - col + (row + (halfrows + 1) % 2) / 2, halfrows + row);
2498 SetList(halfcols + (col + row + (halfrows + 1) % 2) / 2, halfrows - row + col);
2499 SetList(halfcols - row + (col + (halfrows + 1) % 2) / 2, halfrows - col);
2500 SetList(halfcols + row - (col + halfrows % 2) / 2, halfrows + col);
2501 SetList(halfcols + col - (row + halfrows % 2) / 2, halfrows - row);
2502 SetList(halfcols - (col + row + halfrows % 2) / 2, halfrows + row - col);
2503 SetList(halfcols + col - (row + halfrows % 2) / 2, halfrows + row);
2504 SetList(halfcols + row - (col + halfrows % 2) / 2, halfrows - col);
2505 SetList(halfcols - (col + row + halfrows % 2) / 2, halfrows - row + col);
2506 SetList(halfcols - row + (col + (halfrows + 1) % 2) / 2, halfrows + col);
2507 SetList(halfcols + (col + row + (halfrows + 1) % 2) / 2, halfrows + row - col);
2508 SetList(halfcols - col + (row + (halfrows + 1) % 2) / 2, halfrows - row);
2509 }
2510 }
2511 }
2512 if (NRAND(100) < percent) {
2513 SetList(halfcols, halfrows);
2514 }
2515 }
2516 (void) strcpy(lp->nameString, "Full Sym Random");
2517 break;
2518 default:
2519 (void) fprintf(stderr, "wrong symmetry %d\n", symmetryIndex);
2520 }
2521 if (MI_IS_VERBOSE(mi)) {
2522 (void) fprintf(stdout, "%s\n", lp->nameString);
2523 }
2524 }
2525
2526 static void
GetPattern(ModeInfo * mi,int pattern_rule,int pattern)2527 GetPattern(ModeInfo * mi, int pattern_rule, int pattern)
2528 {
2529 lifestruct *lp = &lifes[MI_SCREEN(mi)];
2530 int row, col, orient = 0, temp, startX, startY;
2531 char *patptr = (char *) NULL;
2532 #ifdef LIFE_NAMES
2533 int pat = 2 * pattern + 1;
2534 char * patstrg = (char *) "";
2535 #else
2536 int pat = pattern;
2537 #endif
2538
2539 if (filePattern) {
2540 patptr = &filePattern[0];
2541 #ifdef LIFE_NAMES
2542 (void) strcpy(lp->nameString, patstrg);
2543 #endif
2544 } else {
2545 switch (lp->neighbors) {
2546 case 5:
2547 switch (pattern_rule) {
2548 case LIFE_5B2S24:
2549 patptr = &patterns_5B2S24[pat][0];
2550 #ifdef LIFE_NAMES
2551 patstrg = &patterns_5B2S24[2 * pattern][0];
2552 #endif
2553 break;
2554 case LIFE_5B24S2:
2555 patptr = &patterns_5B24S2[pat][0];
2556 #ifdef LIFE_NAMES
2557 patstrg = &patterns_5B24S2[2 * pattern][0];
2558 #endif
2559 }
2560 break;
2561 case 6:
2562 switch (pattern_rule) {
2563 case LIFE_6B2oS2m34:
2564 patptr = &patterns_6B2oS2m34[pat][0];
2565 #ifdef LIFE_NAMES
2566 patstrg = &patterns_6B2oS2m34[2 * pattern][0];
2567 #endif
2568 break;
2569 case LIFE_6B2o3o4mS2om4o:
2570 patptr = &patterns_6B2o3o4mS2om4o[pat][0];
2571 #ifdef LIFE_NAMES
2572 patstrg = &patterns_6B2o3o4mS2om4o[2 * pattern][0];
2573 #endif
2574 break;
2575 case LIFE_6B2S35:
2576 patptr = &patterns_6B2S35[pat][0];
2577 #ifdef LIFE_NAMES
2578 patstrg = &patterns_6B2S35[2 * pattern][0];
2579 #endif
2580 break;
2581 case LIFE_6B245S3:
2582 patptr = &patterns_6B245S3[pat][0];
2583 #ifdef LIFE_NAMES
2584 patstrg = &patterns_6B245S3[2 * pattern][0];
2585 #endif
2586 break;
2587 case LIFE_6B2S34:
2588 patptr = &patterns_6B2S34[pat][0];
2589 #ifdef LIFE_NAMES
2590 patstrg = &patterns_6B2S34[2 * pattern][0];
2591 #endif
2592 break;
2593 }
2594 break;
2595 case 7:
2596 /*switch (pattern_rule) {
2597 case LIFE_7B346S23:*/
2598 patptr = &patterns_7B346S23[pat][0];
2599 #ifdef LIFE_NAMES
2600 patstrg = &patterns_7B346S23[2 * pattern][0];
2601 #endif
2602 /*break;*/
2603 break;
2604 case 8:
2605 switch (pattern_rule) {
2606 case LIFE_8B3S2ckan3:
2607 patptr = &patterns_8B3S2ckan3[pat][0];
2608 #ifdef LIFE_NAMES
2609 patstrg = &patterns_8B3S2ckan3[2 * pattern][0];
2610 #endif
2611 break;
2612 case LIFE_8B3S23:
2613 if (pattern < (int) common_8size) {
2614 patptr = &patterns_8B3_6S23[pat][0];
2615 #ifdef LIFE_NAMES
2616 patstrg = &patterns_8B3_6S23[2 * pattern][0];
2617 #endif
2618 } else {
2619 patptr = &patterns_8B3S23[pat - PAT_SPACE * common_8size][0];
2620 #ifdef LIFE_NAMES
2621 patstrg = &patterns_8B3S23[2 * pattern - 2 * common_8size][0];
2622 #endif
2623 }
2624 break;
2625 case LIFE_8B36S23:
2626 if (pattern < (int) common_8size) {
2627 patptr = &patterns_8B3_6S23[pat][0];
2628 #ifdef LIFE_NAMES
2629 patstrg = &patterns_8B3_6S23[2 * pattern][0];
2630 #endif
2631 } else {
2632 patptr = &patterns_8B36S23[pat - PAT_SPACE * common_8size][0];
2633 #ifdef LIFE_NAMES
2634 patstrg = &patterns_8B36S23[2 * pattern - 2 * common_8size][0];
2635 #endif
2636 }
2637 break;
2638 case LIFE_8B3678S34678:
2639 patptr = &patterns_8B3678S34678[pat][0];
2640 #ifdef LIFE_NAMES
2641 patstrg = &patterns_8B3678S34678[2 * pattern][0];
2642 #endif
2643 break;
2644 case LIFE_8B3S245:
2645 patptr = &patterns_8B3S245[pat][0];
2646 #ifdef LIFE_NAMES
2647 patstrg = &patterns_8B3S245[2 * pattern][0];
2648 #endif
2649 break;
2650 case LIFE_8B36S245:
2651 patptr = &patterns_8B36S245[pat][0];
2652 #ifdef LIFE_NAMES
2653 patstrg = &patterns_8B36S245[2 * pattern][0];
2654 #endif
2655 break;
2656 }
2657 break;
2658 case 9:
2659 switch (pattern_rule) {
2660 case LIFE_9B34S3:
2661 patptr = &patterns_9B34S3[pat][0];
2662 #ifdef LIFE_NAMES
2663 patstrg = &patterns_9B34S3[2 * pattern][0];
2664 #endif
2665 break;
2666 case LIFE_9B3S34: /* has replicator */
2667 patptr = &patterns_9B3S34[pat][0];
2668 #ifdef LIFE_NAMES
2669 patstrg = &patterns_9B3S34[2 * pattern][0];
2670 #endif
2671 break;
2672 }
2673 break;
2674 case 12:
2675 switch (pattern_rule) {
2676 case LIFE_12B45S34:
2677 patptr = &patterns_12B45S34[pat][0];
2678 #ifdef LIFE_NAMES
2679 patstrg = &patterns_12B45S34[2 * pattern][0];
2680 #endif
2681 break;
2682 case LIFE_12B456S45:
2683 patptr = &patterns_12B456S45[pat][0];
2684 #ifdef LIFE_NAMES
2685 patstrg = &patterns_12B456S45[2 * pattern][0];
2686 #endif
2687 break;
2688 case LIFE_12B45S23:
2689 patptr = &patterns_12B45S23[pat][0];
2690 #ifdef LIFE_NAMES
2691 patstrg = &patterns_12B45S23[2 * pattern][0];
2692 #endif
2693 break;
2694 case LIFE_12B456S23:
2695 patptr = &patterns_12B456S23[pat][0];
2696 #ifdef LIFE_NAMES
2697 patstrg = &patterns_12B456S23[2 * pattern][0];
2698 #endif
2699 break;
2700 case LIFE_12B456S12:
2701 patptr = &patterns_12B456S12[pat][0];
2702 #ifdef LIFE_NAMES
2703 patstrg = &patterns_12B456S12[2 * pattern][0];
2704 #endif
2705 break;
2706 case LIFE_12B3S2:
2707 patptr = &patterns_12B3S2[pat][0];
2708 #ifdef LIFE_NAMES
2709 patstrg = &patterns_12B3S2[2 * pattern][0];
2710 #endif
2711 break;
2712 case LIFE_12B3S27:
2713 patptr = &patterns_12B3S27[pat][0];
2714 #ifdef LIFE_NAMES
2715 patstrg = &patterns_12B3S27[2 * pattern][0];
2716 #endif
2717 break;
2718 case LIFE_12B3S278:
2719 patptr = &patterns_12B3S278[pat][0];
2720 #ifdef LIFE_NAMES
2721 patstrg = &patterns_12B3S278[2 * pattern][0];
2722 #endif
2723 break;
2724 case LIFE_12B46S24:
2725 patptr = &patterns_12B46S24[pat][0];
2726 #ifdef LIFE_NAMES
2727 patstrg = &patterns_12B46S24[2 * pattern][0];
2728 #endif
2729 break;
2730 case LIFE_12B46S246:
2731 patptr = &patterns_12B46S246[pat][0];
2732 #ifdef LIFE_NAMES
2733 patstrg = &patterns_12B46S246[2 * pattern][0];
2734 #endif
2735 break;
2736 case LIFE_12B456S34:
2737 patptr = &patterns_12B456S34[pat][0];
2738 #ifdef LIFE_NAMES
2739 patstrg = &patterns_12B456S34[2 * pattern][0];
2740 #endif
2741 break;
2742 case LIFE_12B4S35:
2743 patptr = &patterns_12B4S35[pat][0];
2744 #ifdef LIFE_NAMES
2745 patstrg = &patterns_12B4S35[2 * pattern][0];
2746 #endif
2747 break;
2748 case LIFE_12B4S356:
2749 patptr = &patterns_12B4S356[pat][0];
2750 #ifdef LIFE_NAMES
2751 patstrg = &patterns_12B4S356[2 * pattern][0];
2752 #endif
2753 break;
2754 case LIFE_12B46S35:
2755 patptr = &patterns_12B46S35[pat][0];
2756 #ifdef LIFE_NAMES
2757 patstrg = &patterns_12B46S35[2 * pattern][0];
2758 #endif
2759 break;
2760 case LIFE_12B46S356:
2761 patptr = &patterns_12B46S356[pat][0];
2762 #ifdef LIFE_NAMES
2763 patstrg = &patterns_12B46S356[2 * pattern][0];
2764 #endif
2765 break;
2766 case LIFE_12B4S456:
2767 patptr = &patterns_12B4S456[pat][0];
2768 #ifdef LIFE_NAMES
2769 patstrg = &patterns_12B4S456[2 * pattern][0];
2770 #endif
2771 break;
2772 case LIFE_12B3S23:
2773 patptr = &patterns_12B3S23[pat][0];
2774 #ifdef LIFE_NAMES
2775 patstrg = &patterns_12B3S23[2 * pattern][0];
2776 #endif
2777 break;
2778 case LIFE_12B4S345:
2779 patptr = &patterns_12B4S345[pat][0];
2780 #ifdef LIFE_NAMES
2781 patstrg = &patterns_12B4S345[2 * pattern][0];
2782 #endif
2783 break;
2784 }
2785 break;
2786 }
2787 #ifdef LIFE_NAMES
2788 (void) strcpy(lp->nameString, patstrg);
2789 #endif
2790 }
2791 #ifndef DEBUG
2792 if (lp->polygon == 3 || lp->polygon == 6) {
2793 orient = NRAND(12);
2794 } else if (lp->polygon == 4 || lp->polygon == 5) {
2795 orient = NRAND(8);
2796 }
2797 #endif
2798 if (MI_IS_VERBOSE(mi) && !filePattern) {
2799 #ifdef LIFE_NAMES
2800 (void) fprintf(stdout, "%s, ", patstrg);
2801 #endif
2802 (void) fprintf(stdout, "table number %d\n", pattern);
2803 }
2804 while ((col = *patptr++) != 127) {
2805 row = *patptr++;
2806 if (lp->polygon == 3) {
2807 temp = col;
2808 col = row;
2809 row = temp;
2810 if (orient >= 6) {
2811 row = -row;
2812 }
2813 /* (a,b) => (b, b-a) */
2814 switch (orient % 6) {
2815 case 0:
2816 break;
2817 case 1:
2818 temp = col;
2819 col = CEIL(temp + row);
2820 row = CEIL(row - temp + 1) - temp;
2821 break;
2822 case 2:
2823 temp = col;
2824 col = CEIL(temp - row);
2825 row = temp - CEIL(1 - row - temp);
2826 break;
2827 case 3:
2828 col = -col + 1;
2829 row = -row;
2830 break;
2831 case 4:
2832 temp = col;
2833 col = 1 - CEIL(temp + row);
2834 row = temp - CEIL(row - temp + 1);
2835 break;
2836 case 5:
2837 temp = col;
2838 col = 1 - CEIL(temp - row);
2839 row = CEIL(1 - row - temp) - temp;
2840 break;
2841 }
2842 } else if (lp->polygon == 4) {
2843 if (orient >= 4) {
2844 temp = col;
2845 col = row;
2846 row = temp;
2847 }
2848 /* Could have made it symmetrical with hexagons where
2849 (a,b) => (-b, a), this should be equivalent */
2850 if (orient % 4 >= 2) {
2851 row = -row;
2852 }
2853 if (orient & 1) {
2854 col = -col;
2855 }
2856 } else if (lp->polygon == 5) {
2857 int mod = MOD(col + 2 * row, 4);
2858 int tcol = row * 2;
2859 int trow = DIV(col, 2);
2860
2861 if (mod == 1 || mod == 2)
2862 tcol++;
2863 if (orient % 4 == 1) {
2864 col = -tcol - 1;
2865 row = trow;
2866 } else if (orient % 4 == 2) {
2867 col = -col - 1;
2868 row = -row - 1;
2869 } else if (orient % 4 == 3) {
2870 col = tcol;
2871 row = -trow - 1;
2872 }
2873 if (orient >= 4) {
2874 col = -col;
2875 col += 1;
2876 mod = MOD(col + 2 * row, 4);
2877 if (mod == 0)
2878 col++;
2879 if (mod == 1)
2880 col--;
2881 }
2882 } else if (lp->polygon == 6) {
2883 if (orient >= 6) {
2884 temp = col;
2885 col = row;
2886 row = temp;
2887 }
2888 /* (a,b) => (b, b-a) */
2889 switch (orient % 6) {
2890 case 0:
2891 break;
2892 case 1:
2893 temp = row;
2894 row = temp - col;
2895 col = temp;
2896 break;
2897 case 2:
2898 temp = -col;
2899 col = temp + row;
2900 row = temp;
2901 break;
2902 case 3:
2903 col = -col;
2904 row = -row;
2905 break;
2906 case 4:
2907 temp = -row;
2908 row = temp + col;
2909 col = temp;
2910 break;
2911 case 5:
2912 temp = col;
2913 col = temp - row;
2914 row = temp;
2915 break;
2916 }
2917 }
2918 startX = lp->ncols / 2;
2919 startY = lp->nrows / 2;
2920 if (lp->polygon == 5) {
2921 startX -= (startX + startY * 2) % 4;
2922 }
2923 col += startX;
2924 if (lp->polygon == 6) {
2925 if (row < 0)
2926 col += (startX & 1) ? -row / 2 :
2927 -(row - 1) / 2;
2928 else
2929 col += (startX & 1) ? -(row + 1) / 2 :
2930 -row / 2;
2931 }
2932 row += startY;
2933 if (lp->polygon == 3 &&
2934 (((startX + startY + 1) & 1) == 1)) {
2935 row++;
2936 }
2937 SetListFromGet(col, row);
2938 }
2939 }
2940
2941 static void
shooter(ModeInfo * mi)2942 shooter(ModeInfo * mi)
2943 {
2944 lifestruct *lp = &lifes[MI_SCREEN(mi)];
2945 int hsp, vsp, hoff = 1, voff = 1, temp;
2946
2947 /* Generate the glider at the edge of the screen */
2948 if (lp->neighbors == 6 && (lp->patterned_rule == LIFE_6B2oS2m34 ||
2949 lp->patterned_rule == LIFE_6B2o3o4mS2om4o ||
2950 lp->patterned_rule == LIFE_6B2S35 ||
2951 lp->patterned_rule == LIFE_6B245S3)) {
2952 int hhex = 0, diagonal, quad;
2953
2954 diagonal = NRAND(3);
2955 if (diagonal) {
2956 temp = MIN((lp->nrows + lp->ncols) / 3, 18);
2957 temp = NRAND(temp) - temp / 2;
2958 /* Take into account it is a 60 degree angle not 45 */
2959 if ((lp->ncols + temp) * 1.35 > lp->nrows) {
2960
2961 hsp = (int) ((lp->ncols + temp) * 1.35 -
2962 lp->nrows) / 2;
2963 vsp = 0;
2964 #ifdef HEXDEBUG
2965 (void) printf("a: ");
2966 #endif
2967 } else {
2968 hsp = 0;
2969 vsp = (int) (lp->nrows -
2970 (lp->ncols + temp)) / 2;
2971 #ifdef HEXDEBUG
2972 (void) printf("b: ");
2973 #endif
2974 }
2975 quad = NRAND(4);
2976 #ifdef HEXDEBUG
2977 (void) printf("quad=%d, ", quad);
2978 #endif
2979 switch (quad) {
2980 case 0: /* Upper left */
2981 vsp = (vsp & 1) ? vsp : vsp + 1;
2982 hhex = 1;
2983 break;
2984 case 1: /* Lower left */
2985 hoff = -1;
2986 hsp = lp->ncols - 1 - hsp;
2987 vsp = (vsp & 1) ? vsp + 1 : vsp;
2988 hhex = hoff;
2989 break;
2990 case 2: /* Upper right */
2991 voff = -1;
2992 vsp = lp->nrows - 1 - vsp;
2993 vsp = (vsp & 1) ? vsp : vsp - 1;
2994 hhex = hoff;
2995 break;
2996 case 3: /* Lower right */
2997 voff = -1;
2998 hoff = -1;
2999 hsp = lp->ncols - 1 - hsp;
3000 vsp = lp->nrows - 1 - vsp;
3001 vsp = (vsp & 1) ? vsp - 1 : vsp;
3002 hhex = hoff;
3003 break;
3004 }
3005 } else {
3006 temp = MIN(lp->nrows / 3, 18);
3007 vsp = lp->nrows / 2 + NRAND(temp) - temp / 2;
3008 if (LRAND() & 1) {
3009 hsp = lp->ncols - 1;
3010 hoff = -1;
3011 hhex = (vsp & 1) ? 0 : hoff;
3012 } else {
3013 hsp = 0;
3014 hhex = (vsp & 1) ? hoff : 0;
3015 }
3016 voff = (LRAND() & 1) ? 1 : -1; /* Mirror image */
3017 }
3018 #ifdef HEXDEBUG
3019 (void) printf("hhex=%d, hsp=%d, hoff=%d, vsp=%d, voff=%d\n",
3020 hhex, hsp, hoff, vsp, voff);
3021 #endif
3022 if (lp->patterned_rule == LIFE_6B2oS2m34) {
3023 if (diagonal) {
3024 SetList(hsp + hhex, vsp);
3025 if (LRAND() & 1) {
3026 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3027 SetList(hsp + 2 * hoff + hhex, vsp + 2 * voff);
3028 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3029 SetList(hsp + 1 * hoff + hhex, vsp + 4 * voff);
3030 SetList(hsp + hhex, vsp + 4 * voff);
3031 } else { /* Mirror image */
3032 SetList(hsp + 3 * hoff + hhex, vsp + 2 * voff);
3033 SetList(hsp + 0 * hoff, vsp + 3 * voff);
3034 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3035 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3036 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3037 }
3038 } else {
3039 SetList(hsp + 2 * hoff + hhex, vsp + 2 * voff);
3040 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3041 SetList(hsp + 3 * hoff + hhex, vsp + 0 * voff);
3042 SetList(hsp + 0 * hoff + hhex, vsp + 0 * voff);
3043 SetList(hsp + 4 * hoff, vsp - 1 * voff);
3044 SetList(hsp + 3 * hoff + hhex, vsp - 2 * voff);
3045 }
3046 } else if (lp->patterned_rule == LIFE_6B2o3o4mS2om4o) {
3047 if (diagonal) {
3048 switch (NRAND(3)) { /* 3 different gliders */
3049 case 0:
3050 /* No mirror image */
3051 SetList(hsp + 2 * hoff + hhex, vsp + 0 * voff);
3052 SetList(hsp + 3 * hoff + hhex, vsp + 0 * voff);
3053 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3054 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3055 SetList(hsp + 0 * hoff + hhex, vsp + 2 * voff);
3056 break;
3057 case 1:
3058 if (LRAND() & 1) {
3059 SetList(hsp + 0 * hoff + hhex, vsp + 0 * voff);
3060 SetList(hsp + 1 * hoff + hhex, vsp + 0 * voff);
3061 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3062 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3063 SetList(hsp + 0 * hoff + hhex, vsp + 2 * voff);
3064 SetList(hsp + 1 * hoff + hhex, vsp + 2 * voff);
3065 SetList(hsp + 2 * hoff + hhex, vsp + 2 * voff);
3066 } else {
3067 SetList(hsp + 1 * hoff + hhex, vsp + 0 * voff);
3068 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3069 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3070 SetList(hsp + 2 * hoff + hhex, vsp + 2 * voff);
3071 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3072 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3073 SetList(hsp + 0 * hoff + hhex, vsp + 4 * voff);
3074 }
3075 break;
3076 case 2:
3077 if (LRAND() & 1) {
3078 SetList(hsp + 1 * hoff + hhex, vsp + 0 * voff);
3079 SetList(hsp + 2 * hoff + hhex, vsp + 2 * voff);
3080 SetList(hsp + 3 * hoff + hhex, vsp + 2 * voff);
3081 SetList(hsp + 0 * hoff, vsp + 3 * voff);
3082 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3083 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3084 } else {
3085 SetList(hsp + 0 * hoff + hhex, vsp + 0 * voff);
3086 SetList(hsp + 3 * hoff + hhex, vsp + 0 * voff);
3087 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3088 SetList(hsp + 1 * hoff + hhex, vsp + 2 * voff);
3089 SetList(hsp + 2 * hoff + hhex, vsp + 2 * voff);
3090 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3091 }
3092 }
3093 } else {
3094 switch (NRAND(3)) { /* 3 different gliders */
3095 case 0:
3096 SetList(hsp + 0 * hoff + hhex, vsp + 0 * voff);
3097 SetList(hsp + 0 * hoff + hhex, vsp - 2 * voff);
3098 SetList(hsp + 0 * hoff + hhex, vsp + 2 * voff);
3099 SetList(hsp + 0 * hoff, vsp - 1 * voff);
3100 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3101 break;
3102 case 1:
3103 SetList(hsp + 0 * hoff + hhex, vsp + 0 * voff);
3104 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3105 SetList(hsp + 1 * hoff + hhex, vsp + 2 * voff);
3106 SetList(hsp + 2 * hoff + hhex, vsp - 2 * voff);
3107 SetList(hsp + 2 * hoff, vsp - 1 * voff);
3108 SetList(hsp + 2 * hoff + hhex, vsp + 0 * voff);
3109 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3110 break;
3111 case 2:
3112 SetList(hsp + 0 * hoff, vsp - 1 * voff);
3113 SetList(hsp + 1 * hoff + hhex, vsp + 2 * voff);
3114 SetList(hsp + 2 * hoff + hhex, vsp - 2 * voff);
3115 SetList(hsp + 2 * hoff, vsp - 1 * voff);
3116 SetList(hsp + 2 * hoff + hhex, vsp + 0 * voff);
3117 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3118 }
3119 }
3120 } else if (lp->patterned_rule == LIFE_6B2S35) {
3121 if (diagonal) {
3122 /* No mirror image */
3123 SetList(hsp + 0 * hoff + hhex, vsp + 1 * voff);
3124 SetList(hsp + 1 * hoff, vsp + 4 * voff);
3125 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3126 SetList(hsp + 2 * hoff, vsp + 5 * voff);
3127 SetList(hsp + 2 * hoff + hhex, vsp + 0 * voff);
3128 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3129 SetList(hsp + 4 * hoff, vsp + 6 * voff);
3130 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3131 SetList(hsp + 5 * hoff, vsp + 3 * voff);
3132 SetList(hsp + 5 * hoff, vsp + 5 * voff);
3133 } else {
3134 SetList(hsp + 5 * hoff, vsp - 1 * voff);
3135 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3136 SetList(hsp + 3 * hoff + hhex, vsp - 2 * voff);
3137 SetList(hsp + 3 * hoff + hhex, vsp + 2 * voff);
3138 SetList(hsp + 2 * hoff, vsp - 3 * voff);
3139 SetList(hsp + 2 * hoff, vsp - 1 * voff);
3140 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3141 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3142 SetList(hsp + 0 * hoff, vsp - 1 * voff);
3143 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3144 }
3145 } else if (lp->patterned_rule == LIFE_6B245S3) {
3146 if (diagonal) {
3147 /* No mirror image */
3148 SetList(hsp + 3 * hoff + hhex, vsp + 0 * voff);
3149 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3150 SetList(hsp + 0 * hoff + hhex, vsp + 2 * voff);
3151 SetList(hsp + 3 * hoff + hhex, vsp + 2 * voff);
3152 SetList(hsp + 5 * hoff + hhex, vsp + 2 * voff);
3153
3154 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3155 SetList(hsp + 4 * hoff + hhex, vsp + 4 * voff);
3156 SetList(hsp + 1 * hoff, vsp + 5 * voff);
3157 SetList(hsp + 3 * hoff, vsp + 5 * voff);
3158 } else {
3159 SetList(hsp + 4 * hoff, vsp - 1 * voff);
3160 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3161 SetList(hsp + 3 * hoff, vsp - 3 * voff);
3162 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3163 SetList(hsp + 2 * hoff, vsp - 1 * voff);
3164 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3165 SetList(hsp + 0 * hoff + hhex, vsp - 2 * voff);
3166 SetList(hsp + 0 * hoff + hhex, vsp - 0 * voff);
3167 SetList(hsp + 0 * hoff + hhex, vsp + 2 * voff);
3168 }
3169 }
3170 } else if ((lp->neighbors == 5 && lp->patterned_rule == LIFE_5B2S24) ||
3171 (lp->neighbors == 7 && lp->patterned_rule == LIFE_7B346S23)) {
3172 int reverse = 0; /* up/down pentagons need special handling */
3173
3174 if (LRAND() & 1) {
3175 hsp = (LRAND() & 1) ? 0 : lp->ncols - 3;
3176 vsp = 2 * (NRAND(lp->nrows / 2));
3177 if (vsp > lp->nrows / 2)
3178 voff = -1;
3179 if (hsp > lp->ncols / 2)
3180 hoff = -1;
3181 } else {
3182 vsp = (LRAND() & 1) ? 0 : lp->nrows - 2;
3183 hsp = 4 * (NRAND(lp->ncols / 4));
3184 if (vsp > lp->nrows / 2) {
3185 voff = -1;
3186 }
3187 if (hsp > lp->ncols / 2) {
3188 hoff = -1;
3189 hsp -= 3;
3190 }
3191 }
3192 if ((hoff == -1 && voff != -1) ||
3193 (hoff != -1 && voff == -1)) {
3194 reverse = 1;
3195 }
3196 /* for reversing, up/down pentagons have to be swapped */
3197 if (lp->neighbors == 5 && lp->patterned_rule == LIFE_5B2S24) {
3198 if (LRAND() & 1) {
3199 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3200 } else {
3201 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3202 }
3203 SetList(hsp + ((reverse) ? 3 : 2) * hoff, vsp + 1 * voff);
3204 SetList(hsp + ((reverse) ? 0 : 1) * hoff, vsp + 2 * voff);
3205 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3206 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3207 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3208 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3209 SetList(hsp + ((reverse) ? 3 : 2) * hoff, vsp + 3 * voff);
3210 #if 0
3211 SetList(hsp + ((reverse) ? 0 : 1) * hoff, vsp + 0 * voff);
3212 SetList(hsp + ((reverse) ? 4 : 5) * hoff, vsp + 0 * voff);
3213 SetList(hsp + ((reverse) ? 2 : 3) * hoff, vsp + 1 * voff);
3214 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3215 SetList(hsp + ((reverse) ? 1 : 0) * hoff, vsp + 2 * voff);
3216 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3217 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3218 SetList(hsp + ((reverse) ? 5 : 4) * hoff, vsp + 2 * voff);
3219 SetList(hsp + ((reverse) ? 3 : 2) * hoff, vsp + 3 * voff);
3220 #endif
3221 } else if (lp->neighbors == 7 && lp->patterned_rule == LIFE_7B346S23) {
3222 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3223 SetList(hsp + ((reverse) ? 6 : 7) * hoff, vsp + 1 * voff);
3224 SetList(hsp + ((reverse) ? 0 : 1) * hoff, vsp + 2 * voff);
3225 SetList(hsp + ((reverse) ? 4 : 5) * hoff, vsp + 2 * voff);
3226 SetList(hsp + 6 * hoff, vsp + 2 * voff);
3227 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3228 SetList(hsp + 5 * hoff, vsp + 3 * voff);
3229 SetList(hsp + 2 * hoff, vsp + 4 * voff);
3230 SetList(hsp + 3 * hoff, vsp + 4 * voff);
3231 }
3232 } else if (lp->neighbors == 8 && (lp->patterned_rule == LIFE_8B3S2ckan3)) {
3233 /* Generate a space ship: c/5 p5, c/3 p3 */
3234 /* where p5 more common */
3235 int coord;
3236 int SS = NRAND(3);
3237
3238 SS = (SS < 2) ? 0 : 1;
3239 if (LRAND() & 1) {
3240 hsp = (LRAND() & 1) ? 0 : lp->ncols - 1;
3241 vsp = NRAND(lp->nrows / 2) + lp->nrows / 4;
3242 coord = 1;
3243 } else {
3244 vsp = (LRAND() & 1) ? 0 : lp->nrows - 1;
3245 hsp = NRAND(lp->ncols / 2) + lp->ncols / 4;
3246 coord = 0;
3247 }
3248 if (vsp > lp->nrows / 2)
3249 voff = -1;
3250 if (hsp > lp->ncols / 2)
3251 hoff = -1;
3252 if (coord == 1) {
3253 if (SS) {
3254 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3255 SetList(hsp + 0 * hoff, vsp + 3 * voff);
3256 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3257 SetList(hsp + 1 * hoff, vsp + 4 * voff);
3258 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3259 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3260 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3261 } else {
3262 SetList(hsp + 0 * hoff, vsp + 0 * voff);
3263 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3264 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3265 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3266 }
3267 } else {
3268 if (SS) {
3269 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3270 SetList(hsp + 3 * hoff, vsp + 0 * voff);
3271 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3272 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3273 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3274 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3275 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3276 } else {
3277 SetList(hsp + 0 * hoff, vsp + 0 * voff);
3278 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3279 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3280 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3281 }
3282 }
3283 } else if (lp->neighbors == 8 && (lp->patterned_rule == LIFE_8B3S23 ||
3284 lp->patterned_rule == LIFE_8B36S23)) {
3285 if (NRAND(3) != 0) {
3286 /* Generate a glider */
3287 if (LRAND() & 1) {
3288 hsp = (LRAND() & 1) ? 0 : lp->ncols - 1;
3289 vsp = NRAND(lp->nrows);
3290 } else {
3291 vsp = (LRAND() & 1) ? 0 : lp->nrows - 1;
3292 hsp = NRAND(lp->ncols);
3293 }
3294 if (vsp > lp->nrows / 2)
3295 voff = -1;
3296 if (hsp > lp->ncols / 2)
3297 hoff = -1;
3298 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3299 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3300 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3301 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3302 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3303 } else {
3304 /* Generate a space ship: LWSS, MWSS, HWSS */
3305 /* where Light Weight ships are more common */
3306 int coord;
3307 int SS = NRAND(6);
3308
3309 SS = (SS < 3) ? 0 : ((SS >= 5) ? 2 : 1);
3310 if (LRAND() & 1) {
3311 hsp = (LRAND() & 1) ? 0 : lp->ncols - 1;
3312 vsp = NRAND(lp->nrows / 2) + lp->nrows / 4;
3313 coord = 1;
3314 } else {
3315 vsp = (LRAND() & 1) ? 0 : lp->nrows - 1;
3316 hsp = NRAND(lp->ncols / 2) + lp->ncols / 4;
3317 coord = 0;
3318 }
3319 if (vsp > lp->nrows / 2)
3320 voff = -1;
3321 if (hsp > lp->ncols / 2)
3322 hoff = -1;
3323 if (coord == 1) {
3324 SetList(hsp + (SS + 4) * hoff, vsp + 0 * voff);
3325 SetList(hsp + (SS + 3) * hoff, vsp + 0 * voff);
3326 SetList(hsp + (SS + 2) * hoff, vsp + 0 * voff);
3327 SetList(hsp + (SS + 1) * hoff, vsp + 0 * voff);
3328 if (SS == 2) {
3329 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3330 }
3331 if (SS != 0) {
3332 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3333 }
3334 SetList(hsp + (SS + 4) * hoff, vsp + 1 * voff);
3335 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3336 SetList(hsp + (SS + 4) * hoff, vsp + 2 * voff);
3337 SetList(hsp + (SS + 3) * hoff, vsp + 3 * voff);
3338 } else {
3339 SetList(hsp + 0 * hoff, vsp + (SS + 4) * voff);
3340 SetList(hsp + 0 * hoff, vsp + (SS + 3) * voff);
3341 SetList(hsp + 0 * hoff, vsp + (SS + 2) * voff);
3342 SetList(hsp + 0 * hoff, vsp + (SS + 1) * voff);
3343 if (SS == 2) {
3344 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3345 }
3346 if (SS != 0) {
3347 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3348 }
3349 SetList(hsp + 1 * hoff, vsp + (SS + 4) * voff);
3350 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3351 SetList(hsp + 2 * hoff, vsp + (SS + 4) * voff);
3352 SetList(hsp + 3 * hoff, vsp + (SS + 3) * voff);
3353 }
3354 }
3355 } else if (lp->neighbors == 8 && (lp->patterned_rule == LIFE_8B3S245 ||
3356 lp->patterned_rule == LIFE_8B36S245)) {
3357 if (LRAND() & 1) {
3358 hsp = (LRAND() & 1) ? 0 : lp->ncols - 1;
3359 vsp = NRAND(lp->nrows);
3360 } else {
3361 vsp = (LRAND() & 1) ? 0 : lp->nrows - 1;
3362 hsp = NRAND(lp->ncols);
3363 }
3364 if (vsp > lp->nrows / 2)
3365 voff = -1;
3366 if (hsp > lp->ncols / 2)
3367 hoff = -1;
3368 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3369 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3370 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3371 SetList(hsp + 0 * hoff, vsp + 0 * voff);
3372 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3373 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3374 } else if (lp->neighbors == 8 &&
3375 lp->patterned_rule == LIFE_8B3678S34678) {
3376 /* Generate a butterfly */
3377 if (LRAND() & 1) {
3378 hsp = (LRAND() & 1) ? 0 : lp->ncols - 1;
3379 vsp = NRAND(lp->nrows);
3380 } else {
3381 vsp = (LRAND() & 1) ? 0 : lp->nrows - 1;
3382 hsp = NRAND(lp->ncols);
3383 }
3384 if (vsp > lp->nrows / 2)
3385 voff = -1;
3386 if (hsp > lp->ncols / 2)
3387 hoff = -1;
3388 SetList(hsp + 4 * hoff, vsp + 3 * voff);
3389 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3390 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3391 SetList(hsp + 3 * hoff, vsp + 4 * voff);
3392 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3393 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3394 SetList(hsp + 3 * hoff, vsp + 0 * voff);
3395 SetList(hsp + 2 * hoff, vsp + 4 * voff);
3396 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3397 SetList(hsp + 1 * hoff, vsp + 4 * voff);
3398 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3399 SetList(hsp + 0 * hoff, vsp + 3 * voff);
3400 } else if ((lp->neighbors == 12 &&
3401 (lp->patterned_rule == LIFE_12B456S12 ||
3402 lp->patterned_rule == LIFE_12B45S23 ||
3403 lp->patterned_rule == LIFE_12B456S23 ||
3404 lp->patterned_rule == LIFE_12B46S246 ||
3405 lp->patterned_rule == LIFE_12B3S27 ||
3406 lp->patterned_rule == LIFE_12B3S278 ||
3407 lp->patterned_rule == LIFE_12B45S34 ||
3408 lp->patterned_rule == LIFE_12B456S34 ||
3409 lp->patterned_rule == LIFE_12B4S35 ||
3410 lp->patterned_rule == LIFE_12B4S356 ||
3411 lp->patterned_rule == LIFE_12B46S35 ||
3412 lp->patterned_rule == LIFE_12B46S356 ||
3413 lp->patterned_rule == LIFE_12B456S45 ||
3414 lp->patterned_rule == LIFE_12B4S456)) ||
3415 (lp->neighbors == 9 &&
3416 lp->patterned_rule == LIFE_9B34S3)) {
3417 Bool sides = LRAND() & 1; /* off by 1 if true */
3418 Bool pick = 0;
3419
3420 if (sides) { /* lower right */
3421 hsp = NRAND(lp->nrows);
3422 if (LRAND() & 1) {
3423 vsp = 0;
3424 if ((vsp + hsp) & 1)
3425 vsp++;
3426 } else {
3427 vsp = lp->ncols - 1;
3428 if (!((vsp + hsp) & 1))
3429 vsp--;
3430 }
3431 if (hsp > lp->nrows / 2)
3432 hoff = -1;
3433 if (vsp > lp->ncols / 2)
3434 voff = -1;
3435 } else { /* down */
3436 vsp = NRAND(lp->ncols / 2) + lp->ncols / 4;
3437 if (LRAND() & 1) {
3438 hsp = 0;
3439 } else {
3440 hsp = lp->nrows - 1;
3441 }
3442 if (hsp > lp->nrows / 2)
3443 hoff = -1;
3444 if (vsp > lp->ncols / 2) {
3445 voff = -1;
3446 if ((vsp + hsp) & 1)
3447 vsp--;
3448 } else {
3449 if (!((vsp + hsp) & 1))
3450 vsp++;
3451 }
3452 }
3453 if (lp->neighbors == 12 && lp->patterned_rule == LIFE_12B3S278) {
3454 pick = LRAND() & 1;
3455 }
3456 if (lp->neighbors == 9 /* need here only */ &&
3457 lp->patterned_rule == LIFE_9B34S3) {
3458 /* glider (3/20, p20) */
3459 int SS = NRAND(10);
3460
3461 if (SS == 0) {
3462 if (sides) {
3463 SetList(hsp + 0 * hoff, vsp + 6 * voff);
3464 SetList(hsp + 2 * hoff, vsp + 7 * voff);
3465 SetList(hsp + 3 * hoff, vsp + 7 * voff);
3466 SetList(hsp + 4 * hoff, vsp + 7 * voff);
3467 SetList(hsp + 5 * hoff, vsp + 7 * voff);
3468 SetList(hsp + 6 * hoff, vsp + 7 * voff);
3469 SetList(hsp + 7 * hoff, vsp + 6 * voff);
3470 SetList(hsp + 8 * hoff, vsp + 6 * voff);
3471 SetList(hsp + 9 * hoff, vsp + 6 * voff);
3472 SetList(hsp + 11 * hoff, vsp + 5 * voff);
3473 SetList(hsp + 12 * hoff, vsp + 5 * voff);
3474 SetList(hsp + 14 * hoff, vsp + 4 * voff);
3475 SetList(hsp + 15 * hoff, vsp + 4 * voff);
3476 SetList(hsp + 15 * hoff, vsp + 3 * voff);
3477 SetList(hsp + 17 * hoff, vsp + 3 * voff);
3478 SetList(hsp + 18 * hoff, vsp + 3 * voff);
3479 SetList(hsp + 18 * hoff, vsp + 2 * voff);
3480 SetList(hsp + 19 * hoff, vsp + 2 * voff);
3481 SetList(hsp + 19 * hoff, vsp + 1 * voff);
3482 SetList(hsp + 19 * hoff, vsp + 0 * voff);
3483 } else {
3484 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3485 SetList(hsp + 1 * hoff, vsp + 13 * voff);
3486 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3487 SetList(hsp + 3 * hoff, vsp + 12 * voff);
3488 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3489 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3490 SetList(hsp + 4 * hoff, vsp + 4 * voff);
3491 SetList(hsp + 4 * hoff, vsp + 9 * voff);
3492 SetList(hsp + 4 * hoff, vsp + 11 * voff);
3493 SetList(hsp + 4 * hoff, vsp + 12 * voff);
3494 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3495 SetList(hsp + 5 * hoff, vsp + 3 * voff);
3496 SetList(hsp + 5 * hoff, vsp + 4 * voff);
3497 SetList(hsp + 5 * hoff, vsp + 5 * voff);
3498 SetList(hsp + 5 * hoff, vsp + 6 * voff);
3499 SetList(hsp + 5 * hoff, vsp + 7 * voff);
3500 SetList(hsp + 5 * hoff, vsp + 8 * voff);
3501 SetList(hsp + 5 * hoff, vsp + 9 * voff);
3502 SetList(hsp + 5 * hoff, vsp + 10 * voff);
3503 SetList(hsp + 5 * hoff, vsp + 11 * voff);
3504 }
3505 } else if (SS == 1) {
3506 if (sides) {
3507 SetList(hsp + 0 * hoff, vsp + 4 * voff);
3508 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3509 SetList(hsp + 2 * hoff, vsp + 4 * voff);
3510 SetList(hsp + 2 * hoff, vsp + 5 * voff);
3511 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3512 SetList(hsp + 4 * hoff, vsp + 3 * voff);
3513 SetList(hsp + 4 * hoff, vsp + 4 * voff);
3514 SetList(hsp + 4 * hoff, vsp + 5 * voff);
3515 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3516 SetList(hsp + 5 * hoff, vsp + 3 * voff);
3517 SetList(hsp + 5 * hoff, vsp + 4 * voff);
3518 SetList(hsp + 6 * hoff, vsp + 4 * voff);
3519 SetList(hsp + 7 * hoff, vsp + 3 * voff);
3520 SetList(hsp + 7 * hoff, vsp + 4 * voff);
3521 SetList(hsp + 9 * hoff, vsp + 3 * voff);
3522 SetList(hsp + 10 * hoff, vsp + 2 * voff);
3523 SetList(hsp + 10 * hoff, vsp + 3 * voff);
3524 SetList(hsp + 11 * hoff, vsp + 0 * voff);
3525 SetList(hsp + 11 * hoff, vsp + 1 * voff);
3526 SetList(hsp + 11 * hoff, vsp + 2 * voff);
3527 } else {
3528 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3529 SetList(hsp + 1 * hoff, vsp + 4 * voff);
3530 SetList(hsp + 1 * hoff, vsp + 7 * voff);
3531 SetList(hsp + 2 * hoff, vsp + 5 * voff);
3532 SetList(hsp + 2 * hoff, vsp + 6 * voff);
3533 SetList(hsp + 2 * hoff, vsp + 8 * voff);
3534 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3535 SetList(hsp + 3 * hoff, vsp + 5 * voff);
3536 SetList(hsp + 3 * hoff, vsp + 7 * voff);
3537 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3538 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3539 SetList(hsp + 4 * hoff, vsp + 4 * voff);
3540 SetList(hsp + 4 * hoff, vsp + 5 * voff);
3541 SetList(hsp + 4 * hoff, vsp + 6 * voff);
3542 SetList(hsp + 4 * hoff, vsp + 7 * voff);
3543 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3544 SetList(hsp + 5 * hoff, vsp + 3 * voff);
3545 SetList(hsp + 5 * hoff, vsp + 4 * voff);
3546 SetList(hsp + 5 * hoff, vsp + 5 * voff);
3547 SetList(hsp + 5 * hoff, vsp + 6 * voff);
3548 }
3549 } else if (SS <= 4) {
3550 if (sides) {
3551 SetList(hsp + 0 * hoff, vsp + 6 * voff);
3552 SetList(hsp + 2 * hoff, vsp + 7 * voff);
3553 SetList(hsp + 3 * hoff, vsp + 7 * voff);
3554 SetList(hsp + 4 * hoff, vsp + 7 * voff);
3555 SetList(hsp + 5 * hoff, vsp + 7 * voff);
3556 SetList(hsp + 6 * hoff, vsp + 7 * voff);
3557 SetList(hsp + 7 * hoff, vsp + 6 * voff);
3558 SetList(hsp + 8 * hoff, vsp + 6 * voff);
3559 SetList(hsp + 9 * hoff, vsp + 6 * voff);
3560 SetList(hsp + 11 * hoff, vsp + 5 * voff);
3561 SetList(hsp + 12 * hoff, vsp + 5 * voff);
3562 SetList(hsp + 12 * hoff, vsp + 4 * voff);
3563 SetList(hsp + 14 * hoff, vsp + 4 * voff);
3564 SetList(hsp + 15 * hoff, vsp + 4 * voff);
3565 SetList(hsp + 15 * hoff, vsp + 3 * voff);
3566 SetList(hsp + 16 * hoff, vsp + 3 * voff);
3567 SetList(hsp + 16 * hoff, vsp + 2 * voff);
3568 SetList(hsp + 16 * hoff, vsp + 1 * voff);
3569 } else {
3570 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3571 SetList(hsp + 1 * hoff, vsp + 11 * voff);
3572 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3573 SetList(hsp + 3 * hoff, vsp + 10 * voff);
3574 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3575 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3576 SetList(hsp + 4 * hoff, vsp + 4 * voff);
3577 SetList(hsp + 4 * hoff, vsp + 7 * voff);
3578 SetList(hsp + 4 * hoff, vsp + 9 * voff);
3579 SetList(hsp + 4 * hoff, vsp + 10 * voff);
3580 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3581 SetList(hsp + 5 * hoff, vsp + 3 * voff);
3582 SetList(hsp + 5 * hoff, vsp + 4 * voff);
3583 SetList(hsp + 5 * hoff, vsp + 5 * voff);
3584 SetList(hsp + 5 * hoff, vsp + 6 * voff);
3585 SetList(hsp + 5 * hoff, vsp + 7 * voff);
3586 SetList(hsp + 5 * hoff, vsp + 8 * voff);
3587 SetList(hsp + 5 * hoff, vsp + 9 * voff);
3588 }
3589 } else {
3590 if (sides) {
3591 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3592 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3593 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3594 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3595 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3596 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3597 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3598 SetList(hsp + 4 * hoff, vsp + 3 * voff);
3599 } else {
3600 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3601 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3602 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3603 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3604 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3605 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3606 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3607 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3608 }
3609 }
3610 } else if (lp->patterned_rule == LIFE_12B456S12) {
3611 /* glider (c/6, p12) */
3612 if (sides) {
3613 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3614 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3615 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3616 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3617 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3618 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3619 SetList(hsp + 4 * hoff, vsp + 3 * voff);
3620 SetList(hsp + 5 * hoff, vsp + 0 * voff);
3621 SetList(hsp + 5 * hoff, vsp + 3 * voff);
3622 SetList(hsp + 7 * hoff, vsp + 1 * voff);
3623 SetList(hsp + 7 * hoff, vsp + 2 * voff);
3624 } else {
3625 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3626 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3627 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3628 SetList(hsp + 2 * hoff, vsp + 4 * voff);
3629 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3630 SetList(hsp + 4 * hoff, vsp + 0 * voff);
3631 SetList(hsp + 4 * hoff, vsp + 3 * voff);
3632 SetList(hsp + 5 * hoff, vsp + 0 * voff);
3633 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3634 SetList(hsp + 5 * hoff, vsp + 3 * voff);
3635 SetList(hsp + 6 * hoff, vsp + 2 * voff);
3636 }
3637 } else if (lp->patterned_rule == LIFE_12B45S23 ||
3638 lp->patterned_rule == LIFE_12B456S23) {
3639 /* glider (c/4, p8) flutters */
3640 if (sides) {
3641 SetList(hsp + 0 * hoff, vsp + 0 * voff);
3642 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3643 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3644 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3645 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3646 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3647 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3648 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3649 SetList(hsp + 4 * hoff, vsp + 3 * voff);
3650 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3651 } else {
3652 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3653 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3654 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3655 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3656 SetList(hsp + 5 * hoff, vsp + 0 * voff);
3657 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3658 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3659 SetList(hsp + 5 * hoff, vsp + 3 * voff);
3660 SetList(hsp + 6 * hoff, vsp + 1 * voff);
3661 SetList(hsp + 6 * hoff, vsp + 2 * voff);
3662 }
3663 } else if (lp->patterned_rule == LIFE_12B46S246) {
3664 /* glider (c/10, p10) */
3665 if (sides) {
3666 SetList(hsp + 0 * hoff, vsp + 0 * voff);
3667 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3668 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3669 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3670 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3671 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3672 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3673 } else {
3674 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3675 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3676 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3677 SetList(hsp + 3 * hoff, vsp + 0 * voff);
3678 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3679 SetList(hsp + 4 * hoff, vsp + 0 * voff);
3680 SetList(hsp + 5 * hoff, vsp + 0 * voff);
3681 }
3682 } else if (lp->patterned_rule == LIFE_12B3S27 || pick == 1) {
3683 if (sides) {
3684 SetList(hsp + 0 * hoff, vsp + 0 * voff);
3685 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3686 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3687 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3688 } else {
3689 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3690 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3691 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3692 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3693 }
3694 } else if (lp->patterned_rule == LIFE_12B3S278) {
3695 if (sides) {
3696 SetList(hsp + 0 * hoff, vsp + 0 * voff);
3697 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3698 SetList(hsp + 3 * hoff, vsp + 0 * voff);
3699 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3700 } else {
3701 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3702 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3703 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3704 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3705 }
3706 } else if (lp->patterned_rule == LIFE_12B45S34) {
3707 /* glider (c/7, p7) */
3708 if (sides) {
3709 SetList(hsp + 0 * hoff, vsp + 0 * voff);
3710 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3711 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3712 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3713 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3714 SetList(hsp + 3 * hoff, vsp + 0 * voff);
3715 SetList(hsp + 4 * hoff, vsp + 0 * voff);
3716 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3717 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3718 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3719 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3720 } else {
3721 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3722 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3723 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3724 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3725 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3726 SetList(hsp + 3 * hoff, vsp + 0 * voff);
3727 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3728 SetList(hsp + 4 * hoff, vsp + 0 * voff);
3729 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3730 SetList(hsp + 5 * hoff, vsp + 0 * voff);
3731 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3732 }
3733 } else if (lp->patterned_rule == LIFE_12B456S34) {
3734 /* glider (c/6, p12) */
3735 if (sides) {
3736 SetList(hsp + 0 * hoff, vsp + 0 * voff);
3737 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3738 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3739 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3740 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3741 SetList(hsp + 1 * hoff, vsp + 4 * voff);
3742 SetList(hsp + 2 * hoff, vsp + 5 * voff);
3743 SetList(hsp + 3 * hoff, vsp + 5 * voff);
3744 SetList(hsp + 4 * hoff, vsp + 0 * voff);
3745 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3746 SetList(hsp + 5 * hoff, vsp + 5 * voff);
3747 SetList(hsp + 6 * hoff, vsp + 2 * voff);
3748 SetList(hsp + 6 * hoff, vsp + 5 * voff);
3749 SetList(hsp + 7 * hoff, vsp + 3 * voff);
3750 SetList(hsp + 7 * hoff, vsp + 4 * voff);
3751 } else {
3752 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3753 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3754 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3755 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3756 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3757 SetList(hsp + 4 * hoff, vsp + 0 * voff);
3758 SetList(hsp + 5 * hoff, vsp + 3 * voff);
3759 SetList(hsp + 6 * hoff, vsp + 0 * voff);
3760 SetList(hsp + 6 * hoff, vsp + 3 * voff);
3761 SetList(hsp + 8 * hoff, vsp + 0 * voff);
3762 SetList(hsp + 8 * hoff, vsp + 3 * voff);
3763 SetList(hsp + 9 * hoff, vsp + 0 * voff);
3764 SetList(hsp + 9 * hoff, vsp + 3 * voff);
3765 SetList(hsp + 10 * hoff, vsp + 1 * voff);
3766 SetList(hsp + 10 * hoff, vsp + 2 * voff);
3767 }
3768 } else if (lp->patterned_rule == LIFE_12B4S35) {
3769 /* glider (c/3, p3) flutters */
3770 if (sides) {
3771 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3772 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3773 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3774 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3775 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3776 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3777 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3778 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3779 } else {
3780 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3781 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3782 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3783 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3784 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3785 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3786 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3787 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3788 }
3789 } else if (lp->patterned_rule == LIFE_12B4S356) {
3790 /* glider (c/2, p2) flutters */
3791 if (sides) {
3792 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3793 SetList(hsp + 0 * hoff, vsp + 3 * voff);
3794 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3795 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3796 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3797 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3798 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3799 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3800 } else {
3801 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3802 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3803 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3804 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3805 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3806 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3807 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3808 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3809 }
3810 } else if (lp->patterned_rule == LIFE_12B46S35) {
3811 /* glider (c/3, p3) flutters */
3812 if (sides) {
3813 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3814 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3815 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3816 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3817 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3818 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3819 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3820 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3821 } else {
3822 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3823 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3824 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3825 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3826 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3827 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3828 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3829 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3830 }
3831 } else if (lp->patterned_rule == LIFE_12B46S356) {
3832 /* glider (c/2, p2) flutters */
3833 int SS = NRAND(4);
3834
3835 if (SS < 2) {
3836 if (sides) {
3837 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3838 SetList(hsp + 0 * hoff, vsp + 3 * voff);
3839 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3840 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3841 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3842 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3843 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3844 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3845 } else {
3846 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3847 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3848 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3849 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3850 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3851 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3852 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3853 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3854 }
3855 } else if (SS == 2) {
3856 if (sides) {
3857 SetList(hsp + 0 * hoff, vsp + 3 * voff);
3858 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3859 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3860 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3861 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3862 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3863 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3864 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3865 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3866 SetList(hsp + 4 * hoff, vsp + 3 * voff);
3867 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3868 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3869 } else {
3870 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3871 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3872 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3873 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3874 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3875 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3876 SetList(hsp + 3 * hoff, vsp + 0 * voff);
3877 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3878 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3879 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3880 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3881 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3882 }
3883 } else {
3884 if (sides) {
3885 SetList(hsp + 0 * hoff, vsp + 2 * voff);
3886 SetList(hsp + 0 * hoff, vsp + 3 * voff);
3887 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3888 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3889 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3890 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3891 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3892 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3893 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3894 SetList(hsp + 4 * hoff, vsp + 3 * voff);
3895 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3896 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3897 } else {
3898 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3899 SetList(hsp + 1 * hoff, vsp + 3 * voff);
3900 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3901 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3902 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3903 SetList(hsp + 2 * hoff, vsp + 3 * voff);
3904 SetList(hsp + 3 * hoff, vsp + 0 * voff);
3905 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3906 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3907 SetList(hsp + 3 * hoff, vsp + 3 * voff);
3908 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3909 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3910 }
3911 }
3912 } else if (lp->patterned_rule == LIFE_12B456S45) {
3913 /* glider (c/4, p8) flutters */
3914 if (sides) {
3915 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3916 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3917 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3918 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3919 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3920 SetList(hsp + 5 * hoff, vsp + 0 * voff);
3921 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3922 } else {
3923 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3924 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3925 SetList(hsp + 3 * hoff, vsp + 0 * voff);
3926 SetList(hsp + 4 * hoff, vsp + 1 * voff);
3927 SetList(hsp + 4 * hoff, vsp + 2 * voff);
3928 SetList(hsp + 5 * hoff, vsp + 1 * voff);
3929 SetList(hsp + 5 * hoff, vsp + 2 * voff);
3930 }
3931 } else if (lp->patterned_rule == LIFE_12B4S456) {
3932 /* glider (c/4, p8) flutters */
3933 if (sides) {
3934 /*SetList(hsp + 1 * hoff, vsp + 0 * voff);
3935 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3936 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3937 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3938 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3939 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3940 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3941 SetList(hsp + 3 * hoff, vsp + 2 * voff);*/
3942 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3943 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3944 SetList(hsp + 1 * hoff, vsp + 2 * voff);
3945 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3946 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3947 SetList(hsp + 2 * hoff, vsp + 2 * voff);
3948 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3949 SetList(hsp + 3 * hoff, vsp + 2 * voff);
3950 } else {
3951 SetList(hsp + 0 * hoff, vsp + 0 * voff);
3952 SetList(hsp + 0 * hoff, vsp + 1 * voff);
3953 SetList(hsp + 1 * hoff, vsp + 0 * voff);
3954 SetList(hsp + 1 * hoff, vsp + 1 * voff);
3955 SetList(hsp + 2 * hoff, vsp + 0 * voff);
3956 SetList(hsp + 2 * hoff, vsp + 1 * voff);
3957 SetList(hsp + 3 * hoff, vsp + 0 * voff);
3958 SetList(hsp + 3 * hoff, vsp + 1 * voff);
3959 }
3960 }
3961 } else if (lp->neighbors == 12 &&
3962 (lp->patterned_rule == LIFE_12B3S2 ||
3963 lp->patterned_rule == LIFE_12B46S24)) {
3964 Bool sides = LRAND() & 1; /* beware, sides offset by 1 */
3965
3966 if (sides) { /* lower right */
3967 if (LRAND() & 1) {
3968 hsp = NRAND(lp->nrows / 4);
3969 hsp += (LRAND() & 1) ? 3 * lp->nrows / 4 : 0;
3970 if (LRAND() & 1) {
3971 vsp = 0;
3972 if ((vsp + hsp) & 1)
3973 vsp++;
3974 } else {
3975 vsp = lp->ncols - 1;
3976 if (!((vsp + hsp) & 1))
3977 vsp--;
3978 }
3979 if (hsp > lp->nrows / 2)
3980 hoff = -1;
3981 if (vsp > lp->ncols / 2)
3982 voff = -1;
3983 } else {
3984 vsp = NRAND(lp->ncols / 4);
3985 vsp += (LRAND() & 1) ? 3 * lp->ncols / 4 : 0;
3986 if (LRAND() & 1) {
3987 hsp = 0;
3988 if ((vsp + hsp) & 1)
3989 hsp++;
3990 } else {
3991 hsp = lp->nrows - 1;
3992 if (!((vsp + hsp) & 1))
3993 hsp--;
3994 }
3995 if (hsp > lp->nrows / 2) {
3996 hsp--;
3997 hoff = -1;
3998 }
3999 if (vsp > lp->ncols / 2) {
4000 vsp--;
4001 voff = -1;
4002 }
4003 }
4004 } else { /* down */
4005 hsp = NRAND(lp->nrows / 2) + lp->nrows / 4;
4006 if (LRAND() & 1) {
4007 vsp = 0;
4008 if ((vsp + hsp) & 1)
4009 vsp++;
4010 } else {
4011 vsp = lp->ncols - 1;
4012 if (!((vsp + hsp) & 1))
4013 vsp--;
4014 }
4015 if (hsp > lp->nrows / 2)
4016 hoff = -1;
4017 if (vsp > lp->ncols / 2)
4018 voff = -1;
4019 }
4020 if (lp->patterned_rule == LIFE_12B3S2) {
4021 if (sides) {
4022 SetList(hsp + 0 * hoff, vsp + 6 * voff);
4023 SetList(hsp + 1 * hoff, vsp + 7 * voff);
4024 SetList(hsp + 2 * hoff, vsp + 7 * voff);
4025 SetList(hsp + 3 * hoff, vsp + 7 * voff);
4026 SetList(hsp + 6 * hoff, vsp + 0 * voff);
4027 SetList(hsp + 8 * hoff, vsp + 0 * voff);
4028 SetList(hsp + 8 * hoff, vsp + 1 * voff);
4029 SetList(hsp + 9 * hoff, vsp + 1 * voff);
4030 } else {
4031 SetList(hsp + 0 * hoff, vsp + 1 * voff);
4032 SetList(hsp + 1 * hoff, vsp + 0 * voff);
4033 SetList(hsp + 1 * hoff, vsp + 1 * voff);
4034 SetList(hsp + 1 * hoff, vsp + 2 * voff);
4035 SetList(hsp + 13 * hoff, vsp + 0 * voff);
4036 SetList(hsp + 13 * hoff, vsp + 1 * voff);
4037 SetList(hsp + 13 * hoff, vsp + 2 * voff);
4038 SetList(hsp + 14 * hoff, vsp + 1 * voff);
4039 }
4040 } else if (lp->patterned_rule == LIFE_12B46S24) {
4041 /* glider (c/4, p8) */
4042 if (sides) {
4043 SetList(hsp + 0 * hoff, vsp + 1 * voff);
4044 SetList(hsp + 0 * hoff, vsp + 2 * voff);
4045 SetList(hsp + 1 * hoff, vsp + 0 * voff);
4046 SetList(hsp + 1 * hoff, vsp + 1 * voff);
4047 SetList(hsp + 1 * hoff, vsp + 2 * voff);
4048 SetList(hsp + 2 * hoff, vsp + 1 * voff);
4049 } else {
4050 SetList(hsp + 0 * hoff, vsp + 1 * voff);
4051 SetList(hsp + 1 * hoff, vsp + 1 * voff);
4052 SetList(hsp + 2 * hoff, vsp + 0 * voff);
4053 SetList(hsp + 2 * hoff, vsp + 1 * voff);
4054 SetList(hsp + 3 * hoff, vsp + 1 * voff);
4055 SetList(hsp + 4 * hoff, vsp + 0 * voff);
4056 }
4057 }
4058 }
4059 }
4060
4061 static int
randomSymmetry(lifestruct * lp,Bool gliderSearch)4062 randomSymmetry(lifestruct *lp, Bool gliderSearch) {
4063 if (lp->polygon == 4) {
4064 if (gliderSearch) {
4065 int symmetry = NRAND(4);
4066 if (symmetry == 3)
4067 symmetry = 6;
4068 return symmetry;
4069 } else {
4070 return NRAND(10);
4071 }
4072 } else if (lp->polygon == 3 || lp->polygon == 6) {
4073 if (gliderSearch) {
4074 return NRAND(3);
4075 } else {
4076 return NRAND(10);
4077 }
4078 } else {
4079 if (gliderSearch) {
4080 return NRAND(3);
4081 } else {
4082 return NRAND(7);
4083 }
4084 }
4085 }
4086
4087 static Bool
init_stuff(ModeInfo * mi)4088 init_stuff(ModeInfo * mi)
4089 {
4090 lifestruct *lp = &lifes[MI_SCREEN(mi)];
4091 #ifndef STANDALONE
4092 Display *display = MI_DISPLAY(mi);
4093
4094 /* this used to work there I think */
4095 if (lp->logo == NULL) {
4096 getImage(mi, &lp->logo, CELL_WIDTH, CELL_HEIGHT, CELL_BITS,
4097 #ifdef HAVE_XPM
4098 DEFAULT_XPM, CELL_NAME,
4099 #endif
4100 &lp->graphics_format, &lp->cmap, &lp->black);
4101 if (lp->logo == NULL) {
4102 free_life_screen(display, lp);
4103 return False;
4104 }
4105 #ifdef XBM_GRELB
4106 if (lp->cmap == None && lp->graphics_format == IS_XBM) {
4107 /* probably do not need the first but I am cautious... */
4108 if (!bimage.data) { /* Only need to do this once */
4109 bimage.data = (char *) CELL2_BITS;
4110 bimage.width = CELL2_WIDTH;
4111 bimage.height = CELL2_HEIGHT;
4112 bimage.bytes_per_line = (CELL2_WIDTH + 7) / 8;
4113 }
4114 lp->logo2 = &bimage;
4115 }
4116 #endif
4117 }
4118 if (lp->cmap != None) {
4119 Window window = MI_WINDOW(mi);
4120
4121 setColormap(display, window, lp->cmap, MI_IS_INWINDOW(mi));
4122 if (lp->backGC == None) {
4123 XGCValues xgcv;
4124
4125 xgcv.background = lp->black;
4126 xgcv.foreground = lp->black;
4127 if ((lp->backGC = XCreateGC(display, window,
4128 GCForeground | GCBackground,
4129 &xgcv)) == None) {
4130 free_life_screen(display, lp);
4131 return False;
4132 }
4133 }
4134 } else
4135 #endif /* STANDALONE */
4136 {
4137 lp->black = MI_BLACK_PIXEL(mi);
4138 lp->backGC = MI_GC(mi);
4139 }
4140 return True;
4141 }
4142
4143 ENTRYPOINT void
init_life(ModeInfo * mi)4144 init_life(ModeInfo * mi)
4145 {
4146 Display *display = MI_DISPLAY(mi);
4147 int size = MI_SIZE(mi), npats, i;
4148 lifestruct *lp;
4149
4150 MI_INIT(mi, lifes);
4151 lp = &lifes[MI_SCREEN(mi)];
4152
4153 lp->generation = 0;
4154 lp->redrawing = 0;
4155 lp->foundBirth = lp->foundSurvival = 0;
4156 if (MI_IS_FULLRANDOM(mi)) {
4157 int r5n1 = patterns_5rules[0];
4158 int r6n1 = patterns_6rules[0] + patterns_6rules[1];
4159 int r6n2 = r6n1 + patterns_6rules[2];
4160 int r6n3 = r6n2 + patterns_6rules[3];
4161 int r7n1 = patterns_7rules[0];
4162 int r8n1 = patterns_8rules[0] + patterns_8rules[1];
4163 int r8n2 = r8n1 + patterns_8rules[2];
4164 int r8n3 = r8n2 + patterns_8rules[3];
4165 int r8n4 = r8n3 + patterns_8rules[4];
4166 int r9n1 = patterns_9rules[0];
4167 int r12n1 = patterns_12rules[0] + patterns_12rules[1];
4168 int r12n2 = r12n1 + patterns_12rules[2];
4169 int r12n12 = r12n2 + patterns_12rules[3] + patterns_12rules[4] +
4170 patterns_12rules[5] + patterns_12rules[6] +
4171 patterns_12rules[7] + patterns_12rules[8] +
4172 patterns_12rules[9] + patterns_12rules[10] +
4173 patterns_12rules[11] + patterns_12rules[12];
4174 #if 1
4175 lp->neighbors = (NRAND(r8n4 + r6n3 + r9n1 + r12n12 + r5n1 + r7n1) < r8n4 + r6n3)
4176 ? ((NRAND(r8n4 + r6n3) < r8n4) ? 8 : 6)
4177 : (NRAND(r9n1 + r12n12 + r5n1 + r7n1) < r5n1 + r7n1)
4178 ? ((NRAND(r5n1 + r7n1) < r5n1) ? 5 : 7)
4179 : ((NRAND(r9n1 + r12n12) < r9n1) ? 9 : 12);
4180 #else
4181 lp->neighbors = 8;
4182 #endif
4183 if (lp->neighbors == 6) {
4184 lp->polygon = 6;
4185 } else if (lp->neighbors % 3 == 0) { /* TRI */
4186 lp->polygon = 3;
4187 } else if (lp->neighbors == 5 || lp->neighbors == 7) {
4188 lp->polygon = 5;
4189 } else /* if (lp->neighbors == 4 || lp->neighbors == 8) */ {
4190 lp->polygon = 4;
4191 }
4192 if (lp->polygon == 3 || lp->polygon == 6) {
4193 lp->vertical = LRAND() & 1;
4194 }
4195 #if 1
4196 lp->allGliders = True;
4197 #else
4198 if (lp->neighbors == 8) {
4199 int n = NRAND(r8n4);
4200
4201 lp->nontot = (n < patterns_8rules[0]);
4202 lp->conway = (n >= patterns_8rules[0] && n < r8n1);
4203 lp->highlife = (n >= patterns_8rules[1] && n < r8n2);
4204 lp->daynight = (n >= r8n2);
4205 } else {
4206 lp->nontot = lp->conway = lp->highlife = lp->daynight = False;
4207 }
4208 if (lp->neighbors == 6) {
4209 int n = NRAND(r6n2);
4210
4211 lp->callahan = (n < patterns_6rules[0]);
4212 lp->andreen = (n >= patterns_6rules[0] && n < r6n1);
4213 lp->bays = (n >= r6n1 );
4214 } else {
4215 lp->andreen = lp->callahan = lp->bays = False;
4216 }
4217 if (lp->neighbors == 5) {
4218 /*r5n1 = patterns_5rules[0];*/
4219 lp->pent = True;
4220 } else {
4221 lp->pent = False;
4222 }
4223 if (lp->neighbors == 7) {
4224 /*r7n1 = patterns_7rules[0];*/
4225 lp->pent2 = True;
4226 } else {
4227 lp->pent2 = False;
4228 }
4229 if (lp->neighbors == 12) {
4230 int n = NRAND(r12n2);
4231
4232 lp->trilife = (n < patterns_12rules[0]);
4233 lp->trilife1 = (n >= patterns_12rules[0] && n < r12n1);
4234 lp->trilife2 = (n >= r12n1);
4235 } else {
4236 lp->trilife = lp->trilife1 = lp->trilife2 = False;
4237 }
4238 #endif
4239 } else {
4240 lp->nontot = nontot;
4241 lp->conway = conway;
4242 lp->highlife = highlife;
4243 lp->daynight = daynight;
4244 lp->callahan = callahan;
4245 lp->andreen = andreen;
4246 lp->bays = bays;
4247 lp->trilife = trilife;
4248 lp->trilife1 = trilife1;
4249 lp->trilife2 = trilife2;
4250 lp->pent = pent;
4251 lp->pent2 = pent2;
4252 lp->vertical = vertical;
4253 }
4254 parseRule(mi, lp->ruleString);
4255 lp->labelOffsetX = NRAND(8);
4256 lp->labelOffsetY = NRAND(8);
4257 #ifndef STANDALONE
4258 parseFile(mi);
4259 #endif
4260 if (lp->allPatterns) {
4261 switch (lp->neighbors) {
4262 case 5:
4263 lp->patterned_rule = NRAND(LIFE_5RULES);
4264 break;
4265 case 6:
4266 lp->patterned_rule = NRAND(LIFE_6RULES);
4267 break;
4268 case 7:
4269 lp->patterned_rule = NRAND(LIFE_7RULES);
4270 break;
4271 case 8:
4272 lp->patterned_rule = NRAND(LIFE_8RULES);
4273 break;
4274 case 9:
4275 lp->patterned_rule = NRAND(LIFE_9RULES);
4276 break;
4277 case 12:
4278 lp->patterned_rule = NRAND(LIFE_12RULES);
4279 break;
4280 }
4281 copyFromPatternedRule(lp->neighbors, &lp->param, lp->patterned_rule);
4282 printRule(lp->neighbors, lp->ruleString, lp->param,
4283 MI_IS_VERBOSE(mi));
4284 } else if (lp->allGliders) {
4285 switch (lp->neighbors) {
4286 case 5:
4287 lp->patterned_rule = NRAND(LIFE_5GLIDERS);
4288 break;
4289 case 6:
4290 lp->patterned_rule = NRAND(LIFE_6GLIDERS);
4291 break;
4292 case 7:
4293 lp->patterned_rule = NRAND(LIFE_7GLIDERS);
4294 break;
4295 case 8:
4296 lp->patterned_rule = NRAND(LIFE_8GLIDERS);
4297 break;
4298 case 9:
4299 lp->patterned_rule = NRAND(LIFE_9GLIDERS);
4300 break;
4301 case 12:
4302 lp->patterned_rule = NRAND(LIFE_12GLIDERS);
4303 break;
4304 }
4305 copyFromPatternedRule(lp->neighbors, &lp->param, lp->patterned_rule);
4306 printRule(lp->neighbors, lp->ruleString, lp->param,
4307 MI_IS_VERBOSE(mi));
4308 } else {
4309 lp->param.birth = lp->input_param.birth;
4310 lp->param.survival = lp->input_param.survival;
4311 for (i = 0; i < maxgroups[invplot(lp->neighbors)]; i++) {
4312 lp->param.birthGroup[i] = lp->input_param.birthGroup[i];
4313 lp->param.survivalGroup[i] = lp->input_param.survivalGroup[i];
4314 }
4315 lp->patterned_rule = codeToPatternedRule(lp->neighbors, lp->param);
4316 printRule(lp->neighbors, lp->ruleString, lp->param,
4317 MI_IS_VERBOSE(mi));
4318 }
4319 lp->width = MI_WIDTH(mi);
4320 lp->height = MI_HEIGHT(mi);
4321
4322 if (lp->first[0]) {
4323 for (i = 0; i < STATES; i++)
4324 flushList(lp, i);
4325 } else {
4326 for (i = 0; i < STATES; i++)
4327 if (!initList(lp, i)) {
4328 free_life_screen(display, lp);
4329 return;
4330 }
4331 }
4332 free_cells(lp);
4333 free_stuff(display, lp);
4334
4335 if (lp->polygon == 3) {
4336 int orient, side;
4337 #ifdef WIN32
4338 int offset = 4;
4339 #else
4340 int offset = 2;
4341 #endif
4342
4343 if (!lp->vertical) {
4344 lp->height = MI_WIDTH(mi);
4345 lp->width = MI_HEIGHT(mi);
4346 }
4347 lp->black = MI_BLACK_PIXEL(mi);
4348 lp->backGC = MI_GC(mi);
4349 if (lp->width < 2)
4350 lp->width = 2;
4351 if (lp->height < 2)
4352 lp->height = 2;
4353 if (size < -MINSIZE) {
4354 lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) /
4355 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
4356 /* do again to trend smaller */
4357 lp->ys = NRAND(MIN(lp->ys, MAX(MINSIZE, MIN(lp->width, lp->height) /
4358 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
4359 } else if (size < MINSIZE) {
4360 if (!size) {
4361 int min = MIN(lp->width, lp->height) / (4 * MINGRIDSIZE);
4362 int max = MIN(lp->width, lp->height) / (MINGRIDSIZE);
4363
4364 lp->ys = MAX(MINSIZE, min + NRAND(max - min + 1));
4365 max = min + NRAND(lp->ys - min + 1);
4366 /* do again to trend smaller */
4367 lp->ys = MAX(MINSIZE, max);
4368 } else
4369 lp->ys = MINSIZE;
4370 } else
4371 lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) /
4372 MINGRIDSIZE));
4373 lp->xs = (int) (1.52 * lp->ys);
4374 lp->ncols = (MAX(lp->width / lp->xs - 1, 2) / 2) * 2;
4375 lp->nrows = (MAX(lp->height / lp->ys - 1, 2) / 2) * 2;
4376 lp->xb = (lp->width - lp->xs * lp->ncols) / 2 + lp->xs / 2;
4377 lp->yb = (lp->height - lp->ys * lp->nrows) / 2 + lp->ys / 2;
4378
4379 for (orient = 0; orient < 2; orient++) {
4380 for (side = 0; side < 3; side++) {
4381 if (lp->vertical) {
4382 lp->shape.triangle[orient][side].x =
4383 (lp->xs - offset) * triangleUnit[orient][side].x;
4384 lp->shape.triangle[orient][side].y =
4385 (lp->ys - offset) * triangleUnit[orient][side].y;
4386 } else {
4387 lp->shape.triangle[orient][side].y =
4388 (lp->xs - offset) * triangleUnit[orient][side].x;
4389 lp->shape.triangle[orient][side].x =
4390 (lp->ys - offset) * triangleUnit[orient][side].y;
4391 }
4392 }
4393 }
4394 } else if (lp->polygon == 4) {
4395 if (!init_stuff(mi))
4396 return;
4397 if (lp->width < 2)
4398 lp->width = 2;
4399 if (lp->height < 2)
4400 lp->height = 2;
4401 #if 0
4402 if (size == 0 && !MI_IS_ICONIC(mi)) {
4403 lp->pixelmode = False;
4404 lp->xs = lp->logo->width;
4405 lp->ys = lp->logo->height;
4406 }
4407 #else
4408 #ifdef STANDALONE
4409 if (size == 0)
4410 #else
4411 if (size == 0 ||
4412 MINGRIDSIZE * size > lp->width || MINGRIDSIZE * size > lp->height) {
4413 if (lp->width > MINGRIDSIZE * lp->logo->width &&
4414 lp->height > MINGRIDSIZE * lp->logo->height) {
4415 lp->pixelmode = False;
4416 lp->xs = lp->logo->width;
4417 lp->ys = lp->logo->height;
4418 } else
4419 #endif
4420 {
4421 int min = MIN(lp->width, lp->height) / (8 * MINGRIDSIZE);
4422 int max = MIN(lp->width, lp->height) / (2 * MINGRIDSIZE);
4423
4424 lp->ys = MAX(MINSIZE, min + NRAND(max - min + 1));
4425 /* do again to trend smaller */
4426 max = min + NRAND(lp->ys - min + 1);
4427 lp->xs = lp->ys = MAX(MINSIZE, max);
4428 lp->pixelmode = True;
4429 }
4430 #ifndef STANDALONE
4431 }
4432 #endif
4433 else
4434 #endif
4435 {
4436 lp->pixelmode = True;
4437 if (size < -MINSIZE) {
4438 lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) /
4439 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
4440 /* do again to trend smaller */
4441 lp->ys = NRAND(MIN(lp->ys, MAX(MINSIZE, MIN(lp->width, lp->height) /
4442 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
4443 } else if (size < MINSIZE)
4444 lp->ys = MINSIZE;
4445 else
4446 lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) /
4447 MINGRIDSIZE));
4448 lp->xs = lp->ys;
4449 }
4450 lp->ncols = MAX(lp->width / lp->xs, 4);
4451 lp->nrows = MAX(lp->height / lp->ys, 4);
4452 lp->xb = (lp->width - lp->xs * lp->ncols) / 2;
4453 lp->yb = (lp->height - lp->ys * lp->nrows) / 2;
4454 } else if (lp->polygon == 5) {
4455 int orient, side;
4456 lp->black = MI_BLACK_PIXEL(mi);
4457 lp->backGC = MI_GC(mi);
4458 if (lp->width < 2)
4459 lp->width = 2;
4460 if (lp->height < 2)
4461 lp->height = 2;
4462 if (size < -MINSIZE) {
4463 lp->xs = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) /
4464 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
4465 /* do again to trend smaller */
4466 lp->xs = NRAND(MIN(lp->xs, MAX(MINSIZE, MIN(lp->width, lp->height) /
4467 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
4468 } else if (size < MINSIZE) {
4469 if (!size) {
4470 int min = MIN(lp->width, lp->height) / (4 * MINGRIDSIZE);
4471 int max = MIN(lp->width, lp->height) / (MINGRIDSIZE);
4472
4473 lp->xs = MAX(MINSIZE, min + NRAND(max - min + 1));
4474 /* do again to trend smaller */
4475 max = min + NRAND(lp->xs - min + 1);
4476 lp->xs = MAX(MINSIZE, max);
4477 } else
4478 lp->xs = MINSIZE;
4479 } else
4480 lp->xs = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) /
4481 MINGRIDSIZE));
4482 lp->ys = lp->xs * 2;
4483 lp->ncols = (MAX((lp->width - 4) / lp->xs, 8) / 4) * 4;
4484 lp->nrows = (MAX((lp->height - lp->ys / 2) / lp->ys, 8)) / 2 * 2;
4485 lp->xb = (lp->width - lp->xs * lp->ncols) / 2;
4486 lp->yb = (lp->height - lp->ys * lp->nrows) / 2 - 2;
4487 for (orient = 0; orient < 4; orient++) {
4488 for (side = 0; side < 5; side++) {
4489 lp->shape.pentagon[orient][side].x =
4490 2 * (lp->xs - 2) * pentagonUnit[orient][side].x / 4;
4491 lp->shape.pentagon[orient][side].y =
4492 (lp->ys - 2) * pentagonUnit[orient][side].y / 4;
4493 }
4494 }
4495 } else if (lp->polygon == 6) {
4496 int nccols, ncrows, side;
4497
4498 if (!lp->vertical) {
4499 lp->height = MI_WIDTH(mi);
4500 lp->width = MI_HEIGHT(mi);
4501 }
4502 lp->black = MI_BLACK_PIXEL(mi);
4503 lp->backGC = MI_GC(mi);
4504 if (lp->width < 2)
4505 lp->width = 2;
4506 if (lp->height < 4)
4507 lp->height = 4;
4508 if (size < -MINSIZE) {
4509 lp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(lp->width, lp->height) /
4510 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
4511 /* do again to trend smaller */
4512 lp->ys = NRAND(MIN(lp->ys, MAX(MINSIZE, MIN(lp->width, lp->height) /
4513 MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
4514 } else if (size < MINSIZE) {
4515 if (!size) {
4516 int min = MIN(lp->width, lp->height) / (4 * MINGRIDSIZE);
4517 int max = MIN(lp->width, lp->height) / (2 * MINGRIDSIZE);
4518
4519 lp->ys = MAX(MINSIZE, min + NRAND(max - min + 1));
4520 /* do again to trend smaller */
4521 max = min + NRAND(lp->ys - min + 1);
4522 lp->ys = MAX(MINSIZE, max);
4523 } else
4524 lp->ys = MINSIZE;
4525 } else
4526 lp->ys = MIN(size, MAX(MINSIZE, MIN(lp->width, lp->height) /
4527 MINGRIDSIZE));
4528 lp->xs = lp->ys;
4529 nccols = MAX(lp->width / lp->xs - 2, 2);
4530 ncrows = MAX(lp->height / lp->ys - 1, 2);
4531 lp->ncols = nccols / 2;
4532 lp->nrows = 2 * (ncrows / 4);
4533 if (lp->ncols % 4 < 2 && lp->nrows % 4 != 0)
4534 lp->nrows -= 2;
4535 else if (lp->ncols % 4 >= 2 && lp->nrows % 4 == 0)
4536 lp->nrows -= 2;
4537 lp->xb = (lp->width - lp->xs * nccols) / 2 + lp->xs / 2;
4538 lp->yb = (lp->height - lp->ys * (ncrows / 2) * 2) / 2 +
4539 lp->ys - 2;
4540 for (side = 0; side < 6; side++) {
4541 if (lp->vertical) {
4542 lp->shape.hexagon[side].x =
4543 (lp->xs - 1) * hexagonUnit[side].x;
4544 lp->shape.hexagon[side].y =
4545 ((lp->ys - 1) * hexagonUnit[side].y /
4546 2) * 4 / 3;
4547 } else {
4548 lp->shape.hexagon[side].y =
4549 (lp->xs - 1) * hexagonUnit[side].x;
4550 lp->shape.hexagon[side].x =
4551 ((lp->ys - 1) * hexagonUnit[side].y /
4552 2) * 4 / 3;
4553 }
4554 }
4555 }
4556 lp->npositions = lp->nrows * lp->ncols;
4557
4558 MI_CLEARWINDOWCOLORMAP(mi, lp->backGC, lp->black);
4559 lp->painted = False;
4560 if ((lp->arr = (CellList **) calloc(lp->npositions,
4561 sizeof (CellList *))) == NULL) {
4562 free_life_screen(display, lp);
4563 return;
4564 }
4565
4566 lp->patterned_rule = codeToPatternedRule(lp->neighbors, lp->param);
4567 npats = 0;
4568 switch (lp->neighbors) {
4569 case 5:
4570 if ((unsigned) lp->patterned_rule < LIFE_5RULES)
4571 npats = patterns_5rules[lp->patterned_rule];
4572 break;
4573 case 6:
4574 if ((unsigned) lp->patterned_rule < LIFE_6RULES)
4575 npats = patterns_6rules[lp->patterned_rule];
4576 break;
4577 case 7:
4578 if ((unsigned) lp->patterned_rule < LIFE_7RULES)
4579 npats = patterns_7rules[lp->patterned_rule];
4580 break;
4581 case 8:
4582 if ((unsigned) lp->patterned_rule < LIFE_8RULES)
4583 npats = patterns_8rules[lp->patterned_rule];
4584 break;
4585 case 9:
4586 if ((unsigned) lp->patterned_rule < LIFE_9RULES)
4587 npats = patterns_9rules[lp->patterned_rule];
4588 break;
4589 case 12:
4590 if ((unsigned) lp->patterned_rule < LIFE_12RULES)
4591 npats = patterns_12rules[lp->patterned_rule];
4592 break;
4593 }
4594 if (glidersearch || patternsearch) {
4595 /* trying to find new patterns */
4596 RandomSoup(mi, randomSymmetry(lp, glidersearch), SOUPPERCENT,
4597 SOUPSIZE(lp->ncols), SOUPSIZE(lp->nrows));
4598 } else {
4599 if (!filePattern)
4600 lp->pattern = NRAND(npats + 3);
4601 if (lp->pattern >= npats && !filePattern)
4602 RandomSoup(mi, randomSymmetry(lp, False), SOUPPERCENT,
4603 SOUPSIZE(lp->ncols), SOUPSIZE(lp->nrows));
4604 else
4605 GetPattern(mi, lp->patterned_rule, lp->pattern);
4606 }
4607 }
4608
4609 ENTRYPOINT void
draw_life(ModeInfo * mi)4610 draw_life(ModeInfo * mi)
4611 {
4612 Display *display = MI_DISPLAY(mi);
4613 Window window = MI_WINDOW(mi);
4614 GC gc = MI_GC(mi);
4615 CellList *middle[STATES]; /* To distinguish between old and new stuff */
4616 CellList *curr;
4617 cellstruct info;
4618 int i, count, gcount, neighborKind;
4619 Bool visible = False;
4620 lifestruct *lp;
4621
4622 if (lifes == NULL)
4623 return;
4624 lp = &lifes[MI_SCREEN(mi)];
4625
4626 /*-
4627 * LIVE list are the on cells
4628 * DEAD list are the cells that may go on in the next iteration.
4629 * Init plan:
4630 Create live list and dead list which border all live cells
4631 (no good for rules like B0/S0 :) )
4632 * Big loop plan:
4633 Setup toggles, toggle state next iteration?
4634 Remove all from dead list except toggled and remove all from live list
4635 that are dead (but in this case draw background square)
4636 Toggle toggled states, age existing ones, create a new dead list, draw
4637 */
4638
4639 /* Go through dead list to see if anything spawns (generate new lists),
4640 then delete the used dead list */
4641
4642 MI_IS_DRAWN(mi) = True;
4643
4644 /* Setup toggles */
4645 curr = lp->first[DEAD]->next;
4646 while (curr != lp->last[DEAD]) {
4647 count = ng_neighbors(lp, curr, &gcount);
4648 if ((lp->param.birth & (1 << count)) || (count >= FIRSTGROUP &&
4649 count < FIRSTGROUP + maxgroups[invplot(lp->neighbors)] &&
4650 ((lp->neighbors == 6 &&
4651 (lp->param.birthGroup[count - FIRSTGROUP] &
4652 (1 << nontotToIndex(nontotalistic6[gcount]))) != 0) ||
4653 (lp->neighbors == 8 &&
4654 (lp->param.birthGroup[count - FIRSTGROUP] &
4655 (1 << nontotToIndex(nontotalistic8[gcount]))) != 0)))) {
4656 setcelltoggles(mi, (int) (curr->info.position % lp->ncols),
4657 (int) (curr->info.position / lp->ncols));
4658 visible = True;
4659 }
4660 curr = curr->next;
4661 }
4662 curr = lp->first[LIVE]->next;
4663 neighborKind = invplot(lp->neighbors);
4664 while (curr != lp->last[LIVE]) {
4665 count = ng_neighbors(lp, curr, &gcount);
4666 if (!((lp->param.survival & (1 << count)) || (count >= FIRSTGROUP &&
4667 count < FIRSTGROUP + maxgroups[neighborKind] &&
4668 ((lp->neighbors == 6 &&
4669 (lp->param.survivalGroup[count - FIRSTGROUP] &
4670 (1 << nontotToIndex(nontotalistic6[gcount]))) != 0) ||
4671 (lp->neighbors == 8 &&
4672 (lp->param.survivalGroup[count - FIRSTGROUP] &
4673 (1 << nontotToIndex(nontotalistic8[gcount]))) != 0))))) {
4674 setcelltoggles(mi, (int) (curr->info.position % lp->ncols),
4675 (int) (curr->info.position / lp->ncols));
4676 visible = True;
4677 }
4678 curr = curr->next;
4679 }
4680
4681 /* Bring out your dead! */
4682 curr = lp->first[DEAD]->next;
4683 while (curr != lp->last[DEAD]) {
4684 curr = curr->next;
4685 if (!curr->previous->info.toggle)
4686 removeFromList(lp, DEAD, curr->previous);
4687 }
4688 curr = lp->first[LIVE]->next;
4689 while (curr != lp->last[LIVE]) {
4690 if (curr->info.toggle) {
4691 curr->info.state = DEAD;
4692 drawCell(mi, curr->info);
4693 curr = curr->next;
4694 removeFromList(lp, LIVE, curr->previous);
4695 } else
4696 curr = curr->next;
4697 }
4698
4699 /* Fence off the babies */
4700 info.position = -1; /* dummy value */
4701 info.age = 0; /* dummy value */
4702 info.state = 0; /* dummy value */
4703 info.toggle = 0; /* dummy value */
4704 if (!addToList(lp, DEAD, info)) {
4705 free_life_screen(MI_DISPLAY(mi), lp);
4706 return;
4707 }
4708 if (!addToList(lp, LIVE, info)) {
4709 free_life_screen(MI_DISPLAY(mi), lp);
4710 return;
4711 }
4712 middle[DEAD] = lp->last[DEAD]->previous;
4713 middle[LIVE] = lp->last[LIVE]->previous;
4714
4715 /* Toggle toggled states, age existing ones, create a new dead list */
4716 while (lp->first[DEAD]->next != middle[DEAD]) {
4717 curr = lp->first[DEAD]->next;
4718 if (!setcellfromtoggle(mi, (int) (curr->info.position % lp->ncols),
4719 (int) (curr->info.position / lp->ncols)))
4720 return;
4721 }
4722 curr = lp->first[LIVE]->next;
4723 while (curr != middle[LIVE]) {
4724 if (!setcellfromtoggle(mi, (int) (curr->info.position % lp->ncols),
4725 (int) (curr->info.position / lp->ncols)))
4726 return;
4727 curr = curr->next;
4728 }
4729 removeFromList(lp, DEAD, middle[DEAD]);
4730 removeFromList(lp, LIVE, middle[LIVE]);
4731
4732 if (draw && lp->redrawing) {
4733 for (i = 0; i < REDRAWSTEP; i++) {
4734 CellList *redraw_curr = lp->arr[lp->redrawpos];
4735
4736 /* TODO: More efficient to use list rather than array. */
4737 if (redraw_curr && redraw_curr->info.state == LIVE) {
4738 drawCell(mi, redraw_curr->info);
4739 }
4740 if (++(lp->redrawpos) >= lp->npositions) {
4741 lp->redrawing = 0;
4742 break;
4743 }
4744 }
4745 }
4746 if (visible)
4747 lp->noChangeCount = 0;
4748 else
4749 lp->noChangeCount++;
4750 if (lp->noChangeCount >= 8)
4751 init_life(mi);
4752 else if (++lp->generation > MI_CYCLES(mi)) {
4753 if (patternsearch || glidersearch)
4754 printList(lp, 1);
4755 init_life(mi);
4756 } else {
4757 if (MI_IS_VERBOSE(mi))
4758 (void) fprintf(stdout, "%s (%d cells)\n",
4759 lp->nameString, lp->ncells[LIVE]);
4760 if (patternsearch || glidersearch) {
4761 if (lp->generation == MI_CYCLES(mi) - repeat + 1)
4762 printList(lp, 0);
4763 }
4764 lp->painted = True;
4765 }
4766 /*
4767 * generate a randomized shooter aimed roughly toward the center of the
4768 * screen after batchcount.
4769 */
4770
4771 if (MI_COUNT(mi)) {
4772 if (lp->generation && lp->generation %
4773 ((MI_COUNT(mi) < 0) ? 1 : MI_COUNT(mi)) == 0)
4774 shooter(mi);
4775 }
4776 if (draw && label) {
4777 int size = MAX(MIN(MI_WIDTH(mi), MI_HEIGHT(mi)) - 1, 1);
4778
4779 if (size >= 10 * FONT_WIDTH) {
4780 char ruleString[120];
4781
4782 /* hard code these to corners */
4783 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
4784 (void) sprintf(ruleString, "N%d:%s",
4785 lp->neighbors, lp->ruleString);
4786 XDrawString(display, window, gc,
4787 16 + lp->labelOffsetX,
4788 16 + lp->labelOffsetY + FONT_HEIGHT,
4789 ruleString, strlen(ruleString));
4790 XDrawString(display, window, gc,
4791 16 + lp->labelOffsetX, MI_HEIGHT(mi) - 16 -
4792 lp->labelOffsetY - FONT_HEIGHT / 2,
4793 lp->nameString, strlen(lp->nameString));
4794 }
4795 }
4796 }
4797
4798 ENTRYPOINT void
release_life(ModeInfo * mi)4799 release_life(ModeInfo * mi)
4800 {
4801 if (lifes != NULL) {
4802 int screen;
4803
4804 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
4805 free_life_screen(MI_DISPLAY(mi), &lifes[screen]);
4806 free(lifes);
4807 lifes = (lifestruct *) NULL;
4808 }
4809 }
4810
4811 #ifndef STANDALONE
4812 ENTRYPOINT void
refresh_life(ModeInfo * mi)4813 refresh_life(ModeInfo * mi)
4814 {
4815 lifestruct *lp;
4816
4817 if (lifes == NULL)
4818 return;
4819 lp = &lifes[MI_SCREEN(mi)];
4820
4821 #ifdef HAVE_XPM
4822 if (lp->graphics_format >= IS_XPM) {
4823 /* This is needed when another program changes the colormap. */
4824 free_life_screen(MI_DISPLAY(mi), lp);
4825 init_life(mi);
4826 return;
4827 }
4828 #endif
4829 if (lp->painted) {
4830 MI_CLEARWINDOWCOLORMAP(mi, lp->backGC, lp->black);
4831 lp->redrawing = 1;
4832 lp->redrawpos = 0;
4833 lp->painted = False;
4834 }
4835 }
4836
4837 void
change_life(ModeInfo * mi)4838 change_life(ModeInfo * mi)
4839 {
4840 int npats, i;
4841 lifestruct *lp;
4842
4843 if (lifes == NULL)
4844 return;
4845 lp = &lifes[MI_SCREEN(mi)];
4846
4847 lp->generation = 0;
4848 if (lp->first[0]) {
4849 for (i = 0; i < STATES; i++)
4850 flushList(lp, i);
4851 } else {
4852 for (i = 0; i < STATES; i++)
4853 if (!initList(lp, i)) {
4854 free_life_screen(MI_DISPLAY(mi), lp);
4855 return;
4856 }
4857 }
4858 free_cells(lp);
4859 if ((lp->arr = (CellList **) calloc(lp->npositions,
4860 sizeof (CellList *))) == NULL) {
4861 free_life_screen(MI_DISPLAY(mi), lp);
4862 return;
4863 }
4864
4865 MI_CLEARWINDOWCOLORMAP(mi, lp->backGC, lp->black);
4866
4867 if (!filePattern)
4868 lp->pattern++;
4869 lp->patterned_rule = codeToPatternedRule(lp->neighbors, lp->param);
4870 npats = 0;
4871 switch (lp->neighbors) {
4872 case 5:
4873 if ((unsigned) lp->patterned_rule < LIFE_5RULES)
4874 npats = patterns_5rules[lp->patterned_rule];
4875 break;
4876 case 6:
4877 if ((unsigned) lp->patterned_rule < LIFE_6RULES)
4878 npats = patterns_6rules[lp->patterned_rule];
4879 break;
4880 case 7:
4881 if ((unsigned) lp->patterned_rule < LIFE_7RULES)
4882 npats = patterns_7rules[lp->patterned_rule];
4883 break;
4884 case 8:
4885 if ((unsigned) lp->patterned_rule < LIFE_8RULES)
4886 npats = patterns_8rules[lp->patterned_rule];
4887 break;
4888 case 9:
4889 if ((unsigned) lp->patterned_rule < LIFE_9RULES)
4890 npats = patterns_9rules[lp->patterned_rule];
4891 break;
4892 case 12:
4893 if ((unsigned) lp->patterned_rule < LIFE_12RULES)
4894 npats = patterns_12rules[lp->patterned_rule];
4895 break;
4896 }
4897 if (lp->pattern >= npats + 2) {
4898 lp->pattern = 0;
4899 if (lp->allPatterns) {
4900 lp->patterned_rule++;
4901 switch (lp->neighbors) {
4902 case 5:
4903 if ((unsigned) lp->patterned_rule >= LIFE_5RULES)
4904 lp->patterned_rule = 0;
4905 break;
4906 case 6:
4907 if ((unsigned) lp->patterned_rule >= LIFE_6RULES)
4908 lp->patterned_rule = 0;
4909 break;
4910 case 7:
4911 if ((unsigned) lp->patterned_rule >= LIFE_7RULES)
4912 lp->patterned_rule = 0;
4913 break;
4914 case 8:
4915 if ((unsigned) lp->patterned_rule >= LIFE_8RULES)
4916 lp->patterned_rule = 0;
4917 break;
4918 case 9:
4919 if ((unsigned) lp->patterned_rule >= LIFE_9RULES)
4920 lp->patterned_rule = 0;
4921 break;
4922 case 12:
4923 if ((unsigned) lp->patterned_rule >= LIFE_12RULES)
4924 lp->patterned_rule = 0;
4925 break;
4926 }
4927 copyFromPatternedRule(lp->neighbors, &lp->param,
4928 lp->patterned_rule);
4929 printRule(lp->neighbors, lp->ruleString, lp->param,
4930 MI_IS_VERBOSE(mi));
4931 } else if (lp->allGliders) {
4932 lp->patterned_rule++;
4933 switch (lp->neighbors) {
4934 case 5:
4935 if ((unsigned) lp->patterned_rule >= LIFE_5GLIDERS)
4936 lp->patterned_rule = 0;
4937 break;
4938 case 6:
4939 if ((unsigned) lp->patterned_rule >= LIFE_6GLIDERS)
4940 lp->patterned_rule = 0;
4941 break;
4942 case 7:
4943 if ((unsigned) lp->patterned_rule >= LIFE_7GLIDERS)
4944 lp->patterned_rule = 0;
4945 break;
4946 case 8:
4947 if ((unsigned) lp->patterned_rule >= LIFE_8GLIDERS)
4948 lp->patterned_rule = 0;
4949 break;
4950 case 9:
4951 if ((unsigned) lp->patterned_rule >= LIFE_9GLIDERS)
4952 lp->patterned_rule = 0;
4953 break;
4954 case 12:
4955 if ((unsigned) lp->patterned_rule >= LIFE_12GLIDERS)
4956 lp->patterned_rule = 0;
4957 break;
4958 }
4959 copyFromPatternedRule(lp->neighbors, &lp->param,
4960 lp->patterned_rule);
4961 printRule(lp->neighbors, lp->ruleString, lp->param,
4962 MI_IS_VERBOSE(mi));
4963 }
4964 }
4965 if (glidersearch || patternsearch) {
4966 /* trying to find new patterns */
4967 RandomSoup(mi, randomSymmetry(lp, glidersearch), SOUPPERCENT,
4968 SOUPSIZE(lp->ncols), SOUPSIZE(lp->nrows));
4969 } else {
4970 if (!serial && !filePattern)
4971 lp->pattern = NRAND(npats + 3);
4972 if (lp->pattern >= npats)
4973 RandomSoup(mi, randomSymmetry(lp, False), SOUPPERCENT,
4974 SOUPSIZE(lp->ncols), SOUPSIZE(lp->nrows));
4975 else
4976 GetPattern(mi, lp->patterned_rule, lp->pattern);
4977 }
4978 }
4979 #endif
4980
4981 XSCREENSAVER_MODULE ("Life", life)
4982
4983 #endif /* MODE_life */
4984