// Individual bug // // Author Matthew Caryl // Created 25.2.97 // // Although under copywrite to the author (Matthew Caryl) this code can be copied and modified for non-commercial // purposes as long as any derivatives contain this condition. package Bugs; import java.awt.Color; import java.lang.Math; final class Bug { // // Private interface // private static int MAXIMUM_ENERGY = 1500; private static int ENERGY_PER_TICK = 1; private static int REPRODUCTION_AGE = 800; private static int REPRODUCTION_ENERGY = 1000; private static int INITIAL_ENERGY = 500; private static int MAXIMUM_GENE_VALUE = 10; private static Color NONSELECTED_COLOR = Color.magenta; private static Color SELECTED_COLOR = Color.yellow; private static int[] facingXDelta = {0, 1, 1, 0, -1, -1}; // x-delta for facing private static int[] facingYDelta = {1, 1, -1, -1, -1, 1}; // y-delta for facing private World world; private int x, y; private int facing; // in range 0..5 private int energy; private int age; private int[] genes = new int[6]; private int[] behaviour = new int[6]; private Color color = Color.magenta; // // Public interface // public Bug(Bug b, int E) { world = b.world; x = b.x; y = b.y; facing = b.facing; energy = E; for (int i = 5; i >= 0; i--) genes[i] = b.genes[i]; mutateGenes(); calculateBehaviour(); } public Bug(World W, int X, int Y) { world = W; x = X; y = Y; facing = world.random().range(6); // random facing energy = INITIAL_ENERGY; for (int i = 5; i >= 0; i--) genes[i] = world.random().range(MAXIMUM_GENE_VALUE); calculateBehaviour(); } public void paint() { world.paint(x, y, color); } public void tick() { age++; world.erase(x, y); possibleTurn(); moveForward(); world.paint(x, y, color); eatAndDigest(); possibleReproduction(); } public int sqrDistance(int X, int Y) { return (x - X) * (x - X) + (y - Y) * (y - Y); } private void possibleTurn() { int r = world.random().range(behaviour[5]); if (r < behaviour[0]) return; else if (r < behaviour[1]) facing += 1; else if (r < behaviour[2]) facing += 2; else if (r < behaviour[3]) facing += 3; else if (r < behaviour[4]) facing += 4; else facing += 5; if (facing > 5) facing -= 6; } private void moveForward() { x += facingXDelta[facing]; y += facingYDelta[facing]; if (x < 0) x += world.width(); else if (x >= world.width()) x -= world.width(); if (y < 0) y += world.height(); else if (y >= world.height()) y -= world.height(); } private void eatAndDigest() { energy += world.feed(x, y) - ENERGY_PER_TICK; if (energy > MAXIMUM_ENERGY) energy = MAXIMUM_ENERGY; else if (energy <= 0) kill(); } private void possibleReproduction() { if (age >= REPRODUCTION_AGE && energy >= REPRODUCTION_ENERGY) { world.add(new Bug(this, energy / 2)); world.add(new Bug(this, energy - energy / 2)); kill(); } } private void mutateGenes() { int r = world.random().range(6); if (world.random().flip()) { genes[r] += 1; // mutate upwards if (genes[r] > MAXIMUM_GENE_VALUE) // if above maximum lower all gene values for (int l = 0; l < 6; l++) { genes[l] -= 1; genes[l] = Math.max(genes[l], 0); } } else if (genes[r] > 0) genes[r] -= 1; } // 1 << genes[i] is the weighing for a turn of i. // behaviour[i] = (sum of all lower behaviours) + (1 << genes[i]) private void calculateBehaviour() { behaviour[0] = (1 << genes[0]); behaviour[1] = behaviour[0] + (1 << genes[1]); behaviour[2] = behaviour[1] + (1 << genes[2]); behaviour[3] = behaviour[2] + (1 << genes[3]); behaviour[4] = behaviour[3] + (1 << genes[4]); behaviour[5] = behaviour[4] + (1 << genes[5]); } private void kill() { world.sub(this); world.erase(x, y); world = null; // indicates bug is dead } public int energy() { return energy; } public int age() { return age; } public int gene(int P) { return genes[P]; } public void select() { color = SELECTED_COLOR; } public void unselect() { color = NONSELECTED_COLOR; } public boolean dead() { return world == null; } }