1421 lines
35 KiB
C
1421 lines
35 KiB
C
|
/* -*- Mode: C; tab-width: 4 -*- */
|
||
|
/* bug --- Michael Palmiter's simulated evolution */
|
||
|
|
||
|
#if !defined( lint ) && !defined( SABER )
|
||
|
static const char sccsid[] = "@(#)bug.c 5.00 2000/11/01 xlockmore";
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*-
|
||
|
* Copyright (c) 1995 by David Bagley.
|
||
|
*
|
||
|
* Permission to use, copy, modify, and distribute this software and its
|
||
|
* documentation for any purpose and without fee is hereby granted,
|
||
|
* provided that the above copyright notice appear in all copies and that
|
||
|
* both that copyright notice and this permission notice appear in
|
||
|
* supporting documentation.
|
||
|
*
|
||
|
* This file is provided AS IS with no warranties of any kind. The author
|
||
|
* shall have no liability with respect to the infringement of copyrights,
|
||
|
* trade secrets or any patents by this file or any part thereof. In no
|
||
|
* event will the author be liable for any lost revenue or profits or
|
||
|
* other special, indirect and consequential damages.
|
||
|
*
|
||
|
* Revision History:
|
||
|
* 01-Nov-2000: Allocation checks
|
||
|
* 10-May-1997: Compatible with xscreensaver
|
||
|
* 24-Aug-1995: Coded from A.K. Dewdney's, "Computer Recreations", Scientific
|
||
|
* American Magazine" May 1989 pp138-141 and Sept 1989 p 183.
|
||
|
* also used wator.c as a guide.
|
||
|
*/
|
||
|
|
||
|
/*-
|
||
|
* Bugs learn to hunt bacteria (or die) in the Garden of Eden and outside.
|
||
|
* They start as jitterbugs and "evolve" to move straight (in the Garden
|
||
|
* they may evolve to twirl around).
|
||
|
*/
|
||
|
|
||
|
#ifdef STANDALONE
|
||
|
#define MODE_bug
|
||
|
#define PROGCLASS "Bug"
|
||
|
#define HACK_INIT init_bug
|
||
|
#define HACK_DRAW draw_bug
|
||
|
#define bug_opts xlockmore_opts
|
||
|
#define DEFAULTS "*delay: 75000 \n" \
|
||
|
"*count: 10 \n" \
|
||
|
"*cycles: 32767 \n" \
|
||
|
"*size: -4 \n" \
|
||
|
"*ncolors: 64 \n"
|
||
|
#include "xlockmore.h" /* in xscreensaver distribution */
|
||
|
#else /* STANDALONE */
|
||
|
#include "xlock.h" /* in xlockmore distribution */
|
||
|
|
||
|
#endif /* STANDALONE */
|
||
|
#include "automata.h"
|
||
|
|
||
|
#ifdef MODE_bug
|
||
|
|
||
|
#define DEF_NEIGHBORS "0" /* choose random value */
|
||
|
#define DEF_EYES "False"
|
||
|
|
||
|
static int neighbors;
|
||
|
static Bool eyes;
|
||
|
|
||
|
static XrmOptionDescRec opts[] =
|
||
|
{
|
||
|
{(char *) "-neighbors", (char *) ".bug.neighbors", XrmoptionSepArg, (caddr_t) NULL},
|
||
|
{(char *) "-eyes", (char *) ".bug.eyes", XrmoptionNoArg, (caddr_t) "on"},
|
||
|
{(char *) "+eyes", (char *) ".bug.eyes", XrmoptionNoArg, (caddr_t) "off"},
|
||
|
};
|
||
|
static argtype vars[] =
|
||
|
{
|
||
|
{(void *) & neighbors, (char *) "neighbors", (char *) "Neighbors", (char *) DEF_NEIGHBORS, t_Int},
|
||
|
{(void *) & eyes, (char *) "eyes", (char *) "Eyes", (char *) DEF_EYES, t_Bool},
|
||
|
};
|
||
|
static OptionStruct desc[] =
|
||
|
{
|
||
|
{(char *) "-neighbors num", (char *) "squares 4 or 8, hexagons 6"},
|
||
|
{(char *) "-/+eyes", (char *) "turn on/off eyes"}
|
||
|
};
|
||
|
|
||
|
ModeSpecOpt bug_opts =
|
||
|
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
|
||
|
|
||
|
|
||
|
#ifdef USE_MODULES
|
||
|
ModStruct bug_description =
|
||
|
{"bug", "init_bug", "draw_bug", "release_bug",
|
||
|
"refresh_bug", "init_bug", (char *) NULL, &bug_opts,
|
||
|
75000, 10, 32767, -4, 64, 1.0, "",
|
||
|
"Shows Palmiter's bug evolution and garden of Eden", 0, NULL};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
#include <assert.h>
|
||
|
#endif
|
||
|
|
||
|
#define BUGBITS(n,w,h)\
|
||
|
if ((bp->pixmaps[bp->init_bits]=\
|
||
|
XCreatePixmapFromBitmapData(display,window,(char *)n,w,h,1,0,1))==None){\
|
||
|
free_bug(display,bp); return;} else {bp->init_bits++;}
|
||
|
|
||
|
#define BACTERIA 0
|
||
|
#define BUG 1
|
||
|
|
||
|
#define MAXENERGY 1500 /* Max energy storage */
|
||
|
#define INITENERGY 400 /* Initial energy */
|
||
|
#define FOODPERCYCLE 1
|
||
|
#define BACTERIAENERGY 40
|
||
|
#define STRONG 1000 /* Min energy to breed */
|
||
|
#define MATURE 800 /* Breeding time of bugs */
|
||
|
#define MAXGENE 6
|
||
|
#define MINGENE (-MAXGENE)
|
||
|
#define REDRAWSTEP 2000 /* How many bacteria to draw per cycle */
|
||
|
#define MINGRIDSIZE 24
|
||
|
#define MINSIZE 1
|
||
|
#define ANGLES 360
|
||
|
#define MAXNEIGHBORS 12
|
||
|
|
||
|
/* Relative hex bug moves */
|
||
|
/* Forward, Right, Hard Right, Reverse, Hard Left, Left */
|
||
|
|
||
|
/* Bug data */
|
||
|
typedef struct {
|
||
|
char direction;
|
||
|
int age, energy;
|
||
|
unsigned int color;
|
||
|
int col, row;
|
||
|
int gene[MAXNEIGHBORS];
|
||
|
double gene_prob[MAXNEIGHBORS];
|
||
|
#if EXTRA_GENES
|
||
|
int lgene[MAXNEIGHBORS];
|
||
|
double lgene_prob[MAXNEIGHBORS];
|
||
|
#endif
|
||
|
} bugstruct;
|
||
|
|
||
|
/* Doublely linked list */
|
||
|
typedef struct _BugList {
|
||
|
bugstruct info;
|
||
|
struct _BugList *previous, *next;
|
||
|
} BugList;
|
||
|
|
||
|
typedef struct {
|
||
|
Bool painted;
|
||
|
int neighbors;
|
||
|
int nbugs; /* Number of bugs */
|
||
|
int eden; /* Does the garden exist? */
|
||
|
int generation;
|
||
|
int ncols, nrows;
|
||
|
int width, height;
|
||
|
int edenwidth, edenheight;
|
||
|
int edenstartx, edenstarty;
|
||
|
int xs, ys, xb, yb;
|
||
|
int redrawing, redrawpos;
|
||
|
int eyes;
|
||
|
BugList *currbug, *babybug, *lastbug, *firstbug, *lasttemp, *firsttemp;
|
||
|
BugList **arr; /* 0=empty or pts to a bug */
|
||
|
char *bacteria; /* 0=empty or food */
|
||
|
int init_bits;
|
||
|
GC stippledGC;
|
||
|
Pixmap pixmaps[NUMSTIPPLES - 1];
|
||
|
union {
|
||
|
XPoint hexagon[6];
|
||
|
XPoint triangle[2][3];
|
||
|
} shape;
|
||
|
} bugfarmstruct;
|
||
|
|
||
|
static double genexp[MAXGENE - MINGENE + 1];
|
||
|
|
||
|
static char plots[] =
|
||
|
{3, 4, 6, 8,
|
||
|
#ifdef NUMBER_9
|
||
|
9,
|
||
|
#endif
|
||
|
12}; /* Neighborhoods */
|
||
|
|
||
|
#define NEIGHBORKINDS (long) (sizeof plots / sizeof *plots)
|
||
|
|
||
|
static bugfarmstruct *bugfarms = (bugfarmstruct *) NULL;
|
||
|
|
||
|
#if 0
|
||
|
static void
|
||
|
position_of_neighbor(bugfarmstruct * bp, int dir, int *pcol, int *prow)
|
||
|
{
|
||
|
int col = *pcol, row = *prow;
|
||
|
|
||
|
/* NO WRAPING */
|
||
|
|
||
|
if (bp->neighbors == 4 || bp->neighbors == 6 || bp->neighbors == 8) {
|
||
|
switch (dir) {
|
||
|
case 0:
|
||
|
col = col + 1;
|
||
|
break;
|
||
|
case 45:
|
||
|
col = col + 1;
|
||
|
row = row - 1;
|
||
|
break;
|
||
|
case 60:
|
||
|
if (!(row & 1))
|
||
|
col = col + 1;
|
||
|
row = row - 1;
|
||
|
break;
|
||
|
case 90:
|
||
|
row = row - 1;
|
||
|
break;
|
||
|
case 120:
|
||
|
if (row & 1)
|
||
|
col = col - 1;
|
||
|
row = row - 1;
|
||
|
break;
|
||
|
case 135:
|
||
|
col = col - 1;
|
||
|
row = row - 1;
|
||
|
break;
|
||
|
case 180:
|
||
|
col = col - 1;
|
||
|
break;
|
||
|
case 225:
|
||
|
col = col - 1;
|
||
|
row = row + 1;
|
||
|
break;
|
||
|
case 240:
|
||
|
if (row & 1)
|
||
|
col = col - 1;
|
||
|
row = row + 1;
|
||
|
break;
|
||
|
case 270:
|
||
|
row = row + 1;
|
||
|
break;
|
||
|
case 300:
|
||
|
if (!(row & 1))
|
||
|
col = col + 1;
|
||
|
row = row + 1;
|
||
|
break;
|
||
|
case 315:
|
||
|
col = col + 1;
|
||
|
row = row + 1;
|
||
|
break;
|
||
|
default:
|
||
|
(void) fprintf(stderr, "wrong direction %d\n", dir);
|
||
|
}
|
||
|
} else { /* TRI */
|
||
|
switch (dir) {
|
||
|
case 0:
|
||
|
col = col + 1;
|
||
|
break;
|
||
|
case 20:
|
||
|
case 30:
|
||
|
case 40:
|
||
|
col = col + 1;
|
||
|
row = row - 1;
|
||
|
break;
|
||
|
case 60:
|
||
|
if ((col + row) % 2) { /* right */
|
||
|
row = row - 1;
|
||
|
} else { /* left */
|
||
|
col = col + 1;
|
||
|
row = row - 2;
|
||
|
}
|
||
|
break;
|
||
|
case 80:
|
||
|
case 90:
|
||
|
case 100:
|
||
|
row = row - 2;
|
||
|
break;
|
||
|
case 120:
|
||
|
if ((col + row) % 2) { /* right */
|
||
|
col = col - 1;
|
||
|
row = row - 2;
|
||
|
} else { /* left */
|
||
|
row = row - 1;
|
||
|
}
|
||
|
break;
|
||
|
case 140:
|
||
|
case 150:
|
||
|
case 160:
|
||
|
col = col - 1;
|
||
|
row = row - 1;
|
||
|
break;
|
||
|
case 180:
|
||
|
col = col - 1;
|
||
|
break;
|
||
|
case 200:
|
||
|
case 210:
|
||
|
case 220:
|
||
|
col = col - 1;
|
||
|
row = row + 1;
|
||
|
break;
|
||
|
case 240:
|
||
|
if ((col + row) % 2) { /* right */
|
||
|
col = col - 1;
|
||
|
row = row + 2;
|
||
|
} else { /* left */
|
||
|
row = row + 1;
|
||
|
}
|
||
|
break;
|
||
|
case 260:
|
||
|
case 270:
|
||
|
case 280:
|
||
|
row = row + 2;
|
||
|
break;
|
||
|
case 300:
|
||
|
if ((col + row) % 2) { /* right */
|
||
|
row = row + 1;
|
||
|
} else { /* left */
|
||
|
col = col + 1;
|
||
|
row = row + 2;
|
||
|
}
|
||
|
break;
|
||
|
case 320:
|
||
|
case 330:
|
||
|
case 340:
|
||
|
col = col + 1;
|
||
|
row = row + 1;
|
||
|
break;
|
||
|
default:
|
||
|
(void) fprintf(stderr, "wrong direction %d\n", dir);
|
||
|
}
|
||
|
}
|
||
|
*pcol = col;
|
||
|
*prow = row;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#if 0
|
||
|
static void
|
||
|
screen2grid(bugfarmstruct *bp, int sx, int sy, int x, int y)
|
||
|
{
|
||
|
*y = sy / 2;
|
||
|
if (bp->neighbors == 6) {
|
||
|
*x = (sx + 1) / 2 - 1;
|
||
|
} else if (bp->neighbors == 4 || bp->neighbors == 8) {
|
||
|
*x = sx / 2;
|
||
|
} else { /* TRI */
|
||
|
/* Wrong but... */
|
||
|
*x = sx / 3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
static void
|
||
|
grid2screen(bugfarmstruct *bp, int x, int y, int *sx, int *sy)
|
||
|
{
|
||
|
*sy = y * 2 + 1;
|
||
|
if (bp->neighbors == 6) {
|
||
|
*sx = 2 * x + 1 + !(y & 1);
|
||
|
} else if (bp->neighbors == 4 || bp->neighbors == 8) {
|
||
|
*sx = x * 2 + 1;
|
||
|
} else { /* TRI */
|
||
|
*sx = x * 3 + 1 + ((y & 1) ? (x & 1) : !(x & 1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static char
|
||
|
dirmove(bugfarmstruct * bp, int x, int y, int dir, int *nx, int *ny)
|
||
|
{
|
||
|
if (bp->neighbors == 6) {
|
||
|
switch (dir) {
|
||
|
case 0:
|
||
|
*ny = y;
|
||
|
*nx = x + 1;
|
||
|
return (*nx < bp->ncols - !(*ny & 1));
|
||
|
case 60:
|
||
|
*ny = y - 1;
|
||
|
*nx = x + (int) !(y & 1);
|
||
|
return (*ny >= 0 && *nx < bp->ncols - !(*ny & 1));
|
||
|
case 120:
|
||
|
*ny = y - 1;
|
||
|
*nx = x - (int) (y & 1);
|
||
|
return (*ny >= 0 && *nx >= 0);
|
||
|
case 180:
|
||
|
*ny = y;
|
||
|
*nx = x - 1;
|
||
|
return (*nx >= 0);
|
||
|
case 240:
|
||
|
*ny = y + 1;
|
||
|
*nx = x - (int) (y & 1);
|
||
|
return (*ny < bp->nrows && *nx >= 0);
|
||
|
case 300:
|
||
|
*ny = y + 1;
|
||
|
*nx = x + (int) !(y & 1);
|
||
|
return (*ny < bp->nrows && *nx < bp->ncols - !(*ny & 1));
|
||
|
default:
|
||
|
(void) fprintf(stderr, "wrong direction %d\n", dir);
|
||
|
}
|
||
|
} else if (bp->neighbors == 4 || bp->neighbors == 8) {
|
||
|
switch (dir) {
|
||
|
case 0:
|
||
|
*ny = y;
|
||
|
*nx = x + 1;
|
||
|
return (*nx < bp->ncols);
|
||
|
case 45:
|
||
|
*ny = y - 1;
|
||
|
*nx = x + 1;
|
||
|
return (*ny >= 0 && *nx < bp->ncols);
|
||
|
case 90:
|
||
|
*ny = y - 1;
|
||
|
*nx = x;
|
||
|
return (*ny >= 0);
|
||
|
case 135:
|
||
|
*ny = y - 1;
|
||
|
*nx = x - 1;
|
||
|
return (*ny >= 0 && *nx >= 0);
|
||
|
case 180:
|
||
|
*ny = y;
|
||
|
*nx = x - 1;
|
||
|
return (*nx >= 0);
|
||
|
case 225:
|
||
|
*ny = y + 1;
|
||
|
*nx = x - 1;
|
||
|
return (*ny < bp->nrows && *nx >= 0);
|
||
|
case 270:
|
||
|
*ny = y + 1;
|
||
|
*nx = x;
|
||
|
return (*ny < bp->nrows);
|
||
|
case 315:
|
||
|
*ny = y + 1;
|
||
|
*nx = x + 1;
|
||
|
return (*ny < bp->nrows && *nx < bp->ncols);
|
||
|
default:
|
||
|
(void) fprintf(stderr, "wrong direction %d\n", dir);
|
||
|
}
|
||
|
} else { /* TRI */
|
||
|
switch (dir) {
|
||
|
case 0:
|
||
|
*nx = x + 1;
|
||
|
*ny = y;
|
||
|
return (*nx < bp->ncols);
|
||
|
case 20:
|
||
|
case 30:
|
||
|
case 40:
|
||
|
*nx = x + 1;
|
||
|
*ny = y - 1;
|
||
|
return (*nx < bp->ncols && *ny >= 0);
|
||
|
case 60:
|
||
|
if ((x + y) % 2) { /* right */
|
||
|
*nx = x;
|
||
|
*ny = y - 1;
|
||
|
return (*ny >= 0);
|
||
|
} else { /* left */
|
||
|
*nx = x + 1;
|
||
|
*ny = y - 2;
|
||
|
return (*nx < bp->ncols && *ny >= 0);
|
||
|
}
|
||
|
case 80:
|
||
|
case 90:
|
||
|
case 100:
|
||
|
*nx = x;
|
||
|
*ny = y - 2;
|
||
|
return (*ny >= 0);
|
||
|
case 120:
|
||
|
if ((x + y) % 2) { /* right */
|
||
|
*nx = x - 1;
|
||
|
*ny = y - 2;
|
||
|
return (*nx >= 0 && *ny >= 0);
|
||
|
} else { /* left */
|
||
|
*nx = x;
|
||
|
*ny = y - 1;
|
||
|
return (*ny >= 0);
|
||
|
}
|
||
|
case 140:
|
||
|
case 150:
|
||
|
case 160:
|
||
|
*nx = x - 1;
|
||
|
*ny = y - 1;
|
||
|
return (*nx >= 0 && *ny >= 0);
|
||
|
case 180:
|
||
|
*nx = x - 1;
|
||
|
*ny = y;
|
||
|
return (*nx >= 0);
|
||
|
case 200:
|
||
|
case 210:
|
||
|
case 220:
|
||
|
*nx = x - 1;
|
||
|
*ny = y + 1;
|
||
|
return (*nx >= 0 && *ny < bp->nrows);
|
||
|
case 240:
|
||
|
if ((x + y) % 2) { /* right */
|
||
|
*nx = x - 1;
|
||
|
*ny = y + 2;
|
||
|
return (*nx >= 0 && *ny < bp->nrows);
|
||
|
} else { /* left */
|
||
|
*nx = x;
|
||
|
*ny = y + 1;
|
||
|
return (*ny < bp->nrows);
|
||
|
}
|
||
|
case 260:
|
||
|
case 270:
|
||
|
case 280:
|
||
|
*nx = x;
|
||
|
*ny = y + 2;
|
||
|
return (*ny < bp->nrows);
|
||
|
case 300:
|
||
|
if ((x + y) % 2) { /* right */
|
||
|
*nx = x;
|
||
|
*ny = y + 1;
|
||
|
return (*ny < bp->nrows);
|
||
|
} else { /* left */
|
||
|
*nx = x + 1;
|
||
|
*ny = y + 2;
|
||
|
return (*nx < bp->ncols && *ny < bp->nrows);
|
||
|
}
|
||
|
case 320:
|
||
|
case 330:
|
||
|
case 340:
|
||
|
*nx = x + 1;
|
||
|
*ny = y + 1;
|
||
|
return (*nx < bp->ncols && *ny < bp->nrows);
|
||
|
default:
|
||
|
(void) fprintf(stderr, "wrong direction %d\n", dir);
|
||
|
}
|
||
|
}
|
||
|
*nx = -1;
|
||
|
*ny = -1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* This keeps bugs from walking over each other and escaping off the screen */
|
||
|
static int
|
||
|
has_neighbor(bugfarmstruct * bp, int col, int row)
|
||
|
{
|
||
|
int colrow = col + row * bp->ncols;
|
||
|
|
||
|
if (bp->neighbors == 6) {
|
||
|
if ((row > 0) && bp->arr[colrow - bp->ncols])
|
||
|
return True;
|
||
|
if ((row < bp->nrows - 1) && bp->arr[colrow + bp->ncols])
|
||
|
return True;
|
||
|
if (col > 0) {
|
||
|
if (bp->arr[colrow - 1])
|
||
|
return True;
|
||
|
if (row & 1) {
|
||
|
if ((row > 0) && bp->arr[colrow - 1 - bp->ncols])
|
||
|
return True;
|
||
|
if ((row < bp->nrows - 1) && bp->arr[colrow - 1 + bp->ncols])
|
||
|
return True;
|
||
|
}
|
||
|
}
|
||
|
if (col < bp->ncols - 1) {
|
||
|
if (bp->arr[colrow + 1])
|
||
|
return True;
|
||
|
if (!(row & 1)) {
|
||
|
if ((row > 0) && bp->arr[colrow + 1 - bp->ncols])
|
||
|
return True;
|
||
|
if ((row < bp->nrows - 1) && bp->arr[colrow + 1 + bp->ncols])
|
||
|
return True;
|
||
|
}
|
||
|
}
|
||
|
} else if (bp->neighbors == 4 || bp->neighbors == 8) {
|
||
|
/* Same for both because the bug square takes up the space regardless */
|
||
|
if ((row > 0) && bp->arr[colrow - bp->ncols])
|
||
|
return True;
|
||
|
if ((row < bp->nrows - 1) && bp->arr[colrow + bp->ncols])
|
||
|
return True;
|
||
|
if ((col > 0) && bp->arr[colrow - 1])
|
||
|
return True;
|
||
|
if ((col < bp->ncols - 1) && bp->arr[colrow + 1])
|
||
|
return True;
|
||
|
if (row > 0 && col > 0 && bp->arr[colrow - bp->ncols - 1])
|
||
|
return True;
|
||
|
if (row > 0 && col < bp->ncols - 1 && bp->arr[colrow - bp->ncols + 1])
|
||
|
return True;
|
||
|
if (row < bp->nrows - 1 && col > 0 && bp->arr[colrow + bp->ncols - 1])
|
||
|
return True;
|
||
|
if (row < bp->nrows - 1 && col < bp->ncols - 1 && bp->arr[colrow + bp->ncols + 1])
|
||
|
return True;
|
||
|
} else { /* TRI */
|
||
|
/* Same for all three neighbor kinds. Only care about 3
|
||
|
adjacent spots because that is all the squares will
|
||
|
overlap.*/
|
||
|
if (((row & 1) && (col & 1)) || ((!(row & 1)) && (!(col & 1)))) {
|
||
|
if ((col < bp->ncols - 1) && bp->arr[colrow + 1])
|
||
|
return True;
|
||
|
} else {
|
||
|
if ((col > 0) && bp->arr[colrow - 1])
|
||
|
return True;
|
||
|
}
|
||
|
if ((row > 0) && bp->arr[colrow - bp->ncols])
|
||
|
return True;
|
||
|
if ((row < bp->nrows - 1) && bp->arr[colrow + bp->ncols])
|
||
|
return True;
|
||
|
}
|
||
|
return False;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
drawabacterium(ModeInfo * mi, int col, int row, unsigned char color)
|
||
|
{
|
||
|
bugfarmstruct *bp = &bugfarms[MI_SCREEN(mi)];
|
||
|
int ccol, crow;
|
||
|
|
||
|
if (color)
|
||
|
XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
|
||
|
else
|
||
|
XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
|
||
|
grid2screen(bp, col, row, &ccol, &crow);
|
||
|
XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
|
||
|
bp->xb + bp->xs * ccol, bp->yb + bp->ys * crow,
|
||
|
bp->xs, bp->ys);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
drawabug(ModeInfo * mi, int col, int row, unsigned int color, int direction)
|
||
|
{
|
||
|
bugfarmstruct *bp = &bugfarms[MI_SCREEN(mi)];
|
||
|
Display *display = MI_DISPLAY(mi);
|
||
|
Window window = MI_WINDOW(mi);
|
||
|
int ccol, crow;
|
||
|
GC gc;
|
||
|
|
||
|
if (MI_NPIXELS(mi) > 3) {
|
||
|
XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, color));
|
||
|
gc = MI_GC(mi);
|
||
|
} else {
|
||
|
XGCValues gcv;
|
||
|
|
||
|
gcv.stipple = bp->pixmaps[color];
|
||
|
gcv.foreground = MI_WHITE_PIXEL(mi);
|
||
|
gcv.background = MI_BLACK_PIXEL(mi);
|
||
|
XChangeGC(MI_DISPLAY(mi), bp->stippledGC,
|
||
|
GCStipple | GCForeground | GCBackground, &gcv);
|
||
|
gc = bp->stippledGC;
|
||
|
}
|
||
|
|
||
|
grid2screen(bp, col, row, &ccol, &crow);
|
||
|
ccol = bp->xb + bp->xs * (ccol - 1);
|
||
|
crow = bp->yb + bp->ys * (crow - 1);
|
||
|
XFillRectangle(display, window, gc,
|
||
|
ccol, crow, 3 * bp->xs, 3 * bp->ys);
|
||
|
|
||
|
if (bp->eyes && bp->xs >= 1 && bp->ys >= 1) { /* Draw Eyes */
|
||
|
XSetForeground(display, MI_GC(mi), MI_BLACK_PIXEL(mi));
|
||
|
switch (direction) {
|
||
|
case 0:
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 3 * bp->xs - 2,
|
||
|
crow + 3 * bp->ys / 2 - 1);
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 3 * bp->xs - 2,
|
||
|
crow + 3 * bp->ys / 2 + 1);
|
||
|
break;
|
||
|
case 20:
|
||
|
case 30:
|
||
|
case 40:
|
||
|
case 45:
|
||
|
case 60:
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 3 * bp->xs - 3,
|
||
|
crow + 1);
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 3 * bp->xs - 2,
|
||
|
crow + 2);
|
||
|
break;
|
||
|
case 80:
|
||
|
case 90:
|
||
|
case 100:
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 3 * bp->xs / 2 - 1,
|
||
|
crow + 1);
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 3 * bp->xs / 2 + 1,
|
||
|
crow + 1);
|
||
|
break;
|
||
|
case 120:
|
||
|
case 135:
|
||
|
case 140:
|
||
|
case 150:
|
||
|
case 160:
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 2,
|
||
|
crow + 1);
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 1,
|
||
|
crow + 2);
|
||
|
break;
|
||
|
case 180:
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 1,
|
||
|
crow + 3 * bp->ys / 2 - 1);
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 1,
|
||
|
crow + 3 * bp->ys / 2 + 1);
|
||
|
break;
|
||
|
case 200:
|
||
|
case 210:
|
||
|
case 220:
|
||
|
case 225:
|
||
|
case 240:
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 2,
|
||
|
crow + 3 * bp->ys - 2);
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 1,
|
||
|
crow + 3 * bp->ys - 3);
|
||
|
break;
|
||
|
case 260:
|
||
|
case 270:
|
||
|
case 280:
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 3 * bp->xs / 2 - 1,
|
||
|
crow + 3 * bp->ys - 2);
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 3 * bp->xs / 2 + 1,
|
||
|
crow + 3 * bp->ys - 2);
|
||
|
break;
|
||
|
case 300:
|
||
|
case 315:
|
||
|
case 320:
|
||
|
case 330:
|
||
|
case 340:
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 3 * bp->xs - 3,
|
||
|
crow + 3 * bp->ys - 2);
|
||
|
XDrawPoint(display, window, MI_GC(mi),
|
||
|
ccol + 3 * bp->xs - 2,
|
||
|
crow + 3 * bp->ys - 3);
|
||
|
break;
|
||
|
default:
|
||
|
(void) fprintf(stderr, "wrong direction %d\n", direction);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
eraseabug(ModeInfo * mi, int col, int row)
|
||
|
{
|
||
|
bugfarmstruct *bp = &bugfarms[MI_SCREEN(mi)];
|
||
|
int ccol, crow;
|
||
|
|
||
|
XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_BLACK_PIXEL(mi));
|
||
|
grid2screen(bp, col, row, &ccol, &crow);
|
||
|
XFillRectangle(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi),
|
||
|
bp->xb + bp->xs * (ccol - 1), bp->yb + bp->ys * (crow - 1),
|
||
|
3 * bp->xs, 3 * bp->ys);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
flush_buglist(bugfarmstruct * bp)
|
||
|
{
|
||
|
while (bp->lastbug->previous != bp->firstbug) {
|
||
|
bp->currbug = bp->lastbug->previous;
|
||
|
bp->currbug->previous->next = bp->lastbug;
|
||
|
bp->lastbug->previous = bp->currbug->previous;
|
||
|
/*bp->arr[bp->currbug->info.col + bp->currbug->info.row * bp->ncols] = 0; */
|
||
|
free(bp->currbug);
|
||
|
}
|
||
|
|
||
|
while (bp->lasttemp->previous != bp->firsttemp) {
|
||
|
bp->currbug = bp->lasttemp->previous;
|
||
|
bp->currbug->previous->next = bp->lasttemp;
|
||
|
bp->lasttemp->previous = bp->currbug->previous;
|
||
|
/*bp->arr[bp->currbug->info.col + bp->currbug->info.row * bp->ncols] = 0; */
|
||
|
free(bp->currbug);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
free_buglist(bugfarmstruct *bp)
|
||
|
{
|
||
|
if (bp->firstbug != NULL) {
|
||
|
flush_buglist(bp);
|
||
|
free(bp->firstbug);
|
||
|
bp->firstbug = (BugList *) NULL;
|
||
|
}
|
||
|
if (bp->lastbug != NULL) {
|
||
|
free(bp->lastbug);
|
||
|
bp->lastbug = (BugList *) NULL;
|
||
|
}
|
||
|
if (bp->lasttemp != NULL) {
|
||
|
free(bp->lasttemp);
|
||
|
bp->lasttemp = (BugList *) NULL;
|
||
|
}
|
||
|
if (bp->firsttemp != NULL) {
|
||
|
free(bp->firsttemp);
|
||
|
bp->firsttemp = (BugList *) NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static Bool
|
||
|
init_buglist(bugfarmstruct * bp)
|
||
|
{
|
||
|
/* Waste some space at the beginning and end of list
|
||
|
so we do not have to complicated checks against falling off the ends. */
|
||
|
if ((bp->lastbug = (BugList *) malloc(sizeof (BugList))) == NULL) {
|
||
|
free_buglist(bp);
|
||
|
return False;
|
||
|
}
|
||
|
if ((bp->firstbug = (BugList *) malloc(sizeof (BugList))) == NULL) {
|
||
|
free_buglist(bp);
|
||
|
return False;
|
||
|
}
|
||
|
bp->firstbug->previous = bp->lastbug->next = (struct _BugList *) NULL;
|
||
|
bp->firstbug->next = bp->lastbug->previous = (struct _BugList *) NULL;
|
||
|
bp->firstbug->next = bp->lastbug;
|
||
|
bp->lastbug->previous = bp->firstbug;
|
||
|
|
||
|
if ((bp->lasttemp = (BugList *) malloc(sizeof (BugList))) == NULL) {
|
||
|
free_buglist(bp);
|
||
|
return False;
|
||
|
}
|
||
|
if ((bp->firsttemp = (BugList *) malloc(sizeof (BugList))) == NULL) {
|
||
|
free_buglist(bp);
|
||
|
return False;
|
||
|
}
|
||
|
bp->firsttemp->previous = bp->lasttemp->next = (struct _BugList *) NULL;
|
||
|
bp->firsttemp->next = bp->lasttemp->previous = (struct _BugList *) NULL;
|
||
|
bp->firsttemp->next = bp->lasttemp;
|
||
|
bp->lasttemp->previous = bp->firsttemp;
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
addto_buglist(bugfarmstruct * bp, bugstruct info)
|
||
|
{
|
||
|
if ((bp->currbug = (BugList *) malloc(sizeof (BugList))) == NULL) {
|
||
|
free_buglist(bp);
|
||
|
return;
|
||
|
}
|
||
|
bp->lastbug->previous->next = bp->currbug;
|
||
|
bp->currbug->previous = bp->lastbug->previous;
|
||
|
bp->currbug->next = bp->lastbug;
|
||
|
bp->lastbug->previous = bp->currbug;
|
||
|
bp->currbug->info = info;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
removefrom_buglist(bugfarmstruct * bp, BugList * ptr)
|
||
|
{
|
||
|
ptr->previous->next = ptr->next;
|
||
|
ptr->next->previous = ptr->previous;
|
||
|
bp->arr[ptr->info.col + ptr->info.row * bp->ncols] = 0;
|
||
|
free(ptr);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
dupin_buglist(bugfarmstruct * bp)
|
||
|
{
|
||
|
BugList *temp;
|
||
|
|
||
|
if ((temp = (BugList *) malloc(sizeof (BugList))) == NULL) {
|
||
|
free_buglist(bp);
|
||
|
return;
|
||
|
}
|
||
|
temp->previous = bp->babybug;
|
||
|
temp->next = bp->babybug->next;
|
||
|
bp->babybug->next = temp;
|
||
|
temp->next->previous = temp;
|
||
|
temp->info = bp->babybug->info;
|
||
|
bp->babybug = temp;
|
||
|
}
|
||
|
|
||
|
/*-
|
||
|
* new bug at end of list, this rotates who goes first, young bugs go last
|
||
|
* this most likely will not change the feel to any real degree
|
||
|
*/
|
||
|
static void
|
||
|
cutfrom_buglist(bugfarmstruct * bp)
|
||
|
{
|
||
|
bp->babybug = bp->currbug;
|
||
|
bp->currbug = bp->currbug->previous;
|
||
|
bp->currbug->next = bp->babybug->next;
|
||
|
bp->babybug->next->previous = bp->currbug;
|
||
|
bp->babybug->next = bp->lasttemp;
|
||
|
bp->babybug->previous = bp->lasttemp->previous;
|
||
|
bp->babybug->previous->next = bp->babybug;
|
||
|
bp->babybug->next->previous = bp->babybug;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
reattach_buglist(bugfarmstruct * bp)
|
||
|
{
|
||
|
bp->currbug = bp->lastbug->previous;
|
||
|
bp->currbug->next = bp->firsttemp->next;
|
||
|
bp->currbug->next->previous = bp->currbug;
|
||
|
bp->lastbug->previous = bp->lasttemp->previous;
|
||
|
bp->lasttemp->previous->next = bp->lastbug;
|
||
|
bp->lasttemp->previous = bp->firsttemp;
|
||
|
bp->firsttemp->next = bp->lasttemp;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
dirbug(bugstruct * info, int local_neighbors)
|
||
|
{
|
||
|
double sum = 0.0, prob;
|
||
|
int i;
|
||
|
|
||
|
prob = (double) LRAND() / MAXRAND;
|
||
|
#if EXTRA_GENES
|
||
|
if ((local_neighbors % 2) && !((info->col + info->row) & 1)) {
|
||
|
for (i = 0; i < local_neighbors; i++) {
|
||
|
sum += info->lgene_prob[i];
|
||
|
if (prob < sum)
|
||
|
return i;
|
||
|
}
|
||
|
} else
|
||
|
#endif
|
||
|
{
|
||
|
for (i = 0; i < local_neighbors; i++) {
|
||
|
sum += info->gene_prob[i];
|
||
|
if (prob < sum)
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
return local_neighbors - 1; /* Could miss due to rounding */
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
mutatebug(bugstruct * info, int local_neighbors)
|
||
|
{
|
||
|
double sum = 0.0;
|
||
|
int gene;
|
||
|
|
||
|
gene = NRAND(local_neighbors);
|
||
|
if (LRAND() & 1) {
|
||
|
if (info->gene[gene] == MAXGENE)
|
||
|
return;
|
||
|
info->gene[gene]++;
|
||
|
} else {
|
||
|
if (info->gene[gene] == MINGENE)
|
||
|
return;
|
||
|
info->gene[gene]--;
|
||
|
}
|
||
|
for (gene = 0; gene < local_neighbors; gene++)
|
||
|
sum += genexp[info->gene[gene] + MAXGENE];
|
||
|
for (gene = 0; gene < local_neighbors; gene++)
|
||
|
info->gene_prob[gene] = genexp[info->gene[gene] + MAXGENE] / sum;
|
||
|
#if EXTRA_GENES
|
||
|
if (local_neighbors % 2) {
|
||
|
sum = 0.0;
|
||
|
gene = NRAND(local_neighbors);
|
||
|
if (LRAND() & 1) {
|
||
|
if (info->lgene[gene] == MAXGENE)
|
||
|
return;
|
||
|
info->lgene[gene]++;
|
||
|
} else {
|
||
|
if (info->lgene[gene] == MINGENE)
|
||
|
return;
|
||
|
info->lgene[gene]--;
|
||
|
}
|
||
|
for (gene = 0; gene < local_neighbors; gene++)
|
||
|
sum += genexp[info->lgene[gene] + MAXGENE];
|
||
|
for (gene = 0; gene < local_neighbors; gene++)
|
||
|
info->lgene_prob[gene] = genexp[info->lgene[gene] + MAXGENE] / sum;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
makebacteria(ModeInfo * mi,
|
||
|
int n, int startx, int starty, int width, int height, Bool draw)
|
||
|
{
|
||
|
int nbacteria = 0, ntries = 0, col, row, colrow;
|
||
|
bugfarmstruct *bp = &bugfarms[MI_SCREEN(mi)];
|
||
|
|
||
|
/* Make bacteria but if can not, exit */
|
||
|
while (nbacteria < n && ntries < 2 * n) {
|
||
|
row = NRAND(height) + starty;
|
||
|
if (bp->neighbors == 6) {
|
||
|
if (width - (!(row & 1)) > 0)
|
||
|
col = NRAND(width - (!(row & 1))) + startx;
|
||
|
else
|
||
|
col = startx;
|
||
|
} else { /* RECT or TRI */
|
||
|
col = NRAND(width) + startx;
|
||
|
}
|
||
|
colrow = col + row * bp->ncols;
|
||
|
ntries++;
|
||
|
if (!bp->arr[colrow] && !bp->bacteria[colrow]) {
|
||
|
nbacteria++;
|
||
|
bp->bacteria[colrow] = True;
|
||
|
drawabacterium(mi, col, row, draw);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
redrawbacteria(ModeInfo * mi, int colrow)
|
||
|
{
|
||
|
int col, row;
|
||
|
bugfarmstruct *bp = &bugfarms[MI_SCREEN(mi)];
|
||
|
|
||
|
if (!bp->bacteria[colrow])
|
||
|
return;
|
||
|
|
||
|
row = colrow / bp->ncols;
|
||
|
col = colrow % bp->ncols;
|
||
|
drawabacterium(mi, col, row, True);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
free_bug(Display *display, bugfarmstruct *bp)
|
||
|
{
|
||
|
int shade;
|
||
|
|
||
|
if (bp->stippledGC != None) {
|
||
|
XFreeGC(display, bp->stippledGC);
|
||
|
bp->stippledGC = None;
|
||
|
}
|
||
|
for (shade = 0; shade < bp->init_bits; shade++) {
|
||
|
if (bp->pixmaps[shade] != None) {
|
||
|
XFreePixmap(display, bp->pixmaps[shade]);
|
||
|
bp->pixmaps[shade] = None;
|
||
|
}
|
||
|
}
|
||
|
bp->init_bits = 0;
|
||
|
if (bp->firstbug != NULL) {
|
||
|
flush_buglist(bp);
|
||
|
free(bp->firstbug);
|
||
|
bp->firstbug = (BugList *) NULL;
|
||
|
}
|
||
|
if (bp->lastbug != NULL) {
|
||
|
free(bp->lastbug);
|
||
|
bp->lastbug = (BugList *) NULL;
|
||
|
}
|
||
|
if (bp->lasttemp != NULL) {
|
||
|
free(bp->lasttemp);
|
||
|
bp->lasttemp = (BugList *) NULL;
|
||
|
}
|
||
|
if (bp->firsttemp != NULL) {
|
||
|
free(bp->firsttemp);
|
||
|
bp->firsttemp = (BugList *) NULL;
|
||
|
}
|
||
|
if (bp->arr != NULL) {
|
||
|
free(bp->arr);
|
||
|
bp->arr = (BugList **) NULL;
|
||
|
}
|
||
|
if (bp->bacteria != NULL) {
|
||
|
free(bp->bacteria);
|
||
|
bp->bacteria = (char *) NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
init_bug(ModeInfo * mi)
|
||
|
{
|
||
|
Display *display = MI_DISPLAY(mi);
|
||
|
Window window = MI_WINDOW(mi);
|
||
|
int size = MI_SIZE(mi);
|
||
|
XGCValues gcv;
|
||
|
int nbugs = 0, ntries = 0, col = 0, row, gene, colrow, i;
|
||
|
int nccols, ncrows;
|
||
|
double sum;
|
||
|
bugstruct info;
|
||
|
bugfarmstruct *bp;
|
||
|
|
||
|
if (bugfarms == NULL) {
|
||
|
if ((bugfarms = (bugfarmstruct *) calloc(MI_NUM_SCREENS(mi),
|
||
|
sizeof (bugfarmstruct))) == NULL)
|
||
|
return;
|
||
|
}
|
||
|
bp = &bugfarms[MI_SCREEN(mi)];
|
||
|
|
||
|
if (MI_NPIXELS(mi) <= 3) {
|
||
|
if (bp->stippledGC == None) {
|
||
|
gcv.fill_style = FillOpaqueStippled;
|
||
|
if ((bp->stippledGC = XCreateGC(display, window,
|
||
|
GCFillStyle, &gcv)) == None) {
|
||
|
free_bug(display, bp);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
if (bp->init_bits == 0) {
|
||
|
for (i = 1; i < NUMSTIPPLES; i++) {
|
||
|
BUGBITS(stipples[i], STIPPLESIZE, STIPPLESIZE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
bp->generation = 0;
|
||
|
if (bp->firstbug == NULL) { /* Genesis */
|
||
|
/* Set up what will be a 'triply' linked list.
|
||
|
doubly linked list, doubly linked to an array */
|
||
|
if (!init_buglist(bp)) {
|
||
|
free_bug(display, bp);
|
||
|
return;
|
||
|
}
|
||
|
genexp[MAXGENE] = 1;
|
||
|
for (i = 1; i <= MAXGENE; i++) {
|
||
|
genexp[MAXGENE + i] = genexp[MAXGENE + i - 1] * M_E;
|
||
|
genexp[MAXGENE - i] = 1.0 / genexp[MAXGENE + i];
|
||
|
}
|
||
|
} else /* Apocolypse now */
|
||
|
flush_buglist(bp);
|
||
|
|
||
|
for (i = 0; i < NEIGHBORKINDS; i++) {
|
||
|
if (neighbors == plots[i]) {
|
||
|
bp->neighbors = plots[i];
|
||
|
break;
|
||
|
}
|
||
|
if (i == NEIGHBORKINDS - 1) {
|
||
|
bp->neighbors = plots[NRAND(NEIGHBORKINDS)];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bp->width = MI_WIDTH(mi);
|
||
|
bp->height = MI_HEIGHT(mi);
|
||
|
if (bp->width < 8)
|
||
|
bp->width = 8;
|
||
|
if (bp->height < 8)
|
||
|
bp->height = 8;
|
||
|
|
||
|
if (size < -MINSIZE)
|
||
|
bp->ys = NRAND(MIN(-size, MAX(MINSIZE, MIN(bp->width, bp->height) /
|
||
|
MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE;
|
||
|
else if (size < MINSIZE) {
|
||
|
if (!size)
|
||
|
bp->ys = MAX(MINSIZE, MIN(bp->width, bp->height) / MINGRIDSIZE);
|
||
|
else
|
||
|
bp->ys = MINSIZE;
|
||
|
} else
|
||
|
bp->ys = MIN(size, MAX(MINSIZE, MIN(bp->width, bp->height) /
|
||
|
MINGRIDSIZE));
|
||
|
bp->xs = bp->ys;
|
||
|
nccols = MAX(bp->width / bp->xs - 2, 2);
|
||
|
ncrows = MAX(bp->height / bp->ys - 1, 2);
|
||
|
bp->nrows = ncrows / 2;
|
||
|
if ((bp->neighbors % 2) || bp->neighbors == 12) {
|
||
|
bp->ncols = nccols / 3;
|
||
|
if (bp->ncols & 1)
|
||
|
bp->ncols--; /* Must be odd for no wrap */
|
||
|
if (bp->ncols < 2)
|
||
|
bp->ncols = 2;
|
||
|
if (!(bp->nrows & 1))
|
||
|
bp->nrows--; /* Must be even for no wrap */
|
||
|
} else
|
||
|
bp->ncols = nccols / 2;
|
||
|
if (bp->neighbors == 6 && !(bp->nrows & 1))
|
||
|
bp->nrows--; /* Must be odd for no wrap */
|
||
|
bp->xb = (bp->width - bp->xs * nccols) / 2;
|
||
|
bp->yb = (bp->height - bp->ys * ncrows) / 2;
|
||
|
if (bp->arr != NULL)
|
||
|
free(bp->arr);
|
||
|
if ((bp->arr = (BugList **) calloc(bp->ncols * bp->nrows,
|
||
|
sizeof (BugList *))) == NULL) {
|
||
|
free_bug(display, bp);
|
||
|
return;
|
||
|
}
|
||
|
if (bp->bacteria != NULL)
|
||
|
free(bp->bacteria);
|
||
|
if ((bp->bacteria = (char *) calloc(bp->ncols * bp->nrows,
|
||
|
sizeof (char))) == NULL) {
|
||
|
free_bug(display, bp);
|
||
|
return;
|
||
|
}
|
||
|
bp->edenheight = bp->nrows / 4;
|
||
|
bp->edenwidth = bp->ncols / 4;
|
||
|
if ((bp->neighbors % 2) || bp->neighbors == 12) {
|
||
|
if (bp->edenwidth & 1)
|
||
|
bp->edenwidth--;
|
||
|
if (!(bp->edenheight & 1))
|
||
|
bp->edenheight--;
|
||
|
} else if (bp->neighbors == 6 && bp->edenheight && !(bp->edenheight & 1))
|
||
|
bp->edenheight--; /* Make sure its odd */
|
||
|
bp->eden = (bp->edenwidth > 1 && bp->edenheight > 1);
|
||
|
if (bp->eden) {
|
||
|
bp->edenstartx = NRAND(bp->ncols - bp->edenwidth);
|
||
|
bp->edenstarty = NRAND(bp->nrows - bp->edenheight);
|
||
|
if ((bp->neighbors % 2) || bp->neighbors == 12) {
|
||
|
if (bp->edenstartx & 1) {
|
||
|
bp->edenstartx--;
|
||
|
bp->eden = (bp->edenwidth > 1);
|
||
|
}
|
||
|
if (bp->edenstarty & 1) {
|
||
|
bp->edenstarty--;
|
||
|
bp->eden = (bp->edenheight > 1);
|
||
|
}
|
||
|
} else if (bp->neighbors == 6 && (bp->edenstarty & 1)) {
|
||
|
bp->edenstarty--;
|
||
|
bp->eden = (bp->edenheight > 1);
|
||
|
}
|
||
|
}
|
||
|
/* Play G-d with these numbers... the genes */
|
||
|
nbugs = MI_COUNT(mi);
|
||
|
if (nbugs < 0)
|
||
|
nbugs = NRAND(-nbugs) + 1;
|
||
|
bp->nbugs = 0;
|
||
|
|
||
|
MI_CLEARWINDOW(mi);
|
||
|
bp->painted = False;
|
||
|
|
||
|
if (MI_IS_FULLRANDOM(mi)) {
|
||
|
bp->eyes = (Bool) (LRAND() & 1);
|
||
|
} else {
|
||
|
bp->eyes = eyes;
|
||
|
}
|
||
|
bp->eyes = (bp->eyes && bp->xs > 1 && bp->ys > 1);
|
||
|
|
||
|
/* Try to make bugs, but if can not, exit */
|
||
|
while (bp->nbugs < nbugs && ntries < 2 * nbugs) {
|
||
|
row = NRAND(bp->nrows);
|
||
|
if (bp->neighbors == 6) {
|
||
|
if (bp->ncols - (!(row & 1)) > 0)
|
||
|
col = NRAND(bp->ncols - (!(row & 1)));
|
||
|
else
|
||
|
col = 0;
|
||
|
} else { /* RECT or TRI */
|
||
|
col = NRAND(bp->ncols);
|
||
|
}
|
||
|
colrow = col + row * bp->ncols;
|
||
|
ntries++;
|
||
|
if (!bp->arr[colrow] && !has_neighbor(bp, col, row)) {
|
||
|
bp->nbugs++;
|
||
|
info.age = 0;
|
||
|
info.energy = INITENERGY;
|
||
|
info.direction = NRAND(bp->neighbors);
|
||
|
for (gene = 0; gene < bp->neighbors; gene++)
|
||
|
#if 0
|
||
|
/* Some creationalism, may create gliders or twirlers */
|
||
|
do {
|
||
|
double temp = (double) LRAND() / MAXRAND;
|
||
|
|
||
|
info.gene[gene] = ((int) (1.0 / (1.0 - temp * temp)) - 1) *
|
||
|
((LRAND() & 1) ? -1 : 1);
|
||
|
} while (info.gene[gene] > MAXGENE / 2 ||
|
||
|
info.gene[gene] < MINGENE / 2);
|
||
|
#else /* Jitterbugs, evolve or die */
|
||
|
info.gene[gene] = 0;
|
||
|
#endif
|
||
|
sum = 0;
|
||
|
for (gene = 0; gene < bp->neighbors; gene++)
|
||
|
sum += genexp[info.gene[gene] + MAXGENE];
|
||
|
for (gene = 0; gene < bp->neighbors; gene++)
|
||
|
info.gene_prob[gene] = genexp[info.gene[gene] + MAXGENE] / sum;
|
||
|
#if EXTRA_GENES
|
||
|
if (bp->neighbors % 2) {
|
||
|
for (gene = 0; gene < bp->neighbors; gene++)
|
||
|
#if 0
|
||
|
/* Some creationalism, may create gliders or twirlers */
|
||
|
do {
|
||
|
double temp = (double) LRAND() / MAXRAND;
|
||
|
|
||
|
info.lgene[gene] = ((int) (1.0 / (1.0 - temp * temp)) - 1) *
|
||
|
((LRAND() & 1) ? -1 : 1);
|
||
|
} while (info.lgene[gene] > MAXGENE / 2 ||
|
||
|
info.lgene[gene] < MINGENE / 2);
|
||
|
#else /* Jitterbugs, evolve or die */
|
||
|
info.lgene[gene] = 0;
|
||
|
#endif
|
||
|
sum = 0;
|
||
|
for (gene = 0; gene < bp->neighbors; gene++)
|
||
|
sum += genexp[info.lgene[gene] + MAXGENE];
|
||
|
for (gene = 0; gene < bp->neighbors; gene++)
|
||
|
info.lgene_prob[gene] = genexp[info.lgene[gene] + MAXGENE] / sum;
|
||
|
}
|
||
|
#endif
|
||
|
if (MI_NPIXELS(mi) > 3)
|
||
|
info.color = NRAND(MI_NPIXELS(mi));
|
||
|
else
|
||
|
info.color = NRAND(NUMSTIPPLES - 1);
|
||
|
info.col = col;
|
||
|
info.row = row;
|
||
|
addto_buglist(bp, info);
|
||
|
if (bp->firstbug == NULL) {
|
||
|
free_bug(display, bp);
|
||
|
return;
|
||
|
}
|
||
|
bp->arr[colrow] = bp->currbug;
|
||
|
drawabug(mi, col, row, bp->currbug->info.color, (int) bp->currbug->info.direction * ANGLES / bp->neighbors);
|
||
|
}
|
||
|
}
|
||
|
makebacteria(mi, bp->ncols * bp->nrows / 2, 0, 0, bp->ncols, bp->nrows,
|
||
|
False);
|
||
|
if (bp->eden)
|
||
|
makebacteria(mi, bp->edenwidth * bp->edenheight / 2,
|
||
|
bp->edenstartx, bp->edenstarty, bp->edenwidth, bp->edenheight, False);
|
||
|
bp->redrawing = 1;
|
||
|
bp->redrawpos = 0;
|
||
|
}
|
||
|
|
||
|
#define ENOUGH 16
|
||
|
void
|
||
|
draw_bug(ModeInfo * mi)
|
||
|
{
|
||
|
int col, row, ncol = -1, nrow = -1, colrow, ncolrow;
|
||
|
int absdir = 0, tryit, dir;
|
||
|
bugfarmstruct *bp;
|
||
|
|
||
|
if (bugfarms == NULL)
|
||
|
return;
|
||
|
bp = &bugfarms[MI_SCREEN(mi)];
|
||
|
if (bp->firstbug == NULL)
|
||
|
return;
|
||
|
|
||
|
MI_IS_DRAWN(mi) = True;
|
||
|
bp->painted = True;
|
||
|
bp->currbug = bp->firstbug->next;
|
||
|
while (bp->currbug != bp->lastbug) {
|
||
|
col = bp->currbug->info.col;
|
||
|
row = bp->currbug->info.row;
|
||
|
colrow = col + row * bp->ncols;
|
||
|
if (bp->currbug->info.energy-- < 0) { /* Time to die, Bug */
|
||
|
#ifdef DEBUG
|
||
|
assert(bp->currbug == bp->arr[colrow]);
|
||
|
#endif
|
||
|
/* back up one or else in void */
|
||
|
bp->currbug = bp->currbug->previous;
|
||
|
removefrom_buglist(bp, bp->arr[colrow]);
|
||
|
#ifdef DEBUG
|
||
|
assert(bp->arr[colrow] == 0);
|
||
|
#endif
|
||
|
bp->arr[colrow] = 0;
|
||
|
eraseabug(mi, col, row);
|
||
|
bp->nbugs--;
|
||
|
} else { /* try to move */
|
||
|
bp->arr[colrow] = 0; /* Don't want neighbor to detect itself */
|
||
|
tryit = 0;
|
||
|
do {
|
||
|
if (tryit++ > ENOUGH) {
|
||
|
break;
|
||
|
}
|
||
|
absdir = (bp->currbug->info.direction +
|
||
|
dirbug(&bp->currbug->info, bp->neighbors)) % bp->neighbors;
|
||
|
dir = absdir * ANGLES / bp->neighbors;
|
||
|
if (bp->neighbors % 2) {
|
||
|
if ((col + row) & 1)
|
||
|
dir = (3 * ANGLES / 2 - dir) % ANGLES;
|
||
|
else
|
||
|
dir = (ANGLES - dir) % ANGLES;
|
||
|
}
|
||
|
} while (!dirmove(bp, col, row, dir,
|
||
|
&ncol, &nrow) || has_neighbor(bp, ncol, nrow) ||
|
||
|
bp->arr[ncol + nrow * bp->ncols]);
|
||
|
bp->currbug->info.age++;
|
||
|
bp->currbug->info.energy--;
|
||
|
if (tryit <= ENOUGH) {
|
||
|
ncolrow = ncol + nrow * bp->ncols;
|
||
|
if (bp->bacteria[ncolrow]) {
|
||
|
bp->currbug->info.energy += BACTERIAENERGY;
|
||
|
bp->bacteria[ncolrow] = 0;
|
||
|
if (bp->currbug->info.energy > MAXENERGY)
|
||
|
bp->currbug->info.energy = MAXENERGY;
|
||
|
}
|
||
|
bp->currbug->info.col = ncol;
|
||
|
bp->currbug->info.row = nrow;
|
||
|
bp->currbug->info.direction = absdir;
|
||
|
#ifdef DEBUG
|
||
|
assert(bp->arr[ncolrow] == 0);
|
||
|
#endif
|
||
|
bp->arr[ncolrow] = bp->currbug;
|
||
|
if (bp->currbug->info.energy > STRONG &&
|
||
|
bp->currbug->info.age > MATURE) { /* breed */
|
||
|
drawabug(mi, ncol, nrow, bp->currbug->info.color, (int) bp->currbug->info.direction * ANGLES / bp->neighbors);
|
||
|
cutfrom_buglist(bp); /* This rotates out who goes first */
|
||
|
bp->babybug->info.age = 0;
|
||
|
bp->babybug->info.energy = INITENERGY;
|
||
|
dupin_buglist(bp);
|
||
|
if (bp->firstbug == NULL) {
|
||
|
free_bug(MI_DISPLAY(mi), bp);
|
||
|
return;
|
||
|
}
|
||
|
mutatebug(&bp->babybug->previous->info, bp->neighbors);
|
||
|
mutatebug(&bp->babybug->info, bp->neighbors);
|
||
|
bp->arr[colrow] = bp->babybug;
|
||
|
bp->babybug->info.col = col;
|
||
|
bp->babybug->info.row = row;
|
||
|
bp->nbugs++;
|
||
|
} else {
|
||
|
eraseabug(mi, col, row);
|
||
|
drawabug(mi, ncol, nrow, bp->currbug->info.color, (int) bp->currbug->info.direction * ANGLES / bp->neighbors);
|
||
|
}
|
||
|
} else
|
||
|
bp->arr[colrow] = bp->currbug;
|
||
|
}
|
||
|
bp->currbug = bp->currbug->next;
|
||
|
}
|
||
|
reattach_buglist(bp);
|
||
|
makebacteria(mi, FOODPERCYCLE, 0, 0, bp->ncols, bp->nrows, True);
|
||
|
if (bp->eden)
|
||
|
makebacteria(mi, FOODPERCYCLE,
|
||
|
bp->edenstartx, bp->edenstarty, bp->edenwidth, bp->edenheight, True);
|
||
|
if (!bp->nbugs || bp->generation >= MI_CYCLES(mi))
|
||
|
init_bug(mi);
|
||
|
bp->generation++;
|
||
|
if (bp->redrawing) {
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < REDRAWSTEP; i++) {
|
||
|
if (bp->bacteria[bp->redrawpos])
|
||
|
redrawbacteria(mi, bp->redrawpos);
|
||
|
if (++(bp->redrawpos) >= bp->ncols * bp->nrows) {
|
||
|
bp->redrawing = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
release_bug(ModeInfo * mi)
|
||
|
{
|
||
|
if (bugfarms != NULL) {
|
||
|
int screen;
|
||
|
|
||
|
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
|
||
|
free_bug(MI_DISPLAY(mi), &bugfarms[screen]);
|
||
|
free(bugfarms);
|
||
|
bugfarms = (bugfarmstruct *) NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
refresh_bug(ModeInfo * mi)
|
||
|
{
|
||
|
bugfarmstruct *bp;
|
||
|
|
||
|
if (bugfarms == NULL)
|
||
|
return;
|
||
|
bp = &bugfarms[MI_SCREEN(mi)];
|
||
|
|
||
|
if (bp->painted) {
|
||
|
MI_CLEARWINDOW(mi);
|
||
|
bp->painted = False;
|
||
|
bp->redrawing = 1;
|
||
|
bp->redrawpos = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif /* MODE_bug */
|