import java.lang.*; import java.math.*; import java.util.Random; public class Beetlex { /************************************************************************* * * These values represent the dimensions of the model, and its general * runtime behavior. We could, if we wanted more flexibility, read these * values (and the next set) from the command-line (i.e. args[]), or some * other runtime input mechanism. As it stands, to change the assumptions * and/or dimensions of the computational model, we have to change them * below and recompile. * *************************************************************************/ private static int rows = 40; private static int columns = 40; private static int runLength = 200; /************************************************************************* * * These values represent the different constants in our model; if we * change these, the model will behave differently. * *************************************************************************/ private static int avgHealthyTrees = 45; private static int avgWeakTrees = 20; private static int eggsPerPair = 75; private static double avgFlightDistance = 2.5; private static double stdDevFlightDistance = 0.5; private static double windDirection = Math.PI; // In radians private static double windSpeed = 1; private static int minSuccessfulWeakAttack = 1; private static int minSuccessfulHealthyAttack = 100; private static int developmentalCycle = 26; private static int seedBeetlesPerWeek = 75; private static int seedPoints = 2; /************************************************************************* * * This is the "playing field" - the map on which we will place trees and * beetles. * *************************************************************************/ private static Forest forest = new Forest (rows, columns, avgHealthyTrees, avgWeakTrees, developmentalCycle); /************************************************************************* * * This is the high-level heart of the model - the work performed at each * iteration. It would probably be more logical to make this a method of * the Forest class (since that is really where everything happens); of * course, if we did that, students would know the joy of typing all this in. * *************************************************************************/ static void iterate (int week) { forest.emerge (eggsPerPair, avgFlightDistance, stdDevFlightDistance, windDirection, windSpeed); System.out.println (forest.inventory (week)); forest.infest (minSuccessfulWeakAttack, minSuccessfulHealthyAttack); } /************************************************************************* * * Any class which is the central class of a Java program MUST have a main * method, with the following declaration: * * public static void main (String[] args) { * // Code goes here. * } * * Our main method contains the time loop of the process, which calls the * iterate method (as well as the Forst.emergeInitial method, until beetles * start emerging from the trees). * *************************************************************************/ public static void main (String[] args) { for (int iterCount = 0; iterCount < runLength; iterCount++) { if (iterCount < developmentalCycle) { for (int seedIndex = 0; seedIndex < seedPoints; seedIndex++) { forest.emergeInitial (seedBeetlesPerWeek, avgFlightDistance, stdDevFlightDistance, windDirection, windSpeed); } } iterate (iterCount + 1); } } } /***************************************************************************** * * For clarity in presentation, this file contains not only the central program * class, but also the private classes instantiated by the program. (When * multiple classes are included in one source file, only one of the classes * may be declared as "public".) * *****************************************************************************/ /***************************************************************************** * * Infestation is a simple class which encapsulates the pairs of beetles which * which have burrowed a number of trees in the same cell of the forest grid. * *****************************************************************************/ class Infestation { private int trees = 0; private int beetlePairs = 0; public Infestation () { } public Infestation (int trees, int beetlePairs) { this.trees = trees; this.beetlePairs = beetlePairs; } public int getTrees () { return trees; } public int getBeetlePairs () { return beetlePairs; } } /***************************************************************************** * * TreePatch is the class which encapsulates all the trees and beetles within * one cell of the grid representing the forest. Since there may be hundreds of * trees, and thousands of beetles, in this single section of the forest, we * aren't managing those as object; instead we are keeping a tally on all of * them, in this object. * *****************************************************************************/ class TreePatch { private int gestation; private int healthyTrees; private int weakTrees; private int deadTrees; private int beetles; private Infestation healthyInfestation []; private Infestation weakInfestation []; public TreePatch (int gestation, int healthyTrees, int weakTrees) { Random rng = new Random (); this.gestation = gestation; this.healthyTrees = (int) (rng.nextGaussian () * Math.sqrt (1.0 * healthyTrees) + healthyTrees); this.weakTrees = (int) (rng.nextGaussian () * Math.sqrt (1.0 * weakTrees) + weakTrees); this.deadTrees = 0; healthyInfestation = new Infestation [gestation]; weakInfestation = new Infestation [gestation]; for (int gestationIndex = 0; gestationIndex < gestation; gestationIndex++) { healthyInfestation [gestationIndex] = new Infestation (); weakInfestation [gestationIndex] = new Infestation (); } } public void land () { this.beetles++; } public void land (int beetles) { this.beetles += beetles; } public void infest (int minSuccessfulWeakAttack, int minSuccessfulHealthyAttack) { int attacks; int healthyAttacks; int weakAttacks; Infestation newHealthyInfestation; Infestation newWeakInfestation; double avgPairs; int treesInfested; int totalTrees = this.healthyTrees + this.weakTrees; if (this.beetles > 0) { if (this.beetles > 2 * totalTrees) { attacks = totalTrees; } else { attacks = (int) (this.beetles / 2); } if (attacks > 0) { healthyAttacks = (int) (attacks * this.healthyTrees / totalTrees); weakAttacks = attacks - healthyAttacks; avgPairs = (0.5 * beetles) / attacks; if (avgPairs <= minSuccessfulWeakAttack - 1) { newHealthyInfestation = new Infestation (0, 0); newWeakInfestation = new Infestation (0, 0); } else if (avgPairs < minSuccessfulWeakAttack) { newHealthyInfestation = new Infestation (0, 0); treesInfested = (int) (weakAttacks * (avgPairs - (int) (avgPairs))); newWeakInfestation = new Infestation (treesInfested, treesInfested * minSuccessfulWeakAttack); } else if (avgPairs <= minSuccessfulHealthyAttack - 1) { newHealthyInfestation = new Infestation (0, 0); newWeakInfestation = new Infestation (weakAttacks, (int) (weakAttacks * avgPairs)); } else if (avgPairs < minSuccessfulHealthyAttack) { treesInfested = (int) (healthyAttacks * (avgPairs - (int) (avgPairs))); newHealthyInfestation = new Infestation (treesInfested, treesInfested * minSuccessfulHealthyAttack); newWeakInfestation = new Infestation (weakAttacks, (int) (weakAttacks * avgPairs)); } else { newHealthyInfestation = new Infestation (healthyAttacks, (int) (healthyAttacks * avgPairs)); newWeakInfestation = new Infestation (weakAttacks, (int) (weakAttacks * avgPairs)); } } else { newHealthyInfestation = new Infestation (0, 0); newWeakInfestation = new Infestation (0, 0); } } else { newHealthyInfestation = new Infestation (0, 0); newWeakInfestation = new Infestation (0, 0); } healthyTrees -= newHealthyInfestation.getTrees (); weakTrees -= newWeakInfestation.getTrees (); healthyInfestation [gestation - 1] = newHealthyInfestation; weakInfestation [gestation - 1] = newWeakInfestation; this.beetles = 0; } public int emerge (int eggsPerPair) { int beetlePairs = healthyInfestation [0].getBeetlePairs () + weakInfestation [0].getBeetlePairs (); deadTrees += healthyInfestation [0].getTrees () + weakInfestation [0].getTrees (); for (int infestIndex = 1; infestIndex < gestation; infestIndex++) { healthyInfestation [infestIndex - 1] = healthyInfestation [infestIndex]; weakInfestation [infestIndex - 1] = weakInfestation [infestIndex]; }; return (beetlePairs * eggsPerPair); } public int getHealthyTrees () { return this.healthyTrees; } public int getWeakTrees () { return this.weakTrees; } public int getDeadTrees () { return this.deadTrees; } public int getBeetles () { return this.beetles; } } /***************************************************************************** * * The Forest class contains a grid of TreePatch cells; this class "knows" how * to iterate across the rows and columns - to "plant" the trees, to "seed" the * forest with the initial beetle population, to move the beetles that emerge * in one cell to another, etc. It also knows how to take an "inventory" of the * state of the forest (number of beetles, healthy trees, weak trees, etc. * *****************************************************************************/ class Forest { private int rows; private int columns; private TreePatch patches [][]; public Forest (int rows, int columns, int avgHealthyTrees, int avgWeakTrees, int gestation) { this.rows = rows; this.columns = columns; this.patches = new TreePatch [rows][columns]; for (int row = 0; row < rows; row++) { for (int column = 0; column < columns; column++) { this.patches [row][column] = new TreePatch (gestation, avgHealthyTrees, avgWeakTrees); } } } public void emergeInitial (int beetles, double avgFlight, double stdDevFlight, double windDirection, double windSpeed) { int endingX; int endingY; double flightDistance; double flightDirection; Random rng = new Random (); double startingX = 0.5 + (int) (Math.random () * columns); double startingY = 0.5 + (int) (Math.random () * rows); for (int beetleIndex = 0; beetleIndex < beetles; beetleIndex++) { flightDirection = Math.random () * 2 * Math.PI; flightDistance = rng.nextGaussian () * stdDevFlight + avgFlight; endingX = (int) (Math.round (startingX + Math.cos (flightDirection) * flightDistance + Math.cos (windDirection) * windSpeed)); endingY = (int) (Math.round (startingY + Math.sin (flightDirection) * flightDistance + Math.sin (windDirection) * windSpeed)); while (endingX < 0) { endingX += columns; } while (endingX >= columns) { endingX -= columns; } while (endingY < 0) { endingY += rows; } while (endingY >= rows) { endingY -= rows; } patches [endingY][endingX].land (); } } public void emerge (int eggsPerPair, double avgFlight, double stdDevFlight, double windDirection, double windSpeed) { int beetles; double startingX; double startingY; int endingX; int endingY; double flightDistance; double flightDirection; Random rng = new Random (); for (int rowIndex = 0; rowIndex < rows; rowIndex++) { startingY = 0.5 + rowIndex; for (int colIndex = 0; colIndex < rows; colIndex++) { startingX = 0.5 + colIndex; beetles = patches [rowIndex][colIndex].emerge (eggsPerPair); for (int beetleIndex = 0; beetleIndex < beetles; beetleIndex++) { flightDirection = Math.random () * 2 * Math.PI; flightDistance = rng.nextGaussian () * stdDevFlight + avgFlight; endingX = (int) (Math.round (startingX + Math.cos (flightDirection) * flightDistance + Math.cos (windDirection) * windSpeed)); endingY = (int) (Math.round (startingY + Math.sin (flightDirection) * flightDistance + Math.sin (windDirection) * windSpeed)); while (endingX < 0) { endingX += columns; } while (endingX >= columns) { endingX -= columns; } while (endingY < 0) { endingY += rows; } while (endingY >= rows) { endingY -= rows; } patches [endingY][endingX].land (); } } } } public void infest (int minSuccessfulHealthyAttack, int minSuccessfulWeakAttack) { for (int row = 0; row < rows; row++) { for (int column = 0; column < columns; column++) { patches [row][column].infest (minSuccessfulHealthyAttack, minSuccessfulWeakAttack); } } } public String inventory (int week) { int healthyTrees = 0; int weakTrees = 0; int deadTrees = 0; int beetles = 0; for (int row = 0; row < rows; row++) { for (int column = 0; column < columns; column++) { healthyTrees += patches [row][column].getHealthyTrees (); weakTrees += patches [row][column].getWeakTrees (); deadTrees += patches [row][column].getDeadTrees (); beetles += patches [row][column].getBeetles (); } } return ( "\nWeek: " + week + "\nBeetles: " + beetles + "\nHealthy trees: " + healthyTrees + "\nWeak trees: " + weakTrees + "\nDead trees: " + deadTrees ); } }