// World for Artificial Termites. // A simulation of termites which can move bits of wood around the world // according to simple rules. // // Author Matthew Caryl // Created 29.10.96 // Modified 2.3.01 // // 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 ArtificialTermites; import java.awt.Color; import java.awt.Event; import java.awt.Graphics; import java.applet.Applet; import java.util.Date; import ADT.Queue; import ADT.QueueEmpty; public final class World extends Applet implements Runnable { private Queue termiteQueue; private boolean[][] woodWorld; private int worldWidth; private int worldHeight; private int screenWidth; private int screenHeight; private int blockSize; private int woodPercentage; private int termitePercentage; private Thread animationThread; private float frameTime = 40; private Graphics graphicsWorld; private long randomSeed = 0; private static Color backgroundColor = Color.black; private static Color woodColor = Color.yellow; static int defaultWorldWidth = 64; static int defaultWorldHeight = 64; static int defaultBlockSize = 2; static int defaultWoodPercentage = 5; static int defaultTermitePercentage = 1; public void init() { int width, height, block, wood, termites; // set background and random number seed setBackground(backgroundColor); Date date = new Date(); randomSeed = date.getTime(); // Read in width, height, and block size parameters. String widthString = this.getParameter("worldWidth"); try { width = Integer.parseInt(widthString); if (width < 1) throw new NumberFormatException("Width must be postive"); } catch (NumberFormatException e) {width = defaultWorldWidth;} String heightString = this.getParameter("worldHeight"); try { height = Integer.parseInt(heightString); if (height < 1) throw new NumberFormatException("Height must be postive"); } catch (NumberFormatException e) {height = defaultWorldHeight;} String blockString = this.getParameter("blockSize"); try { block = Integer.parseInt(blockString); if (block < 1) throw new NumberFormatException("Pixel must be postive"); } catch (NumberFormatException e) {block = defaultBlockSize;} // Read in percentage for wood String woodString = this.getParameter("woodPercentage"); try { wood = Integer.parseInt(woodString); if (wood < 0 || wood > 100) throw new NumberFormatException("Wood must be percentage"); } catch (NumberFormatException e) {wood = defaultWoodPercentage;} // Read in percentage for termites and add to world String termitesString = this.getParameter("termitePercentage"); try { termites = Integer.parseInt(termitesString); if (termites < 0 || termites > 100) throw new NumberFormatException("Termite must be percentage"); } catch (NumberFormatException e) {termites = defaultTermitePercentage;} // how fast do we go String frameRateString = this.getParameter("frameRate"); try { frameTime = (float) 1000 / (float) Integer.parseInt(frameRateString); } catch (NumberFormatException e) { // do nothing } // initialise the world with parameter values initialiseWorld(width, height, block, wood, termites); } void initialiseWorld(int width, int height, int block, int wood, int termites) { worldWidth = width; worldHeight = height; blockSize = block; woodPercentage = wood; termitePercentage = termites; if (worldWidth < 1) worldWidth = defaultWorldWidth; if (worldHeight < 1) worldHeight = defaultWorldHeight; if (blockSize < 1) blockSize = defaultBlockSize; if (woodPercentage < 0 || woodPercentage > 100) woodPercentage = defaultWoodPercentage; if (termitePercentage < 0 || termitePercentage > 100) termitePercentage = defaultTermitePercentage; // Calculate screen space required. screenWidth = worldWidth * blockSize; screenHeight = worldHeight * blockSize; // and ask the browser for the space resize(screenWidth, screenHeight); // Save graphics context for later // Note: this seems to reduce garbage collection problems // Note: have to do this after every resize graphicsWorld = this.getGraphics(); woodWorld = new boolean[worldWidth][worldHeight]; for (int i = worldWidth * worldHeight * woodPercentage / 100; i > 0; i--) addWood(); int termiteCount = worldWidth * worldHeight * termitePercentage / 100; termiteQueue = new Queue(); for (int i = termiteCount; i > 0; i--) addTermite(); paint(graphicsWorld); } public void finalize() throws Throwable { stop(); super.finalize(); } public void start() { if (animationThread == null) { animationThread = new Thread(this); animationThread.start(); } } public void stop() { if (animationThread != null && animationThread.isAlive()) animationThread.stop(); animationThread = null; } public void run() { try { while (true) { long Time = System.currentTimeMillis(); synchronized (termiteQueue) { for (int i = termiteQueue.size(); i > 0; i--) ((Termite) termiteQueue.requeue()).tick(); } // slow thread down try { long sleepTime = (long)(frameTime - (float) System.currentTimeMillis() + (float) Time); System.out.println(sleepTime); animationThread.sleep(Math.max(0, sleepTime)); } catch (InterruptedException e) { // do nothing } } } catch (QueueEmpty e) { // this just means there are no termites } } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { synchronized (termiteQueue) { g.setColor(backgroundColor); g.fillRect(0, 0, screenWidth, screenHeight); paintWood(); paintTermites(); } } public void paint() { paint(graphicsWorld); } public boolean mouseDown(Event e, int x, int y) { // only open a control window if animation active if (animationThread != null) { stop(); ControlFrame controlFrame = new ControlFrame(this); } return true; } public String[][] getParameterInfo() { String[][] info = { {"worldWidth ", "positive integer ", "width of world in blocks"}, {"worldHeight ", "positive integer ", "height of world in blocks"}, {"blockSize ", "positive integer ", "size of block in pixels"}, {"woodPercentage ", "percentage ", "percentage of blocks with wood"}, {"termitePercentage ", "percentage ", "percentage of blocks with termites"} }; return info; } public String getAppletInfo() { return "Artificial Termites v1.0 Written by Matthew Caryl"; } private void paintWood() { for (int x = worldWidth - 1; x >= 0; x--) for (int y = worldHeight - 1; y >= 0; y--) // for speed, check if the wood is there or not before painting if (woodAt(x, y)) paintBlock(x, y, World.woodColor); } private void paintTermites() { try { for (int i = termiteQueue.size(); i > 0; i--) ((Termite) termiteQueue.requeue()).paint(); } catch (QueueEmpty e) { // this just means there are no termites } } void paintBlock(int x, int y, Color c) { graphicsWorld.setColor(c); // adjust postion for size of blocks graphicsWorld.fillRect(x * blockSize, y * blockSize, blockSize, blockSize); } void paintBlock(int x, int y) { if (woodAt(x, y)) paintBlock(x, y, woodColor); else paintBlock(x, y, backgroundColor); } int random(int range) { randomSeed = randomSeed * 1103515245 + 12345; return (int) ((randomSeed / 65535) % range); } boolean woodAt(int x, int y) { return woodWorld[mod(x, worldWidth)][mod(y, worldHeight)]; } int woodPercentage() { return woodPercentage; } int termitePercentage() { return termitePercentage; } int width() { return worldWidth; } int height() { return worldHeight; } int blockSize() { return blockSize; } private void addWood() { int x, y; // find free space for wood do { x = random(worldWidth); y = random(worldHeight); } while (woodAt(x, y)); putWood(x, y); } private void addTermite() { int x, y; Termite t; x = random(worldWidth); y = random(worldHeight); t = new Termite(this, x, y); termiteQueue.enqueue(t); } void putWood(int x, int y) { x = mod(x, worldWidth); y = mod(y, worldHeight); woodWorld[x][y] = true; } void getWood(int x, int y) { x = mod(x, worldWidth); y = mod(y, worldHeight); woodWorld[x][y] = false; } static int mod(int x, int y) { int m; m = x % y; if (m < 0) return m + y; else return m; } }