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