1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* bug --- Michael Palmiter's simulated evolution */
3 
4 #if 0
5 static const char sccsid[] = "@(#)bug.c	5.24 2007/01/18 xlockmore";
6 
7 #endif
8 
9 /*-
10  * Copyright (c) 1995 by David Bagley.
11  *
12  * Permission to use, copy, modify, and distribute this software and its
13  * documentation for any purpose and without fee is hereby granted,
14  * provided that the above copyright notice appear in all copies and that
15  * both that copyright notice and this permission notice appear in
16  * supporting documentation.
17  *
18  * This file is provided AS IS with no warranties of any kind.  The author
19  * shall have no liability with respect to the infringement of copyrights,
20  * trade secrets or any patents by this file or any part thereof.  In no
21  * event will the author be liable for any lost revenue or profits or
22  * other special, indirect and consequential damages.
23  *
24  * Revision History:
25  * 18-Jan-2007: Added vertical option.
26  * 01-Nov-2000: Allocation checks
27  * 10-May-1997: Compatible with xscreensaver
28  * 24-Aug-1995: Coded from A.K. Dewdney's, "Computer Recreations", Scientific
29  *              American Magazine" May 1989 pp138-141 and Sept 1989 p 183.
30  *              also used wator.c as a guide.
31  */
32 
33 /*-
34  * Bugs learn to hunt bacteria (or die) in the Garden of Eden and outside.
35  * They start as jitterbugs and "evolve" to move straight (in the Garden
36  *  they may evolve to twirl around).
37  */
38 
39 #ifdef STANDALONE
40 # define MODE_bug
41 # define DEFAULTS	"*delay: 75000 \n" \
42 			"*count: 10 \n" \
43 			"*cycles: 32767 \n" \
44 			"*size: -4 \n" \
45 		 	"*ncolors: 64 \n" \
46 
47 # define free_bug 0
48 # define reshape_bug 0
49 # define bug_handle_event 0
50 # include "xlockmore.h"		/* in xscreensaver distribution */
51 #else /* STANDALONE */
52 # include "xlock.h"		/* in xlockmore distribution */
53 #endif /* STANDALONE */
54 #define DO_STIPPLE
55 #include "automata.h"
56 
57 #ifdef MODE_bug
58 
59 #define DEF_NEIGHBORS  "0"      /* choose random value */
60 #define DEF_EYES  "False"
61 #define DEF_VERTICAL "False"
62 
63 static int  neighbors;
64 static Bool eyes;
65 static Bool vertical;
66 
67 static XrmOptionDescRec opts[] =
68 {
69 	{(char *) "-neighbors", (char *) ".bug.neighbors", XrmoptionSepArg, (caddr_t) NULL},
70 	{(char *) "-eyes", (char *) ".bug.eyes", XrmoptionNoArg, (caddr_t) "on"},
71 	{(char *) "+eyes", (char *) ".bug.eyes", XrmoptionNoArg, (caddr_t) "off"},
72 	{(char *) "-vertical", (char *) ".bug.vertical", XrmoptionNoArg, (caddr_t) "on"},
73 	{(char *) "+vertical", (char *) ".bug.vertical", XrmoptionNoArg, (caddr_t) "off"}
74 };
75 static argtype vars[] =
76 {
77 	{(void *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
78 	{(void *) & eyes, (char *) "eyes", (char *) "Eyes", (char *) DEF_EYES, t_Bool},
79 	{(void *) & vertical, (char *) "vertical", (char *) "Vertical", (char *) DEF_VERTICAL, t_Bool}
80 };
81 static OptionStruct desc[] =
82 {
83 	{(char *) "-neighbors num", (char *) "squares 4 or 8, hexagons 6, triangles 3 or 12"},
84 	{(char *) "-/+eyes", (char *) "turn on/off eyes"},
85 	{(char *) "-/+vertical", (char *) "change orientation for hexagons and triangles"}
86 };
87 
88 ENTRYPOINT ModeSpecOpt bug_opts =
89 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
90 
91 
92 #ifdef USE_MODULES
93 ModStruct   bug_description =
94 {"bug", "init_bug", "draw_bug", "release_bug",
95  "refresh_bug", "init_bug", (char *) NULL, &bug_opts,
96  75000, 10, 32767, -4, 64, 1.0, "",
97  "Shows Palmiter's bug evolution and garden of Eden", 0, NULL};
98 
99 #endif
100 
101 #ifdef DEBUG
102 #include <assert.h>
103 #endif
104 
105 #define BUGBITS(n,w,h)\
106   if ((bp->pixmaps[bp->init_bits]=\
107   XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
108   free_bug_screen(display,bp); return;} else {bp->init_bits++;}
109 
110 #define BACTERIA 0
111 #define BUG 1
112 
113 #define MAXENERGY 1500		/* Max energy storage */
114 #define INITENERGY 400		/* Initial energy */
115 #define FOODPERCYCLE 1
116 #define BACTERIAENERGY 40
117 #define STRONG 1000		/* Min energy to breed */
118 #define MATURE 800		/* Breeding time of bugs */
119 #define MAXGENE 6
120 #define MINGENE (-MAXGENE)
121 #define REDRAWSTEP 2000		/* How many bacteria to draw per cycle */
122 #define MINGRIDSIZE 24
123 #define MINSIZE 1
124 #define ANGLES 360
125 #define MAXNEIGHBORS 12
126 
127 /* Relative hex bug moves */
128 /* Forward, Right, Hard Right, Reverse, Hard Left, Left */
129 
130 /* Bug data */
131 typedef struct {
132 	char        direction;
133 	int         age, energy;
134 	unsigned int color;
135 	int         col, row;
136 	int         gene[MAXNEIGHBORS];
137 	double      gene_prob[MAXNEIGHBORS];
138 #ifdef EXTRA_GENES
139 	int         lgene[MAXNEIGHBORS];
140 	double      lgene_prob[MAXNEIGHBORS];
141 #endif
142 } bugstruct;
143 
144 /* Doubly linked list */
145 typedef struct _BugList {
146 	bugstruct   info;
147 	struct _BugList *previous, *next;
148 } BugList;
149 
150 typedef struct {
151 	Bool        painted, vertical;
152 	int         neighbors;
153 	int         nbugs;	/* Number of bugs */
154 	int         eden;	/* Does the garden exist? */
155 	int         generation;
156 	int         ncols, nrows;
157 	int         width, height;
158 	int         edenwidth, edenheight;
159 	int         edenstartx, edenstarty;
160 	int         xs, ys, xb, yb;
161 	int         redrawing, redrawpos;
162 	int         eyes;
163 	BugList    *currbug, *babybug, *lastbug, *firstbug, *lasttemp, *firsttemp;
164 	BugList   **arr;	/* 0=empty or pts to a bug */
165 	char       *bacteria;	/* 0=empty or food */
166 	int         init_bits;
167 	GC          stippledGC;
168 	Pixmap      pixmaps[NUMSTIPPLES - 1];
169 	union {
170 		XPoint      hexagon[6];
171 		XPoint      triangle[2][3];
172 	} shape;
173 } bugfarmstruct;
174 
175 static double genexp[MAXGENE - MINGENE + 1];
176 
177 static char plots[] =
178 {3, 4, 6, 8,
179 #ifdef NUMBER_9
180  9,
181 #endif
182  12};		/* Neighborhoods */
183 
184 #define NEIGHBORKINDS (long) (sizeof plots / sizeof *plots)
185 
186 static bugfarmstruct *bugfarms = (bugfarmstruct *) NULL;
187 
188 #if 0
189 static void
190 positionOfNeighbor(bugfarmstruct * bp, int dir, int *pcol, int *prow)
191 {
192 	int         col = *pcol, row = *prow;
193 
194 	/* NO WRAPPING */
195 
196 	if (bp->neighbors == 4 || bp->neighbors == 6 || bp->neighbors == 8) {
197 		switch (dir) {
198 			case 0:
199 				col = col + 1;
200 				break;
201 			case 45:
202 				col = col + 1;
203 				row = row - 1;
204 				break;
205 			case 60:
206 				if (!(row & 1))
207 					col = col + 1;
208 				row = row - 1;
209 				break;
210 			case 90:
211 				row = row - 1;
212 				break;
213 			case 120:
214 				if (row & 1)
215 					col = col - 1;
216 				row = row - 1;
217 				break;
218 			case 135:
219 				col = col - 1;
220 				row = row - 1;
221 				break;
222 			case 180:
223 				col = col - 1;
224 				break;
225 			case 225:
226 				col = col - 1;
227 				row = row + 1;
228 				break;
229 			case 240:
230 				if (row & 1)
231 					col = col - 1;
232 				row = row + 1;
233 				break;
234 			case 270:
235 				row = row + 1;
236 				break;
237 			case 300:
238 				if (!(row & 1))
239 					col = col + 1;
240 				row = row + 1;
241 				break;
242 			case 315:
243 				col = col + 1;
244 				row = row + 1;
245 				break;
246 			default:
247 				(void) fprintf(stderr, "wrong direction %d\n", dir);
248 		}
249 	} else {		/* TRI */
250 		switch (dir) {
251 			case 0:
252 				col = col + 1;
253 				break;
254 			case 20:
255 			case 30:
256 			case 40:
257 				col = col + 1;
258 				row = row - 1;
259 				break;
260 			case 60:
261 				if ((col + row) % 2) {	/* right */
262 					row = row - 1;
263 				} else { /* left */
264 					col = col + 1;
265 					row = row - 2;
266 				}
267 				break;
268 			case 80:
269 			case 90:
270 			case 100:
271 				row = row - 2;
272 				break;
273 			case 120:
274 				if ((col + row) % 2) {	/* right */
275 					col = col - 1;
276 					row = row - 2;
277 				} else { /* left */
278 					row = row - 1;
279 				}
280 				break;
281 			case 140:
282 			case 150:
283 			case 160:
284 				col = col - 1;
285 				row = row - 1;
286 				break;
287 			case 180:
288 				col = col - 1;
289 				break;
290 			case 200:
291 			case 210:
292 			case 220:
293 				col = col - 1;
294 				row = row + 1;
295 				break;
296 			case 240:
297 				if ((col + row) % 2) {	/* right */
298 					col = col - 1;
299 					row = row + 2;
300 				} else { /* left */
301 					row = row + 1;
302 				}
303 				break;
304 			case 260:
305 			case 270:
306 			case 280:
307 				row = row + 2;
308 				break;
309 			case 300:
310 				if ((col + row) % 2) {	/* right */
311 					row = row + 1;
312 				} else { /* left */
313 					col = col + 1;
314 					row = row + 2;
315 				}
316 				break;
317 			case 320:
318 			case 330:
319 			case 340:
320 				col = col + 1;
321 				row = row + 1;
322 				break;
323 			default:
324 				(void) fprintf(stderr, "wrong direction %d\n", dir);
325 		}
326 	}
327 	*pcol = col;
328 	*prow = row;
329 }
330 
331 #endif
332 
333 #if 0
334 static void
335 screen2grid(bugfarmstruct *bp, int sx, int sy, int x, int y)
336 {
337 	*y = sy / 2;
338 	if (bp->neighbors == 6) {
339 		*x = (sx + 1) / 2 - 1;
340 	} else if (bp->neighbors == 4 || bp->neighbors == 8) {
341 		*x = sx / 2;
342 	} else {		/* TRI */
343 		/* Wrong but... */
344 		*x = sx / 3;
345 	}
346 }
347 
348 #endif
349 
350 static void
grid2screen(bugfarmstruct * bp,int x,int y,int * sx,int * sy)351 grid2screen(bugfarmstruct *bp, int x, int y, int *sx, int *sy)
352 {
353 	*sy = y * 2 + 1;
354 	if (bp->neighbors == 6) {
355 		*sx = 2 * x + 1 + !(y & 1);
356 	} else if (bp->neighbors == 4 || bp->neighbors == 8) {
357 		*sx = x * 2 + 1;
358 	} else {		/* TRI */
359 		*sx = x * 3 + 1 + ((y & 1) ? (x & 1) : !(x & 1));
360 	}
361 }
362 
363 static char
dirmove(bugfarmstruct * bp,int x,int y,int dir,int * nx,int * ny)364 dirmove(bugfarmstruct * bp, int x, int y, int dir, int *nx, int *ny)
365 {
366 	if (bp->neighbors == 6) {
367 		switch (dir) {
368 			case 0:
369 				*ny = y;
370 				*nx = x + 1;
371 				return (*nx < bp->ncols - !(*ny & 1));
372 			case 60:
373 				*ny = y - 1;
374 				*nx = x + (int) !(y & 1);
375 				return (*ny >= 0 && *nx < bp->ncols - !(*ny & 1));
376 			case 120:
377 				*ny = y - 1;
378 				*nx = x - (int) (y & 1);
379 				return (*ny >= 0 && *nx >= 0);
380 			case 180:
381 				*ny = y;
382 				*nx = x - 1;
383 				return (*nx >= 0);
384 			case 240:
385 				*ny = y + 1;
386 				*nx = x - (int) (y & 1);
387 				return (*ny < bp->nrows && *nx >= 0);
388 			case 300:
389 				*ny = y + 1;
390 				*nx = x + (int) !(y & 1);
391 				return (*ny < bp->nrows && *nx < bp->ncols - !(*ny & 1));
392 			default:
393 				(void) fprintf(stderr, "wrong direction %d\n", dir);
394 		}
395 	} else if (bp->neighbors == 4 || bp->neighbors == 8) {
396 		switch (dir) {
397 			case 0:
398 				*ny = y;
399 				*nx = x + 1;
400 				return (*nx < bp->ncols);
401 			case 45:
402 				*ny = y - 1;
403 				*nx = x + 1;
404 				return (*ny >= 0 && *nx < bp->ncols);
405 			case 90:
406 				*ny = y - 1;
407 				*nx = x;
408 				return (*ny >= 0);
409 			case 135:
410 				*ny = y - 1;
411 				*nx = x - 1;
412 				return (*ny >= 0 && *nx >= 0);
413 			case 180:
414 				*ny = y;
415 				*nx = x - 1;
416 				return (*nx >= 0);
417 			case 225:
418 				*ny = y + 1;
419 				*nx = x - 1;
420 				return (*ny < bp->nrows && *nx >= 0);
421 			case 270:
422 				*ny = y + 1;
423 				*nx = x;
424 				return (*ny < bp->nrows);
425 			case 315:
426 				*ny = y + 1;
427 				*nx = x + 1;
428 				return (*ny < bp->nrows && *nx < bp->ncols);
429 			default:
430 				(void) fprintf(stderr, "wrong direction %d\n", dir);
431 		}
432 	} else {		/* TRI */
433 		switch (dir) {
434 			case 0:
435 				*nx = x + 1;
436 				*ny = y;
437 				return (*nx < bp->ncols);
438 			case 20:
439 			case 30:
440 			case 40:
441 				*nx = x + 1;
442 				*ny = y - 1;
443 				return (*nx < bp->ncols && *ny >= 0);
444 			case 60:
445 				if ((x + y) % 2) {  /* right */
446 					*nx = x;
447 					*ny = y - 1;
448 					return (*ny >= 0);
449 				} else { /* left */
450 					*nx = x + 1;
451 					*ny = y - 2;
452 					return (*nx < bp->ncols && *ny >= 0);
453 				}
454 			case 80:
455 			case 90:
456 			case 100:
457 				*nx = x;
458 				*ny = y - 2;
459 				return (*ny >= 0);
460 			case 120:
461 				if ((x + y) % 2) {  /* right */
462 					*nx = x - 1;
463 					*ny = y - 2;
464 					return (*nx >= 0 && *ny >= 0);
465 				} else { /* left */
466 					*nx = x;
467 					*ny = y - 1;
468 					return (*ny >= 0);
469 				}
470 			case 140:
471 			case 150:
472 			case 160:
473 				*nx = x - 1;
474 				*ny = y - 1;
475 				return (*nx >= 0 && *ny >= 0);
476 			case 180:
477 				*nx = x - 1;
478 				*ny = y;
479 				return (*nx >= 0);
480 			case 200:
481 			case 210:
482 			case 220:
483 				*nx = x - 1;
484 				*ny = y + 1;
485 				return (*nx >= 0 && *ny < bp->nrows);
486 			case 240:
487 				if ((x + y) % 2) {  /* right */
488 					*nx = x - 1;
489 					*ny = y + 2;
490 					return (*nx >= 0 && *ny < bp->nrows);
491 				} else { /* left */
492 					*nx = x;
493 					*ny = y + 1;
494 					return (*ny < bp->nrows);
495 				}
496 			case 260:
497 			case 270:
498 			case 280:
499 				*nx = x;
500 				*ny = y + 2;
501 				return (*ny < bp->nrows);
502 			case 300:
503 				if ((x + y) % 2) {  /* right */
504 					*nx = x;
505 					*ny = y + 1;
506 					return (*ny < bp->nrows);
507 				} else { /* left */
508 					*nx = x + 1;
509 					*ny = y + 2;
510 					return (*nx < bp->ncols && *ny < bp->nrows);
511 				}
512 			case 320:
513 			case 330:
514 			case 340:
515 				*nx = x + 1;
516 				*ny = y + 1;
517 				return (*nx < bp->ncols && *ny < bp->nrows);
518 			default:
519 				(void) fprintf(stderr, "wrong direction %d\n", dir);
520 		}
521 	}
522 	*nx = -1;
523 	*ny = -1;
524 	return 0;
525 }
526 
527 /* This keeps bugs from walking over each other and escaping off the screen */
528 static int
has_neighbor(bugfarmstruct * bp,int col,int row)529 has_neighbor(bugfarmstruct * bp, int col, int row)
530 {
531 	int         colrow = col + row * bp->ncols;
532 
533 	if (bp->neighbors == 6) {
534 		if ((row > 0) && bp->arr[colrow - bp->ncols])
535 			return True;
536 		if ((row < bp->nrows - 1) && bp->arr[colrow + bp->ncols])
537 			return True;
538 		if (col > 0) {
539 			if (bp->arr[colrow - 1])
540 				return True;
541 			if (row & 1) {
542 				if ((row > 0) && bp->arr[colrow - 1 - bp->ncols])
543 					return True;
544 				if ((row < bp->nrows - 1) && bp->arr[colrow - 1 + bp->ncols])
545 					return True;
546 			}
547 		}
548 		if (col < bp->ncols - 1) {
549 			if (bp->arr[colrow + 1])
550 				return True;
551 			if (!(row & 1)) {
552 				if ((row > 0) && bp->arr[colrow + 1 - bp->ncols])
553 					return True;
554 				if ((row < bp->nrows - 1) && bp->arr[colrow + 1 + bp->ncols])
555 					return True;
556 			}
557 		}
558 	} else if (bp->neighbors == 4 || bp->neighbors == 8) {
559 		/* Same for both because the bug square takes up the space regardless */
560 		if ((row > 0) && bp->arr[colrow - bp->ncols])
561 			return True;
562 		if ((row < bp->nrows - 1) && bp->arr[colrow + bp->ncols])
563 			return True;
564 		if ((col > 0) && bp->arr[colrow - 1])
565 			return True;
566 		if ((col < bp->ncols - 1) && bp->arr[colrow + 1])
567 			return True;
568 		if (row > 0 && col > 0 && bp->arr[colrow - bp->ncols - 1])
569 			return True;
570 		if (row > 0 && col < bp->ncols - 1 && bp->arr[colrow - bp->ncols + 1])
571 			return True;
572 		if (row < bp->nrows - 1 && col > 0 && bp->arr[colrow + bp->ncols - 1])
573 			return True;
574 		if (row < bp->nrows - 1 && col < bp->ncols - 1 && bp->arr[colrow + bp->ncols + 1])
575 			return True;
576 	} else {		/* TRI */
577 		/* Same for all three neighbor kinds. Only care about 3
578 		   adjacent spots because that is all the squares will
579 		   overlap.*/
580 		if (((row & 1) && (col & 1)) || ((!(row & 1)) && (!(col & 1)))) {
581 			if ((col < bp->ncols - 1) && bp->arr[colrow + 1])
582 				return True;
583 		} else {
584 			if ((col > 0) && bp->arr[colrow - 1])
585 				return True;
586 		}
587 		if ((row > 0) && bp->arr[colrow - bp->ncols])
588 			return True;
589 		if ((row < bp->nrows - 1) && bp->arr[colrow + bp->ncols])
590 			return True;
591 	}
592 	return False;
593 }
594 
595 static void
drawabacterium(ModeInfo * mi,int col,int row,unsigned char color)596 drawabacterium(ModeInfo * mi, int col, int row, unsigned char color)
597 {
598 	bugfarmstruct *bp = &bugfarms[MI_SCREEN(mi)];
599 	int         ccol, crow;
600 
601 	if (color)
602 		XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
603 	else
604 		XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
605 	grid2screen(bp, col, row, &ccol, &crow);
606 	if (bp->vertical) {
607 		XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
608 			bp->xb + bp->xs * ccol,
609 			bp->yb + bp->ys * crow,
610 			bp->xs, bp->ys);
611 	} else {
612 		XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
613 			bp->yb + bp->ys * crow,
614 			bp->xb + bp->xs * ccol,
615 			bp->ys, bp->xs);
616 	}
617 }
618 
619 static void
drawabug(ModeInfo * mi,int col,int row,unsigned int color,int direction)620 drawabug(ModeInfo * mi, int col, int row, unsigned int color, int direction)
621 {
622 	bugfarmstruct *bp = &bugfarms[MI_SCREEN(mi)];
623 	Display *display = MI_DISPLAY(mi);
624 	Window window = MI_WINDOW(mi);
625 	int         ccol, crow;
626 	GC          gc;
627 
628 	if (MI_NPIXELS(mi) > 3) {
629 		XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, color));
630 		gc = MI_GC(mi);
631 	} else {
632 		XGCValues   gcv;
633 
634 		gcv.stipple = bp->pixmaps[color];
635 		gcv.foreground = MI_WHITE_PIXEL(mi);
636 		gcv.background = MI_BLACK_PIXEL(mi);
637 		XChangeGC(MI_DISPLAY(mi), bp->stippledGC,
638 			  GCStipple | GCForeground | GCBackground, &gcv);
639 		gc = bp->stippledGC;
640 	}
641 
642 	grid2screen(bp, col, row, &ccol, &crow);
643 	ccol = bp->xb + bp->xs * (ccol - 1);
644 	crow = bp->yb + bp->ys * (crow - 1);
645 	if (bp->vertical) {
646 		XFillRectangle(display, window, gc,
647 			ccol, crow, 3 * bp->xs, 3 * bp->ys);
648 	} else {
649 		XFillRectangle(display, window, gc,
650 			crow, ccol, 3 * bp->ys, 3 * bp->xs);
651 	}
652 
653 	if (bp->eyes && bp->xs >= 1 && bp->ys >= 1) { /* Draw Eyes */
654 		XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
655 		switch (direction) {
656 		case 0:
657 			if (bp->vertical) {
658 				XDrawPoint(display, window, MI_GC(mi),
659 					ccol + 3 * bp->xs - 2,
660 					crow + 3 * bp->ys / 2 - 1);
661 				XDrawPoint(display, window, MI_GC(mi),
662 					ccol + 3 * bp->xs - 2,
663 					crow + 3 * bp->ys / 2 + 1);
664 			} else {
665 				XDrawPoint(display, window, MI_GC(mi),
666 					crow + 3 * bp->ys / 2 - 1,
667 					ccol + 3 * bp->xs - 2);
668 				XDrawPoint(display, window, MI_GC(mi),
669 					crow + 3 * bp->ys / 2 + 1,
670 					ccol + 3 * bp->xs - 2);
671 			}
672 			break;
673 		case 20:
674 		case 30:
675 		case 40:
676 		case 45:
677 		case 60:
678 			if (bp->vertical) {
679 				XDrawPoint(display, window, MI_GC(mi),
680 					ccol + 3 * bp->xs - 3,
681 					crow + 1);
682 				XDrawPoint(display, window, MI_GC(mi),
683 					ccol + 3 * bp->xs - 2,
684 					crow + 2);
685 			} else {
686 				XDrawPoint(display, window, MI_GC(mi),
687 					crow + 1,
688 					ccol + 3 * bp->xs - 3);
689 				XDrawPoint(display, window, MI_GC(mi),
690 					crow + 2,
691 					ccol + 3 * bp->xs - 2);
692 			}
693 			break;
694 		case 80:
695 		case 90:
696 		case 100:
697 			if (bp->vertical) {
698 				XDrawPoint(display, window, MI_GC(mi),
699 					ccol + 3 * bp->xs / 2 - 1,
700 					crow + 1);
701 				XDrawPoint(display, window, MI_GC(mi),
702 					ccol + 3 * bp->xs / 2 + 1,
703 					crow + 1);
704 			} else {
705 				XDrawPoint(display, window, MI_GC(mi),
706 					crow + 1,
707 					ccol + 3 * bp->xs / 2 - 1);
708 				XDrawPoint(display, window, MI_GC(mi),
709 					crow + 1,
710 					ccol + 3 * bp->xs / 2 + 1);
711 			}
712 			break;
713 		case 120:
714 		case 135:
715 		case 140:
716 		case 150:
717 		case 160:
718 			if (bp->vertical) {
719 				XDrawPoint(display, window, MI_GC(mi),
720 					ccol + 2,
721 					crow + 1);
722 				XDrawPoint(display, window, MI_GC(mi),
723 					ccol + 1,
724 					crow + 2);
725 			} else {
726 				XDrawPoint(display, window, MI_GC(mi),
727 					crow + 1,
728 					ccol + 2);
729 				XDrawPoint(display, window, MI_GC(mi),
730 					crow + 2,
731 					ccol + 1);
732 			}
733 			break;
734 		case 180:
735 			if (bp->vertical) {
736 				XDrawPoint(display, window, MI_GC(mi),
737 					ccol + 1,
738 					crow + 3 * bp->ys / 2 - 1);
739 				XDrawPoint(display, window, MI_GC(mi),
740 					ccol + 1,
741 					crow + 3 * bp->ys / 2 + 1);
742 			} else {
743 				XDrawPoint(display, window, MI_GC(mi),
744 					crow + 3 * bp->ys / 2 - 1,
745 					ccol + 1);
746 				XDrawPoint(display, window, MI_GC(mi),
747 					crow + 3 * bp->ys / 2 + 1,
748 					ccol + 1);
749 			}
750 			break;
751 		case 200:
752 		case 210:
753 		case 220:
754 		case 225:
755 		case 240:
756 			if (bp->vertical) {
757 				XDrawPoint(display, window, MI_GC(mi),
758 					ccol + 2,
759 					crow + 3 * bp->ys - 2);
760 				XDrawPoint(display, window, MI_GC(mi),
761 					ccol + 1,
762 					crow + 3 * bp->ys - 3);
763 			} else {
764 				XDrawPoint(display, window, MI_GC(mi),
765 					crow + 3 * bp->ys - 2,
766 					ccol + 2);
767 				XDrawPoint(display, window, MI_GC(mi),
768 					crow + 3 * bp->ys - 3,
769 					ccol + 1);
770 			}
771 			break;
772 		case 260:
773 		case 270:
774 		case 280:
775 			if (bp->vertical) {
776 				XDrawPoint(display, window, MI_GC(mi),
777 					ccol + 3 * bp->xs / 2 - 1,
778 					crow + 3 * bp->ys - 2);
779 				XDrawPoint(display, window, MI_GC(mi),
780 					ccol + 3 * bp->xs / 2 + 1,
781 					crow + 3 * bp->ys - 2);
782 			} else {
783 				XDrawPoint(display, window, MI_GC(mi),
784 					crow + 3 * bp->ys - 2,
785 					ccol + 3 * bp->xs / 2 - 1);
786 				XDrawPoint(display, window, MI_GC(mi),
787 					crow + 3 * bp->ys - 2,
788 					ccol + 3 * bp->xs / 2 + 1);
789 			}
790 			break;
791 		case 300:
792 		case 315:
793 		case 320:
794 		case 330:
795 		case 340:
796 			if (bp->vertical) {
797 				XDrawPoint(display, window, MI_GC(mi),
798 					ccol + 3 * bp->xs - 3,
799 					crow + 3 * bp->ys - 2);
800 				XDrawPoint(display, window, MI_GC(mi),
801 					ccol + 3 * bp->xs - 2,
802 					crow + 3 * bp->ys - 3);
803 			} else {
804 				XDrawPoint(display, window, MI_GC(mi),
805 					crow + 3 * bp->ys - 2,
806 					ccol + 3 * bp->xs - 3);
807 				XDrawPoint(display, window, MI_GC(mi),
808 					crow + 3 * bp->ys - 3,
809 					ccol + 3 * bp->xs - 2);
810 			}
811 			break;
812 		default:
813 			(void) fprintf(stderr, "wrong direction %d\n", direction);
814 		}
815 	}
816 }
817 
818 static void
eraseabug(ModeInfo * mi,int col,int row)819 eraseabug(ModeInfo * mi, int col, int row)
820 {
821 	bugfarmstruct *bp = &bugfarms[MI_SCREEN(mi)];
822 	int         ccol, crow;
823 
824 	XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
825 	grid2screen(bp, col, row, &ccol, &crow);
826 	if (bp->vertical) {
827 		XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
828 			bp->xb + bp->xs * (ccol - 1),
829 			bp->yb + bp->ys * (crow - 1),
830 			3 * bp->xs, 3 * bp->ys);
831 	} else {
832 		XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
833 			bp->yb + bp->ys * (crow - 1),
834 			bp->xb + bp->xs * (ccol - 1),
835 			3 * bp->ys, 3 * bp->xs);
836 	}
837 }
838 
839 static void
flush_buglist(bugfarmstruct * bp)840 flush_buglist(bugfarmstruct * bp)
841 {
842 	while (bp->lastbug->previous != bp->firstbug) {
843 		bp->currbug = bp->lastbug->previous;
844 		bp->currbug->previous->next = bp->lastbug;
845 		bp->lastbug->previous = bp->currbug->previous;
846 		/*bp->arr[bp->currbug->info.col + bp->currbug->info.row * bp->ncols] = 0; */
847 		free(bp->currbug);
848 	}
849 
850 	while (bp->lasttemp->previous != bp->firsttemp) {
851 		bp->currbug = bp->lasttemp->previous;
852 		bp->currbug->previous->next = bp->lasttemp;
853 		bp->lasttemp->previous = bp->currbug->previous;
854 		/*bp->arr[bp->currbug->info.col + bp->currbug->info.row * bp->ncols] = 0; */
855 		free(bp->currbug);
856 	}
857 }
858 
859 static void
free_buglist(bugfarmstruct * bp)860 free_buglist(bugfarmstruct *bp)
861 {
862 	if (bp->firstbug != NULL) {
863 		flush_buglist(bp);
864 		free(bp->firstbug);
865 		bp->firstbug = (BugList *) NULL;
866 	}
867 	if (bp->lastbug != NULL) {
868 		free(bp->lastbug);
869 		bp->lastbug = (BugList *) NULL;
870 	}
871 	if (bp->lasttemp != NULL) {
872 		free(bp->lasttemp);
873 		bp->lasttemp = (BugList *) NULL;
874 	}
875 	if (bp->firsttemp != NULL) {
876 		free(bp->firsttemp);
877 		bp->firsttemp = (BugList *) NULL;
878 	}
879 }
880 
881 static Bool
init_buglist(bugfarmstruct * bp)882 init_buglist(bugfarmstruct * bp)
883 {
884 	/* Waste some space at the beginning and end of list
885 	   so we do not have to complicated checks against falling off the ends. */
886 	if ((bp->lastbug = (BugList *) malloc(sizeof (BugList))) == NULL) {
887 		free_buglist(bp);
888 		return False;
889 	}
890 	if ((bp->firstbug = (BugList *) malloc(sizeof (BugList))) == NULL) {
891 		free_buglist(bp);
892 		return False;
893 	}
894 	bp->firstbug->previous = bp->lastbug->next = (struct _BugList *) NULL;
895 	bp->firstbug->next = bp->lastbug->previous = (struct _BugList *) NULL;
896 	bp->firstbug->next = bp->lastbug;
897 	bp->lastbug->previous = bp->firstbug;
898 
899 	if ((bp->lasttemp = (BugList *) malloc(sizeof (BugList))) == NULL) {
900 		free_buglist(bp);
901 		return False;
902 	}
903 	if ((bp->firsttemp = (BugList *) malloc(sizeof (BugList))) == NULL) {
904 		free_buglist(bp);
905 		return False;
906 	}
907 	bp->firsttemp->previous = bp->lasttemp->next = (struct _BugList *) NULL;
908 	bp->firsttemp->next = bp->lasttemp->previous = (struct _BugList *) NULL;
909 	bp->firsttemp->next = bp->lasttemp;
910 	bp->lasttemp->previous = bp->firsttemp;
911 	return True;
912 }
913 
914 static void
addto_buglist(bugfarmstruct * bp,bugstruct info)915 addto_buglist(bugfarmstruct * bp, bugstruct info)
916 {
917 	if ((bp->currbug = (BugList *) malloc(sizeof (BugList))) == NULL) {
918 		free_buglist(bp);
919 		return;
920 	}
921 	bp->lastbug->previous->next = bp->currbug;
922 	bp->currbug->previous = bp->lastbug->previous;
923 	bp->currbug->next = bp->lastbug;
924 	bp->lastbug->previous = bp->currbug;
925 	bp->currbug->info = info;
926 }
927 
928 static void
removefrom_buglist(bugfarmstruct * bp,BugList * ptr)929 removefrom_buglist(bugfarmstruct * bp, BugList * ptr)
930 {
931 	ptr->previous->next = ptr->next;
932 	ptr->next->previous = ptr->previous;
933 	bp->arr[ptr->info.col + ptr->info.row * bp->ncols] = 0;
934 	free(ptr);
935 }
936 
937 static void
dupin_buglist(bugfarmstruct * bp)938 dupin_buglist(bugfarmstruct * bp)
939 {
940 	BugList    *temp;
941 
942 	if ((temp = (BugList *) malloc(sizeof (BugList))) == NULL) {
943 		free_buglist(bp);
944 		return;
945 	}
946 	temp->previous = bp->babybug;
947 	temp->next = bp->babybug->next;
948 	bp->babybug->next = temp;
949 	temp->next->previous = temp;
950 	temp->info = bp->babybug->info;
951 	bp->babybug = temp;
952 }
953 
954 /*-
955  * new bug at end of list, this rotates who goes first, young bugs go last
956  * this most likely will not change the feel to any real degree
957  */
958 static void
cutfrom_buglist(bugfarmstruct * bp)959 cutfrom_buglist(bugfarmstruct * bp)
960 {
961 	bp->babybug = bp->currbug;
962 	bp->currbug = bp->currbug->previous;
963 	bp->currbug->next = bp->babybug->next;
964 	bp->babybug->next->previous = bp->currbug;
965 	bp->babybug->next = bp->lasttemp;
966 	bp->babybug->previous = bp->lasttemp->previous;
967 	bp->babybug->previous->next = bp->babybug;
968 	bp->babybug->next->previous = bp->babybug;
969 }
970 
971 static void
reattach_buglist(bugfarmstruct * bp)972 reattach_buglist(bugfarmstruct * bp)
973 {
974 	bp->currbug = bp->lastbug->previous;
975 	bp->currbug->next = bp->firsttemp->next;
976 	bp->currbug->next->previous = bp->currbug;
977 	bp->lastbug->previous = bp->lasttemp->previous;
978 	bp->lasttemp->previous->next = bp->lastbug;
979 	bp->lasttemp->previous = bp->firsttemp;
980 	bp->firsttemp->next = bp->lasttemp;
981 }
982 
983 static int
dirbug(bugstruct * info,int local_neighbors)984 dirbug(bugstruct * info, int local_neighbors)
985 {
986 	double      sum = 0.0, prob;
987 	int         i;
988 
989 	prob = (double) LRAND() / MAXRAND;
990 #if EXTRA_GENES
991 	if ((local_neighbors % 2) && !((info->col + info->row) & 1)) {
992 		for (i = 0; i < local_neighbors; i++) {
993 			sum += info->lgene_prob[i];
994 			if (prob < sum)
995 				return i;
996 		}
997 	} else
998 #endif
999 	{
1000 		for (i = 0; i < local_neighbors; i++) {
1001 			sum += info->gene_prob[i];
1002 			if (prob < sum)
1003 				return i;
1004 		}
1005 	}
1006 	return local_neighbors - 1;	/* Could miss due to rounding */
1007 }
1008 
1009 static void
mutatebug(bugstruct * info,int local_neighbors)1010 mutatebug(bugstruct * info, int local_neighbors)
1011 {
1012 	double      sum = 0.0;
1013 	int         gene;
1014 
1015 	gene = NRAND(local_neighbors);
1016 	if (LRAND() & 1) {
1017 		if (info->gene[gene] == MAXGENE)
1018 			return;
1019 		info->gene[gene]++;
1020 	} else {
1021 		if (info->gene[gene] == MINGENE)
1022 			return;
1023 		info->gene[gene]--;
1024 	}
1025 	for (gene = 0; gene < local_neighbors; gene++)
1026 		sum += genexp[info->gene[gene] + MAXGENE];
1027 	for (gene = 0; gene < local_neighbors; gene++)
1028 		info->gene_prob[gene] = genexp[info->gene[gene] + MAXGENE] / sum;
1029 #ifdef EXTRA_GENES
1030 	if (local_neighbors % 2) {
1031 		sum = 0.0;
1032 		gene = NRAND(local_neighbors);
1033 		if (LRAND() & 1) {
1034 			if (info->lgene[gene] == MAXGENE)
1035 				return;
1036 			info->lgene[gene]++;
1037 		} else {
1038 			if (info->lgene[gene] == MINGENE)
1039 				return;
1040 			info->lgene[gene]--;
1041 		}
1042 		for (gene = 0; gene < local_neighbors; gene++)
1043 			sum += genexp[info->lgene[gene] + MAXGENE];
1044 		for (gene = 0; gene < local_neighbors; gene++)
1045 			info->lgene_prob[gene] = genexp[info->lgene[gene] + MAXGENE] / sum;
1046 	}
1047 #endif
1048 }
1049 
1050 static void
makebacteria(ModeInfo * mi,int n,int startx,int starty,int width,int height,Bool draw)1051 makebacteria(ModeInfo * mi,
1052 	     int n, int startx, int starty, int width, int height, Bool draw)
1053 {
1054 	int         nbacteria = 0, ntries = 0, col, row, colrow;
1055 	bugfarmstruct *bp = &bugfarms[MI_SCREEN(mi)];
1056 
1057 	/* Make bacteria but if can not, exit */
1058 	while (nbacteria < n && ntries < 2 * n) {
1059 		row = NRAND(height) + starty;
1060 		if (bp->neighbors == 6) {
1061 			if (width - (!(row & 1)) > 0)
1062 				col = NRAND(width - (!(row & 1))) + startx;
1063 			else
1064 				col = startx;
1065 		} else { /* RECT or TRI */
1066 			col = NRAND(width) + startx;
1067 		}
1068 		colrow = col + row * bp->ncols;
1069 		ntries++;
1070 		if (!bp->arr[colrow] && !bp->bacteria[colrow]) {
1071 			nbacteria++;
1072 			bp->bacteria[colrow] = True;
1073 			drawabacterium(mi, col, row, draw);
1074 		}
1075 	}
1076 }
1077 
1078 static void
redrawbacteria(ModeInfo * mi,int colrow)1079 redrawbacteria(ModeInfo * mi, int colrow)
1080 {
1081 	int         col, row;
1082 	bugfarmstruct *bp = &bugfarms[MI_SCREEN(mi)];
1083 
1084 	if (!bp->bacteria[colrow])
1085 		return;
1086 
1087 	row = colrow / bp->ncols;
1088 	col = colrow % bp->ncols;
1089 	drawabacterium(mi, col, row, True);
1090 }
1091 
1092 static void
free_bug_screen(Display * display,bugfarmstruct * bp)1093 free_bug_screen(Display *display, bugfarmstruct *bp)
1094 {
1095 	int         shade;
1096 
1097 	if (bp == NULL) {
1098 		return;
1099 	}
1100 	if (bp->stippledGC != None) {
1101 		XFreeGC(display, bp->stippledGC);
1102 		bp->stippledGC = None;
1103 	}
1104 	for (shade = 0; shade < bp->init_bits; shade++) {
1105 		if (bp->pixmaps[shade] != None) {
1106 			XFreePixmap(display, bp->pixmaps[shade]);
1107 			bp->pixmaps[shade] = None;
1108 		}
1109 	}
1110 	bp->init_bits = 0;
1111 	if (bp->firstbug != NULL) {
1112 		flush_buglist(bp);
1113 		free(bp->firstbug);
1114 		bp->firstbug = (BugList *) NULL;
1115 	}
1116 	if (bp->lastbug != NULL) {
1117 		free(bp->lastbug);
1118 		bp->lastbug = (BugList *) NULL;
1119 	}
1120 	if (bp->lasttemp != NULL) {
1121 		free(bp->lasttemp);
1122 		bp->lasttemp = (BugList *) NULL;
1123 	}
1124 	if (bp->firsttemp != NULL) {
1125 		free(bp->firsttemp);
1126 		bp->firsttemp = (BugList *) NULL;
1127 	}
1128 	if (bp->arr != NULL) {
1129 		free(bp->arr);
1130 		bp->arr = (BugList **) NULL;
1131 	}
1132 	if (bp->bacteria != NULL) {
1133 		free(bp->bacteria);
1134 		bp->bacteria = (char *) NULL;
1135 	}
1136 	bp = NULL;
1137 }
1138 
1139 ENTRYPOINT void
init_bug(ModeInfo * mi)1140 init_bug(ModeInfo * mi)
1141 {
1142 	Display    *display = MI_DISPLAY(mi);
1143 	Window      window = MI_WINDOW(mi);
1144 	int         size = MI_SIZE(mi);
1145 	XGCValues   gcv;
1146 	int         nbugs = 0, ntries = 0, col = 0, row, gene, colrow, i;
1147 	int         nccols, ncrows;
1148 	double      sum;
1149 	bugstruct   info;
1150 	bugfarmstruct *bp;
1151 
1152 	MI_INIT(mi, bugfarms);
1153 	bp = &bugfarms[MI_SCREEN(mi)];
1154 
1155 	if (MI_IS_FULLRANDOM(mi)) {
1156 		bp->eyes = (Bool) (LRAND() & 1);
1157 		bp->vertical = (Bool) (LRAND() & 1);
1158 	} else {
1159 		bp->eyes = eyes;
1160 		bp->vertical = vertical;
1161 	}
1162 	bp->eyes = (bp->eyes && bp->xs > 1 && bp->ys > 1);
1163 
1164 	if (MI_NPIXELS(mi) <= 3) {
1165 		if (bp->stippledGC == None) {
1166 			gcv.fill_style = FillOpaqueStippled;
1167 			if ((bp->stippledGC = XCreateGC(display, window,
1168 					GCFillStyle, &gcv)) == None) {
1169 				free_bug_screen(display, bp);
1170 				return;
1171 			}
1172 		}
1173 		if (bp->init_bits == 0) {
1174 			for (i = 1; i < NUMSTIPPLES; i++) {
1175 				BUGBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
1176 			}
1177 		}
1178 	}
1179 	bp->generation = 0;
1180 	if (bp->firstbug == NULL) {	/* Genesis */
1181 		/* Set up what will be a 'triply' linked list.
1182 		   doubly linked list, doubly linked to an array */
1183 		if (!init_buglist(bp)) {
1184 			free_bug_screen(display, bp);
1185 			return;
1186 		}
1187 		genexp[MAXGENE] = 1;
1188 		for (i = 1; i <= MAXGENE; i++) {
1189 			genexp[MAXGENE + i] = genexp[MAXGENE + i - 1] * M_E;
1190 			genexp[MAXGENE - i] = 1.0 / genexp[MAXGENE + i];
1191 		}
1192 	} else			/* Apocolypse now */
1193 		flush_buglist(bp);
1194 
1195 	for (i = 0; i < NEIGHBORKINDS; i++) {
1196 		if (neighbors == plots[i]) {
1197 			bp->neighbors = plots[i];
1198 			break;
1199 		}
1200 		if (i == NEIGHBORKINDS - 1) {
1201 			bp->neighbors = plots[NRAND(NEIGHBORKINDS)];
1202 			break;
1203 		}
1204 	}
1205 
1206 	bp->width = MI_WIDTH(mi);
1207 	bp->height = MI_HEIGHT(mi);
1208 
1209 	if (!bp->vertical && bp->neighbors != 4 && bp->neighbors != 8) {
1210 		bp->height = MI_WIDTH(mi);
1211 		bp->width = MI_HEIGHT(mi);
1212 	} else {
1213 		bp->vertical = True;
1214 	}
1215 	if (bp->width < 8)
1216 		bp->width = 8;
1217 	if (bp->height < 8)
1218 		bp->height = 8;
1219 
1220 	if (size < -MINSIZE)
1221 		bp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(bp->width, bp->height) /
1222 				      MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
1223 	else if (size < MINSIZE) {
1224 		if (!size)
1225 			bp->ys = MAX(MINSIZE, MIN(bp->width, bp->height) / MINGRIDSIZE);
1226 		else
1227 			bp->ys = MINSIZE;
1228 	} else
1229 		bp->ys = MIN(size, MAX(MINSIZE, MIN(bp->width, bp->height) /
1230 				       MINGRIDSIZE));
1231 	bp->xs = bp->ys;
1232 	nccols = MAX(bp->width / bp->xs - 2, 2);
1233 	ncrows = MAX(bp->height / bp->ys - 1, 2);
1234 	bp->nrows = ncrows / 2;
1235 	if ((bp->neighbors % 2) || bp->neighbors == 12) {
1236 		bp->ncols = nccols / 3;
1237 		if (bp->ncols & 1)
1238 			bp->ncols--;	/* Must be odd for no wrap */
1239 		if (bp->ncols < 2)
1240 			bp->ncols = 2;
1241 		if (!(bp->nrows & 1))
1242 			bp->nrows--;	/* Must be even for no wrap */
1243 	} else
1244 		bp->ncols = nccols / 2;
1245 	if (bp->neighbors == 6 && !(bp->nrows & 1))
1246 		bp->nrows--;	/* Must be odd for no wrap */
1247 	bp->xb = (bp->width - bp->xs * nccols) / 2;
1248 	bp->yb = (bp->height - bp->ys * ncrows) / 2;
1249 	if (bp->arr != NULL)
1250 		free(bp->arr);
1251 	if ((bp->arr = (BugList **) calloc(bp->ncols * bp->nrows,
1252 			sizeof (BugList *))) == NULL) {
1253 		free_bug_screen(display, bp);
1254 		return;
1255 	}
1256 	if (bp->bacteria != NULL)
1257 		free(bp->bacteria);
1258 	if ((bp->bacteria = (char *) calloc(bp->ncols * bp->nrows,
1259 			sizeof (char))) == NULL) {
1260 		free_bug_screen(display, bp);
1261 		return;
1262 	}
1263 	bp->edenheight = bp->nrows / 4;
1264 	bp->edenwidth = bp->ncols / 4;
1265 	if ((bp->neighbors % 2) || bp->neighbors == 12) {
1266 		if (bp->edenwidth & 1)
1267 			bp->edenwidth--;
1268 		if (!(bp->edenheight & 1))
1269 			bp->edenheight--;
1270 	} else if (bp->neighbors == 6 && bp->edenheight && !(bp->edenheight & 1))
1271 		bp->edenheight--;	/* Make sure its odd */
1272 	bp->eden = (bp->edenwidth > 1 && bp->edenheight > 1);
1273 	if (bp->eden) {
1274 		bp->edenstartx = NRAND(bp->ncols - bp->edenwidth);
1275 		bp->edenstarty = NRAND(bp->nrows - bp->edenheight);
1276 		if ((bp->neighbors % 2) || bp->neighbors == 12) {
1277 			if (bp->edenstartx & 1) {
1278 				bp->edenstartx--;
1279 				bp->eden = (bp->edenwidth > 1);
1280 			}
1281 			if (bp->edenstarty & 1) {
1282 				bp->edenstarty--;
1283 				bp->eden = (bp->edenheight > 1);
1284 			}
1285 		} else if (bp->neighbors == 6 && (bp->edenstarty & 1)) {
1286 			bp->edenstarty--;
1287 			bp->eden = (bp->edenheight > 1);
1288 		}
1289 	}
1290 	/* Play G-d with these numbers... the genes */
1291 	nbugs = MI_COUNT(mi);
1292 	if (nbugs < 0)
1293 		nbugs = NRAND(-nbugs) + 1;
1294 	bp->nbugs = 0;
1295 
1296 	MI_CLEARWINDOW(mi);
1297 	bp->painted = False;
1298 
1299 	/* Try to make bugs, but if can not, exit */
1300 	while (bp->nbugs < nbugs && ntries < 2 * nbugs) {
1301 		row = NRAND(bp->nrows);
1302 		if (bp->neighbors == 6) {
1303 			if (bp->ncols - (!(row & 1)) > 0)
1304 				col = NRAND(bp->ncols - (!(row & 1)));
1305 			else
1306 				col = 0;
1307 		} else { /* RECT or TRI */
1308 			col = NRAND(bp->ncols);
1309 		}
1310 		colrow = col + row * bp->ncols;
1311 		ntries++;
1312 		if (!bp->arr[colrow] && !has_neighbor(bp, col, row)) {
1313 			bp->nbugs++;
1314 			info.age = 0;
1315 			info.energy = INITENERGY;
1316 			info.direction = NRAND(bp->neighbors);
1317 			for (gene = 0; gene < bp->neighbors; gene++) {
1318 #if 1
1319 				/* Jitterbugs, evolve or die */
1320 				info.gene[gene] = 0;
1321 #else
1322 				/* Some creationalism, may create gliders or twirlers */
1323 				do {
1324 					double      temp = (double) LRAND() / MAXRAND;
1325 
1326 					info.gene[gene] = ((int) (1.0 / (1.0 - temp * temp)) - 1) *
1327 						((LRAND() & 1) ? -1 : 1);
1328 				} while (info.gene[gene] > MAXGENE / 2 ||
1329 					 info.gene[gene] < MINGENE / 2);
1330 #endif
1331 			}
1332 			sum = 0;
1333 			for (gene = 0; gene < bp->neighbors; gene++)
1334 				sum += genexp[info.gene[gene] + MAXGENE];
1335 			for (gene = 0; gene < bp->neighbors; gene++)
1336 				info.gene_prob[gene] = genexp[info.gene[gene] + MAXGENE] / sum;
1337 #ifdef EXTRA_GENES
1338 			if (bp->neighbors % 2) {
1339 				for (gene = 0; gene < bp->neighbors; gene++) {
1340 #if 1
1341 					/* Jitterbugs, evolve or die */
1342 					info.lgene[gene] = 0;
1343 #else
1344 					/* Some creationalism, may create gliders or twirlers */
1345 					do {
1346 						double      temp = (double) LRAND() / MAXRAND;
1347 
1348 						info.lgene[gene] = ((int) (1.0 / (1.0 - temp * temp)) - 1) *
1349 							((LRAND() & 1) ? -1 : 1);
1350 					} while (info.lgene[gene] > MAXGENE / 2 ||
1351 						 info.lgene[gene] < MINGENE / 2);
1352 #endif
1353 				}
1354 				sum = 0;
1355 				for (gene = 0; gene < bp->neighbors; gene++)
1356 					sum += genexp[info.lgene[gene] + MAXGENE];
1357 				for (gene = 0; gene < bp->neighbors; gene++)
1358 					info.lgene_prob[gene] = genexp[info.lgene[gene] + MAXGENE] / sum;
1359 			}
1360 #endif
1361 			if (MI_NPIXELS(mi) > 3)
1362 				info.color = NRAND(MI_NPIXELS(mi));
1363 			else
1364 				info.color = NRAND(NUMSTIPPLES - 1);
1365 			info.col = col;
1366 			info.row = row;
1367 			addto_buglist(bp, info);
1368 			if (bp->firstbug == NULL) {
1369 				free_bug_screen(display, bp);
1370 				return;
1371 			}
1372 			bp->arr[colrow] = bp->currbug;
1373 			drawabug(mi, col, row, bp->currbug->info.color, (int) bp->currbug->info.direction * ANGLES / bp->neighbors);
1374 		}
1375 	}
1376 	makebacteria(mi, bp->ncols * bp->nrows / 2, 0, 0, bp->ncols, bp->nrows,
1377 		     False);
1378 	if (bp->eden)
1379 		makebacteria(mi, bp->edenwidth * bp->edenheight / 2,
1380 		bp->edenstartx, bp->edenstarty, bp->edenwidth, bp->edenheight, False);
1381 	bp->redrawing = 1;
1382 	bp->redrawpos = 0;
1383 }
1384 
1385 #define ENOUGH 16
1386 ENTRYPOINT void
draw_bug(ModeInfo * mi)1387 draw_bug(ModeInfo * mi)
1388 {
1389 	int         col, row, ncol = -1, nrow = -1, colrow, ncolrow;
1390 	int         absdir = 0, tryit, dir;
1391 	bugfarmstruct *bp;
1392 
1393 	if (bugfarms == NULL)
1394 		return;
1395 	bp = &bugfarms[MI_SCREEN(mi)];
1396 	if (bp->firstbug == NULL)
1397 		return;
1398 
1399 	MI_IS_DRAWN(mi) = True;
1400 	bp->painted = True;
1401 	bp->currbug = bp->firstbug->next;
1402 	while (bp->currbug != bp->lastbug) {
1403 		col = bp->currbug->info.col;
1404 		row = bp->currbug->info.row;
1405 		colrow = col + row * bp->ncols;
1406 		if (bp->currbug->info.energy-- < 0) {	/* Time to die, Bug */
1407 #ifdef DEBUG
1408 			assert(bp->currbug == bp->arr[colrow]);
1409 #endif
1410 			/* back up one or else in void */
1411 			bp->currbug = bp->currbug->previous;
1412 			removefrom_buglist(bp, bp->arr[colrow]);
1413 #ifdef DEBUG
1414 			assert(bp->arr[colrow] == 0);
1415 #endif
1416 			bp->arr[colrow] = 0;
1417 			eraseabug(mi, col, row);
1418 			bp->nbugs--;
1419 		} else {	/* try to move */
1420 			bp->arr[colrow] = 0;	/* Don't want neighbor to detect itself */
1421 			tryit = 0;
1422 			do {
1423 				if (tryit++ > ENOUGH) {
1424 					break;
1425 				}
1426 				absdir = (bp->currbug->info.direction +
1427 					  dirbug(&bp->currbug->info, bp->neighbors)) % bp->neighbors;
1428 				dir = absdir * ANGLES / bp->neighbors;
1429 				if (bp->neighbors % 2) {
1430 					if ((col + row) & 1)
1431 						dir = (3 * ANGLES / 2 - dir) % ANGLES;
1432 					else
1433 						dir = (ANGLES - dir) % ANGLES;
1434 				}
1435 			} while (!dirmove(bp, col, row, dir,
1436 			  &ncol, &nrow) || has_neighbor(bp, ncol, nrow) ||
1437 			  bp->arr[ncol + nrow * bp->ncols]);
1438 			bp->currbug->info.age++;
1439 			bp->currbug->info.energy--;
1440 			if (tryit <= ENOUGH) {
1441 				ncolrow = ncol + nrow * bp->ncols;
1442 				if (bp->bacteria[ncolrow]) {
1443 					bp->currbug->info.energy += BACTERIAENERGY;
1444 					bp->bacteria[ncolrow] = 0;
1445 					if (bp->currbug->info.energy > MAXENERGY)
1446 						bp->currbug->info.energy = MAXENERGY;
1447 				}
1448 				bp->currbug->info.col = ncol;
1449 				bp->currbug->info.row = nrow;
1450 				bp->currbug->info.direction = absdir;
1451 #ifdef DEBUG
1452 				assert(bp->arr[ncolrow] == 0);
1453 #endif
1454 				bp->arr[ncolrow] = bp->currbug;
1455 				if (bp->currbug->info.energy > STRONG &&
1456 				    bp->currbug->info.age > MATURE) {	/* breed */
1457 					drawabug(mi, ncol, nrow, bp->currbug->info.color, (int) bp->currbug->info.direction * ANGLES / bp->neighbors);
1458 					cutfrom_buglist(bp);	/* This rotates out who goes first */
1459 					bp->babybug->info.age = 0;
1460 					bp->babybug->info.energy = INITENERGY;
1461 					dupin_buglist(bp);
1462 					if (bp->firstbug == NULL) {
1463 						free_bug_screen(MI_DISPLAY(mi), bp);
1464 						return;
1465 					}
1466 					mutatebug(&bp->babybug->previous->info, bp->neighbors);
1467 					mutatebug(&bp->babybug->info, bp->neighbors);
1468 					bp->arr[colrow] = bp->babybug;
1469 					bp->babybug->info.col = col;
1470 					bp->babybug->info.row = row;
1471 					bp->nbugs++;
1472 				} else {
1473 					eraseabug(mi, col, row);
1474 					drawabug(mi, ncol, nrow, bp->currbug->info.color, (int) bp->currbug->info.direction * ANGLES / bp->neighbors);
1475 				}
1476 			} else
1477 				bp->arr[colrow] = bp->currbug;
1478 		}
1479 		bp->currbug = bp->currbug->next;
1480 	}
1481 	reattach_buglist(bp);
1482 	makebacteria(mi, FOODPERCYCLE, 0, 0, bp->ncols, bp->nrows, True);
1483 	if (bp->eden)
1484 		makebacteria(mi, FOODPERCYCLE,
1485 			bp->edenstartx, bp->edenstarty,
1486 			bp->edenwidth, bp->edenheight, True);
1487 	if (!bp->nbugs || bp->generation >= MI_CYCLES(mi))
1488 		init_bug(mi);
1489 	bp->generation++;
1490 	if (bp->redrawing) {
1491 		int         i;
1492 
1493 		for (i = 0; i < REDRAWSTEP; i++) {
1494 			if (bp->bacteria[bp->redrawpos])
1495 				redrawbacteria(mi, bp->redrawpos);
1496 			if (++(bp->redrawpos) >= bp->ncols * bp->nrows) {
1497 				bp->redrawing = 0;
1498 				break;
1499 			}
1500 		}
1501 	}
1502 }
1503 
1504 ENTRYPOINT void
release_bug(ModeInfo * mi)1505 release_bug(ModeInfo * mi)
1506 {
1507 	if (bugfarms != NULL) {
1508 		int         screen;
1509 
1510 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1511 			free_bug_screen(MI_DISPLAY(mi), &bugfarms[screen]);
1512 		free(bugfarms);
1513 		bugfarms = (bugfarmstruct *) NULL;
1514 	}
1515 }
1516 
1517 #ifndef STANDALONE
1518 ENTRYPOINT void
refresh_bug(ModeInfo * mi)1519 refresh_bug(ModeInfo * mi)
1520 {
1521 	bugfarmstruct *bp;
1522 
1523 	if (bugfarms == NULL)
1524 		return;
1525 	bp = &bugfarms[MI_SCREEN(mi)];
1526 
1527 	if (bp->painted) {
1528 		MI_CLEARWINDOW(mi);
1529 		bp->painted = False;
1530 		bp->redrawing = 1;
1531 		bp->redrawpos = 0;
1532 	}
1533 }
1534 #endif
1535 
1536 XSCREENSAVER_MODULE ("Bug", bug)
1537 
1538 #endif /* MODE_bug */
1539