package model; import java.util.ArrayList; import java.util.HashMap; import java.util.Random; import main.EcologiaIO; import controller.Humidity; import controller.OccupantType; import controller.World; /** * The Simulator class is the main class of the model package. It manages all * elements of the actual simulation, and passes any relevant information on * to World. * * @author Daniel Vedder * @version 30.8.2014 */ public class Simulator { private static ArrayList<Herbivore> herbivorePopulation; private static ArrayList<Carnivore> carnivorePopulation; private static MapField[][] map; private Random random; /** * The constructor. */ public Simulator() { EcologiaIO.debug("Creating simulator"); random = new Random(); initMap(); initWaterTiles(); initPopulations(); updateWorld(); } /** * Updates the model each turn. */ public void update() { //Calculate the new grass density on each plot EcologiaIO.debug("Simulator: Recalculating grass density."); double averageDensity = 0; int xsize = World.getInstance().getParam("xsize"); int ysize = World.getInstance().getParam("ysize"); for (int x = 0; x < xsize; x++) { for (int y = 0; y < ysize; y++) { if (!map[x][y].nearWater()) { map[x][y].setLocalHumidity(Humidity.getStatus(World.getInstance().getParam("humidity"))); } map[x][y].calculateGrassDensity(); averageDensity += map[x][y].getGrassDensity(); } } averageDensity = averageDensity/(xsize*ysize); World.getInstance().setAverageGrassDensity((int) averageDensity); //Each animal has its turn EcologiaIO.debug("Simulator: Updating herbivores."); for (int h = 0; h < herbivorePopulation.size(); h++) { herbivorePopulation.get(h).update(); } EcologiaIO.debug("Simulator: Updating carnivores."); for (int c = 0; c < carnivorePopulation.size(); c++) { // <-- C++ in a Java program :D carnivorePopulation.get(c).update(); } double hunt_success = (double) Carnivore.fights_won / (double) Carnivore.total_fights; EcologiaIO.analysis("Carnivore hunt success rate: "+(int) (hunt_success*100)+"%"); updateWorld(); } /** * Send the current state of the simulation on to World */ public void updateWorld() { EcologiaIO.debug("Simulator: Collecting information to send to World."); //The states of all animals are collected and passed on to the World ArrayList<HashMap<String, Integer>> animalInfo = new ArrayList<HashMap<String, Integer>>(); for (int hi = 0; hi < herbivorePopulation.size(); hi++) { animalInfo.add(herbivorePopulation.get(hi).getInfo()); } for (int ci = 0; ci < carnivorePopulation.size(); ci++) { animalInfo.add(carnivorePopulation.get(ci).getInfo()); } World.getInstance().setAnimals(animalInfo); //Update the population counters World.getInstance().setCarnivoreCount(carnivorePopulation.size()); World.getInstance().setHerbivoreCount(herbivorePopulation.size()); } /* * Component initialisation */ /** * Initialise the map. */ private void initMap() { EcologiaIO.debug("Simulator: initialising map."); int xsize = World.getInstance().getParam("xsize"); int ysize = World.getInstance().getParam("ysize"); map = new MapField[xsize][ysize]; for (int x = 0; x < xsize; x++) { for (int y = 0; y < ysize; y++) { map[x][y] = new MapField(x, y, OccupantType.NONE, Humidity.getStatus(World.getInstance().getParam("humidity")), World.getInstance().getParam("startGrassDensity")); } } } /** * Initialise the water tiles. */ private void initWaterTiles() { EcologiaIO.debug("Simulator: initialising water tiles."); for (int i = 0; i < World.getInstance().getParam("waterTiles"); i++) { //Each water tile is placed in a random location int setX = random.nextInt(World.getInstance().getParam("xsize")); int setY = random.nextInt(World.getInstance().getParam("ysize")); while (map[setX][setY].getOccupant() != OccupantType.NONE) { setX = random.nextInt(World.getInstance().getParam("xsize")); setY = random.nextInt(World.getInstance().getParam("ysize")); } map[setX][setY].setOccupant(OccupantType.WATER); //The fields around each water tile are watered for (int x = setX-2; x <= setX+2; x++) { for (int y = setY-2; y <= setY+2; y++) { try { Simulator.getField(x, y).setNearWater(true); Simulator.getField(x, y).setLocalHumidity(Humidity.SATURATION); } catch (ArrayIndexOutOfBoundsException aioobe) {} //Can be safely ignored } } } } /** * Initialise the animal populations. */ private void initPopulations() { carnivorePopulation = new ArrayList<Carnivore>(); herbivorePopulation = new ArrayList<Herbivore>(); //Create the initial carnivore population, setting each carnivore down at a random position EcologiaIO.debug("Simulator: initialising carnivores."); for (int j = 0; j < World.getInstance().getParam("startNoCarnivores"); j++) { int setXCarnivore = random.nextInt(World.getInstance().getParam("xsize")); int setYCarnivore = random.nextInt(World.getInstance().getParam("ysize")); while (map[setXCarnivore][setYCarnivore].getOccupant() != OccupantType.NONE) { setXCarnivore = random.nextInt(World.getInstance().getParam("xsize")); setYCarnivore = random.nextInt(World.getInstance().getParam("ysize")); } int startEnergyCarnivores = World.getInstance().getParam("startEnergyCarnivores"); carnivorePopulation.add(new Carnivore(World.getInstance().getNextID(), Carnivore.defaultGenome, 1, setXCarnivore, setYCarnivore, startEnergyCarnivores, 0)); } //Create the initial herbivore population, setting each herbivore down at a random position EcologiaIO.debug("Simulator: initialising herbivores."); for (int i = 0; i < World.getInstance().getParam("startNoHerbivores"); i++) { int setXHerbivore = random.nextInt(World.getInstance().getParam("xsize")); int setYHerbivore = random.nextInt(World.getInstance().getParam("ysize")); while (map[setXHerbivore][setYHerbivore].getOccupant() != OccupantType.NONE) { setXHerbivore = random.nextInt(World.getInstance().getParam("xsize")); setYHerbivore = random.nextInt(World.getInstance().getParam("ysize")); } int startEnergyHerbivores = World.getInstance().getParam("startEnergyHerbivores"); herbivorePopulation.add(new Herbivore(World.getInstance().getNextID(), Herbivore.defaultGenome, 1, setXHerbivore, setYHerbivore, startEnergyHerbivores, 0)); } } /* * Interface methods for interacting with map and animals */ /** * Returns the field at the required position. * @param x, y * @return MapField */ public static MapField getField(int x, int y) { return map[x][y]; } /** * Return the animal at (x, y), or null if there is no animal at that field. */ public static Animal getAnimal(int x, int y) { Animal a = getHerbivore(x, y); if (a == null) a = getCarnivore(x, y); return a; } /** * Return the herbivore at (x, y), or null if there is no animal at that field. */ public static Herbivore getHerbivore(int x, int y) { for (int h = 0; h < herbivorePopulation.size(); h++) { if (herbivorePopulation.get(h).getX() == x && herbivorePopulation.get(h).getY() == y) { return herbivorePopulation.get(h); } } return null; } /** * Return the carnivore at (x, y), or null if there is no animal at that field. */ public static Carnivore getCarnivore(int x, int y) { for (int c = 0; c < carnivorePopulation.size(); c++) { if (carnivorePopulation.get(c).getX() == x && carnivorePopulation.get(c).getY() == y) { return carnivorePopulation.get(c); } } return null; } /** * Add an animal to the population * @param animal */ public static void addAnimal(Animal a) { EcologiaIO.debug("Simulator: adding a "+a.getType().toString()); if (a.getType() == OccupantType.HERBIVORE) { herbivorePopulation.add((Herbivore) a); } else if (a.getType() == OccupantType.CARNIVORE) { carnivorePopulation.add((Carnivore) a); } else { EcologiaIO.error("Simulator: Invalid OccupantType passed to addAnimal()!", EcologiaIO.FATAL_ERROR); } } /** * Remove an animal from the population * @param x, y coordinates * @param type Make sure we are removing the right animal */ public static void removeAnimal(int x, int y, OccupantType type) { Animal a = null; if (type == OccupantType.CARNIVORE) a = getCarnivore(x, y); else if (type == OccupantType.HERBIVORE) a = getHerbivore(x, y); if (a == null) { EcologiaIO.error("Simulator.removeAnimal(): no "+type.toString()+" at "+x+"/"+y+"."); } else if (type == OccupantType.HERBIVORE) { herbivorePopulation.remove((Herbivore) a); map[x][y].setOccupant(OccupantType.NONE); EcologiaIO.debug("Simulator: removing a herbivore."); } else if (type == OccupantType.CARNIVORE) { carnivorePopulation.remove((Carnivore) a); map[x][y].setOccupant(OccupantType.NONE); EcologiaIO.debug("Simulator: removing a carnivore."); } else { EcologiaIO.error("Simulator: Invalid OccupantType passed to removeAnimal()!", EcologiaIO.FATAL_ERROR); } if (a != null) EcologiaIO.analysis("Animal "+a.getID()+" died at age "+a.getAge()); } }