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