// Bugs // // A simulation of some bugs crusing about and eating food. Their // change of direction is controlled by 6 genes. Those that survive // produce offspring with similar genes. Over the generations // genes drift towards an optimum pattern. // // 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.awt.Graphics; import java.awt.Event; import java.applet.Applet; import ADT.Queue; import ADT.QueueEmpty; import ADT.QueueItemAbsent; import ADT.Random; public final class World extends Applet implements Runnable { // // Private interface // private static int BLOCK_SIZE = 2; private static int CLICK_RADIUS = 5 * 5; private static int FOOD_ENERGY = 40; private static int MAXIMUM_SPEED = 1; private static int MEDIUM_SPEED = 10; private static int MINIMUM_SPEED = 100; private static Color backgroundColor = Color.black; private static Color foodColor = Color.green; private Queue bugQueue; private int[][] food; private int foodPercentage; private int bugCount; private int width; private int height; private int speed = MAXIMUM_SPEED; private Control control; private Thread animation; private Graphics graphics; private Random random = new Random(); private static int defaultFoodPercentage = 10; private static int defaultBugs = 10; // // Public interface // public void init() { int f, b; setBackground(backgroundColor); // Read in percentage for food String foodString = this.getParameter("foodPercentage"); try { f = Integer.parseInt(foodString); if (f < 0 || f > 100) throw new NumberFormatException("Food must be percentage"); } catch (NumberFormatException e) { f = defaultFoodPercentage; } // Read in number of bugs String bugsString = this.getParameter("bugPercentage"); try { b = Integer.parseInt(bugsString); if (b < 0) throw new NumberFormatException("Bugs must be non-negative"); } catch (NumberFormatException e) { b = defaultBugs; } // initialise world foodPercentage = f; bugCount = b; width = size().width / BLOCK_SIZE; height = size().height / BLOCK_SIZE; graphics = this.getGraphics(); reset(); } public void reset() { food = new int[width][height]; int foodCount = width * height * foodPercentage / 100; for (int i = foodCount; i > 0; i--) grow(); bugQueue = new Queue(); for (int i = bugCount; i > 0; i--) add(new Bug(this, random.range(width), random.range(height))); paint(graphics); control = null; } public void cancel() { control = null; } public void destroy() { if (control != null) { control.hide(); control.dispose(); } } public void start() { if (animation == null) { animation = new Thread(this); animation.start(); } } public void stop() { if (animation != null && animation.isAlive()) animation.stop(); animation = null; } public void run() { try { while (true) { synchronized (bugQueue) { for (int i = bugQueue.size(); i > 0; i--) ((Bug) bugQueue.requeue()).tick(); grow(); } try { animation.sleep(speed); } catch (InterruptedException e) { // do nothing } } } catch (QueueEmpty e) { // this just means there are no bugs } } public void paint(Graphics g) { synchronized (bugQueue) { g.setColor(backgroundColor); g.fillRect(0, 0, size().width, size().height); for (int x = width - 1; x >= 0; x--) for (int y = height - 1; y >= 0; y--) if (food[x][y] > 0) paint(x, y, foodColor); try { for (int i = bugQueue.size(); i > 0; i--) ((Bug) bugQueue.requeue()).paint(); } catch (QueueEmpty e) { // this just means there are no bugs } } } public boolean mouseDown(Event e, int x, int y) { Bug closest = null; // find closest bug to click point try { x = x / BLOCK_SIZE; y = y / BLOCK_SIZE; synchronized (bugQueue) { for (int i = bugQueue.size(); i > 0; i--) { Bug b = (Bug) bugQueue.requeue(); if (closest == null) closest = b; else if (b.sqrDistance(x, y) < closest.sqrDistance(x, y)) closest = b; } } } catch (QueueEmpty f) { // this just means there are no bugs } // bring up bug control panel if (closest != null && closest.sqrDistance(x, y) <= CLICK_RADIUS) new Control(this, closest); // or speed control panel else if (control == null) control = new Control(this, speed == MAXIMUM_SPEED ? 0 : (speed == MEDIUM_SPEED ? 1 : 2)); return true; } public String[][] getParameterInfo() { String[][] info = { {"foodPercentage ", "percentage ", "percentage of blocks with food"}, {"bugs ", "percentage ", "number of bugs"} }; return info; } public String getAppletInfo() { return "Bugs v1.0 Written by Matthew Caryl"; } public void paint(int x, int y, Color c) { graphics.setColor(c); graphics.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); } public void erase(int x, int y) { graphics.setColor(backgroundColor); graphics.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); } // clear food from coordinates public int feed(int x, int y) { int f = food[x][y]; food[x][y] = 0; return f; } // grow food at random coordinates public void grow() { int x = random.range(width); int y = random.range(height); food[x][y] += FOOD_ENERGY; paint(x, y, foodColor); } // add a bug public void add(Bug b) { bugQueue.enqueue(b); } // remove a bug public void sub(Bug b) { try { bugQueue.remove(b); } catch (QueueItemAbsent e) { System.err.println("Report to programmer - sub"); } } public Random random() { return random; } public int width() { return width; } public int height() { return height; } // set speed - maximum, medium, minimum public void speed(int S) { switch (S) { case 0: speed = MAXIMUM_SPEED; break; case 1: speed = MEDIUM_SPEED; break; default: speed = MINIMUM_SPEED; break; } } }