Portfolio Code | Clement Colmerauer
Repositories
Site
Rabbit simulation
Code
Commits
Branches
Tags
Search
Tree:
a20104a
Branches
Tags
master
Rabbit simulation
src
Simulation.java
initial commit
Clement COLMERAUER
commited
a20104a
at 2024-09-09 10:17:52
Simulation.java
Blame
History
Raw
package rabbit; import java.util.*; import java.io.*; import cern.jet.random.Uniform; /*---------------------------------------------------------------------* * Simulation : represents a simualtion * *----------------------------------------------------------------------*/ public class Simulation { private Population population; private Parameter parameters; private int startingMonth; private int numberOfMonth; private int actualMonth; private int foodInd; private int predaInd; private Uniform rand; //States (use for print) private State previous; private State actual; //Constants final static double DEATHBYFLOOD = 0.65; final static int LOW = 1; final static int HIGH = 2; /*---------------------------------------------------------------------* * Constructor * * * * Input : * * - _path : a string representing the path to the file * *----------------------------------------------------------------------*/ public Simulation(String _path) throws FileNotFoundException, IOException { //Open file File file = new File(_path); FileReader fr = new FileReader(file); BufferedReader br = new BufferedReader(fr); //Initialization int lineNumber = 0; int rabbitNumber = 0; String line = ""; String[] lineSplit; this.population = new Population(); this.parameters = new Parameter(); Uniform randAdult = new Uniform(Rabbit.ADULT,Rabbit.LIFETIME,5489); Uniform randYoung = new Uniform(0,Rabbit.ADULT,5489); //Process through the file while(line != null) { line = br.readLine(); switch(lineNumber) { //Line for adult male rabbit case 0: //Get rabbit number lineSplit = line.split("\\s+"); lineNumber++; rabbitNumber = Integer.parseInt(lineSplit[1]); //Create new rabbit following the extracted number for(int i = 0 ; i < rabbitNumber ; i++) { this.population.add(new Rabbit(randAdult.nextInt(),'m',3)); } break; //Line for adult female rabbit case 1: //Get rabbit number lineSplit = line.split("\\s+"); rabbitNumber = Integer.parseInt(lineSplit[1]); lineNumber++; //Create new rabbit following the extracted number for(int i = 0 ; i < rabbitNumber ; i++) { this.population.add(new Rabbit(randAdult.nextInt(),'f',3)); } break; //Line for young male rabbit case 2: //Get rabbit number lineSplit = line.split("\\s+"); rabbitNumber = Integer.parseInt(lineSplit[1]); lineNumber++; //Create new rabbit following the extracted number for(int i = 0 ; i < rabbitNumber ; i++) { this.population.add(new Rabbit(randYoung.nextInt(),'m',0)); } break; //Line for young female rabbit case 3: //Get rabbit number lineSplit = line.split("\\s+"); rabbitNumber = Integer.parseInt(lineSplit[1]); lineNumber++; //Create new rabbit following the extracted number for(int i = 0 ; i < rabbitNumber ; i++) { this.population.add(new Rabbit(randYoung.nextInt(),'f',0)); } break; //Line for starting month case 4: //Get month number lineSplit = line.split("\\s+"); this.startingMonth = Integer.parseInt(lineSplit[1]); lineNumber++; break; //Line for number month/iteration case 5: //Get number of month lineSplit = line.split("\\s+"); this.numberOfMonth = Integer.parseInt(lineSplit[1]); lineNumber++; break; //Line for surface case 6: //Get surface lineSplit = line.split("\\s+"); this.parameters.surface(Double.parseDouble(lineSplit[1])); lineNumber++; break; //Line for predators array size case 7: //Get predator array size lineSplit = line.split("\\s+"); this.parameters.predaSize(Integer.parseInt(lineSplit[1])); lineNumber++; break; //Line for predator array case 8: //Split the string lineSplit = line.split("\\s+"); //Iterate over array size for(int i = 0 ; i < this.parameters.predaSize() ; i++) { this.parameters.addPreda(Double.parseDouble(lineSplit[i+1])); } lineNumber++; break; //Line for food arrays size case 9: //Get arrays size lineSplit = line.split("\\s+"); this.parameters.foodSize(Integer.parseInt(lineSplit[1])); lineNumber++; break; //Line for food array case 10: //Splip the string lineSplit = line.split("\\s+"); //Iterate over array size for(int i = 0 ; i < this.parameters.predaSize() ; i++) { this.parameters.addFood(Double.parseDouble(lineSplit[i+1])); } lineNumber++; break; //Line for disease array size case 11: //Get arrays size lineSplit = line.split("\\s+"); this.parameters.diseaseSize(Integer.parseInt(lineSplit[1])); lineNumber++; break; //Line for disease array case 12: //Init this.parameters.initDisease(); //Splip the string lineSplit = line.split("\\s+"); //Iterate over array size for(int i = 0 ; i < lineSplit.length -1 ; i++) { this.parameters.addDisease(i%this.parameters.diseaseSize(),Double.parseDouble(lineSplit[i+1])); } lineNumber++; break; //Line for climate arrays size case 13: //Get array size lineSplit = line.split("\\s+"); this.parameters.climateSize(Integer.parseInt(lineSplit[1])); lineNumber++; break; //Line for climate array case 14: //Init this.parameters.initClimate(); //Splip the string lineSplit = line.split("\\s+"); /*for(int i = 0 ; i < lineSplit.length ; i++) System.console().printf(lineSplit[i] + " ");*/ //Iterate over array size for(int i = 0 ; i < lineSplit.length - 1 ; i++) { this.parameters.addClimate((i)%this.parameters.climateSize(),Integer.parseInt(lineSplit[i+1])); } lineNumber++; break; //Line for starting food index case 15: lineSplit = line.split("\\s+"); this.foodInd = Integer.parseInt(lineSplit[1]); lineNumber++; break; //Line for startingPredaIndex case 16: lineSplit = line.split("\\s+"); this.predaInd = Integer.parseInt(lineSplit[1]); lineNumber++; break; } } //Attribution this.actualMonth = this.startingMonth; this.actual = new State(this.foodInd,this.predaInd); //Init a uniform distribution in [0,1] this.rand = new Uniform(0,1,5489); } /*----------------------------------------------------------------------* * PrintSimulation : print a Simulation to terminal * * * * Input : * * - _sim : a pointer to the Simulation we want to print * *----------------------------------------------------------------------*/ public void print() { //Print population for(int i = 0;i<this.population.size() ; i++) { System.console().printf(String.valueOf(i+1) + ", " +this.population.get(i).toString() + "\n"); } //Print parameters this.parameters.print(); //Print starting month and iteration System.console().printf("Starting food index: %d\nStarting predator index: %d\n",this.foodInd,this.predaInd); System.console().printf("Starting month: %d\nNumber of month: %d\nActual month : %d\n",this.startingMonth,this.numberOfMonth,this.actualMonth); } /*----------------------------------------------------------------------* * reproduction : process through the population and call the reproduce * * methods * *----------------------------------------------------------------------*/ private void reproduction() { //If temperature == moderate if(this.parameters.getClimate(this.actualMonth % this.parameters.climateSize(),0) == 1) { //If it is not dry if(this.parameters.getClimate(this.actualMonth % this.parameters.climateSize(),1)!= 2) { //We clone the list to avoid any unecessary side effect LinkedList<Rabbit> liClone = this.population.clone(); int newRabbit = 0; //For each rabbit for(int i = 0 ; i < liClone.size() ; i++) { newRabbit = this.population.get(i).reproduce(this.population); this.actual.newBorn(newRabbit); } } } } /*----------------------------------------------------------------------* * death : process through the population and compute if the rabbit die * *----------------------------------------------------------------------*/ private void death() { //We clone the list to avoid side effect (like out of bounds) LinkedList<Rabbit> liClone = this.population.clone(); //For each disease for(int i = 0 ; i < this.parameters.diseaseSize() ; i++) { //If disease appear if(rand.nextDouble() < this.parameters.getDisease(i,0)) { //Test on each rabbit for(int j = 0 ; j < liClone.size() ; j++) { if(this.population.size() == 0) { return; } //If population is uniform if(this.population.size()/this.parameters.surface() > this.population.UNIFORMPOP) { //Check if current rabbit survive if(this.rand.nextDouble() > this.parameters.getDisease(i,1)) { this.actual.death(liClone.get(j)); this.population.remove(liClone.get(j)); } } //If population is scattered else if(this.population.size()/this.parameters.surface() <= this.population.UNIFORMPOP) { //Check if current rabbit survive if(this.rand.nextDouble() > this.parameters.getDisease(i,2)) { this.actual.death(liClone.get(j)); this.population.remove(liClone.get(j)); } } } } } //We compute the global survival rate for this month double probaSurvive = this.parameters.getFood(this.foodInd) * this.parameters.getPreda(this.predaInd); //We reset our clone liClone = this.population.clone(); //For each rabbit for(int i = 0 ; i < liClone.size() ; i++) { //Stop case (less computing) if(this.population.size() == 0) { return; } //If a random number in [0,1] is above the survival rate if(this.rand.nextDouble() > probaSurvive) { //Our rabbit die (sad) this.actual.death(liClone.get(i)); this.population.remove(liClone.get(i)); //Use reference instead of index for OOB error } //If the month is humid else if(this.parameters.getClimate(this.actualMonth % this.parameters.climateSize(),1) == 0) { //If our rabbit is young if(liClone.get(i).age() < Rabbit.ADULT) { //If a random number is below the death rate by flood if(this.rand.nextDouble() < DEATHBYFLOOD) { //Our young rabbit die (very sad) this.actual.death(liClone.get(i)); this.population.remove(liClone.get(i)); } } } //If our rabbit is old if(liClone.get(i).age() > Rabbit.LIFETIME) { //1/2 chance to die of oldness if(this.rand.nextDouble() < 0.5) { this.actual.death(liClone.get(i)); this.population.remove(liClone.get(i)); } } } } /*----------------------------------------------------------------------* * modifyParameter : use the actual parameter to determine the parameter * * for next iteration * *----------------------------------------------------------------------*/ private void modifyParameter() { //Switch on month temperature switch(this.parameters.getClimate(this.actualMonth % this.parameters.climateSize(),0)) { //Cold case 0 : if(this.foodInd >= LOW) { this.foodInd -= LOW; } else { this.foodInd = 0; } if(this.predaInd >= LOW) { this.predaInd -= LOW; } else { this.predaInd = 0; } break; //Moderate case 1 : if(this.foodInd < this.parameters.foodSize() - LOW) { this.foodInd += LOW; } break; //Hot case 2 : if(this.foodInd < this.parameters.foodSize() - HIGH) { this.foodInd += HIGH; } if(this.predaInd < this.parameters.predaSize() - LOW) { this.predaInd += LOW; } break; } //Switch on month humidity switch(this.parameters.getClimate(this.actualMonth % this.parameters.climateSize(),1)) { //Humid case 0 : if(this.foodInd < this.parameters.foodSize() - HIGH) { this.foodInd += HIGH; } if(this.predaInd < this.parameters.predaSize() - LOW) { this.predaInd += LOW; } break; //Moderate case 1 : if(this.foodInd < this.parameters.foodSize() - LOW) { this.foodInd += LOW; } break; //Dry case 2 : if(this.foodInd >= LOW) { this.foodInd -= LOW; } else { this.foodInd = 0; } break; } //If our population is very dense (overpopulated) if(this.population.size()/this.parameters.surface() > this.population.DENSITY3) { if(this.foodInd >= HIGH) { this.foodInd -= HIGH; } else { this.foodInd = 0; } if(this.predaInd < this.parameters.predaSize() - HIGH) { this.predaInd += HIGH; } } //Else else if(this.population.size()/this.parameters.surface() > this.population.DENSITY3) { if(this.predaInd >= HIGH) { this.predaInd -= HIGH; } else { this.predaInd = 0; } } } /*----------------------------------------------------------------------* * iterate : iterate over the simulation, compute death, reproduction * * and modify parameters * * * * Input : * * - _path : a String used as relative path to output file * *----------------------------------------------------------------------*/ public void iterate(String _path) throws IOException { //Iterate for(int i = 0 ; i < this.numberOfMonth ; i++) { //Change state this.previous = this.actual; this.actual = new State(); //Age population this.population.aging(); //Compute death this.death(); //Reproduce this.reproduction(); //Alter parameters this.modifyParameter(); //Set the actual state this.actual.set(this.population, this.foodInd,this.predaInd); //Print (both file and terminal) this.actual.print(this.previous, true, _path,i); //Iterate this.actualMonth++; } } /*----------------------------------------------------------------------* * State : repressent a state of a month * *----------------------------------------------------------------------*/ private class State { private int popSize; private int maleAdult; private int maleYoung; private int femaleAdult; private int femaleYoung; private int foodInd; private int predaInd; private int juvenileDeath; private int adultDeath; private int newBorn; /*----------------------------------------------------------------------* * Constructor * *----------------------------------------------------------------------*/ private State() { this.popSize = 0; this.maleAdult = 0; this.maleYoung = 0; this.femaleAdult = 0; this.femaleYoung = 0; this.foodInd = 0; this.predaInd = 0; this.juvenileDeath = 0; this.adultDeath = 0; this.newBorn = 0; } /*----------------------------------------------------------------------* * Constructor * * * * Input : * * - _foodIndex : an int representing the actual food array index * * - _predaIndex : an int representing the actual predator index * *----------------------------------------------------------------------*/ private State(int _foodIndex, int _predaInd) { //Loop for counting rabbits for(int i = 0 ; i < population.size() ; i++) { this.popSize++; if(population.get(i).sexe() == 'f') { if(population.get(i).age() < Rabbit.ADULT) { this.femaleYoung++; } else { this.femaleAdult++; } } else { if(population.get(i).age() < Rabbit.ADULT) { this.maleYoung++; } else { this.maleAdult++; } } } //Attribution this.foodInd = _foodIndex; this.predaInd = _predaInd; this.juvenileDeath = 0; this.adultDeath = 0; this.newBorn = 0; } /*----------------------------------------------------------------------* * newBorn : increment the newBorn count * *----------------------------------------------------------------------*/ private void newBorn(int _new) { this.newBorn += _new; } /*----------------------------------------------------------------------* * death : increment the different death count * *----------------------------------------------------------------------*/ private void death(Rabbit _rab) { if(_rab.age() < _rab.ADULT) { this.juvenileDeath++; } else { this.adultDeath ++; } } /*----------------------------------------------------------------------* * set : work like the second constructor * * * * Input : * * - _pop : the rabbit population * * - _foodIndex : an int representing the actual food array index * * - _predaIndex : an int representing the actual predator index * *----------------------------------------------------------------------*/ private void set(Population _pop, int _foodInd, int _predaInd) { //Count rabbits for(int i = 0 ; i < _pop.size() ; i++) { this.popSize++; if(_pop.get(i).sexe() == 'f') { if(_pop.get(i).age() >= Rabbit.ADULT) { this.maleAdult++; } else { this.maleYoung++; } } else { if(_pop.get(i).age() >= Rabbit.ADULT) { this.femaleAdult++; } else { this.femaleYoung++; } } } this.foodInd = _foodInd; this.predaInd = _predaInd; } /*----------------------------------------------------------------------* * print : print the state * * * * Input : * * - _previous : the previous state * * - _terminal : if true, it will also print in terminal * * - _path : a string used as relative path to output file * *----------------------------------------------------------------------*/ private void print(State _previous, Boolean _terminal, String _path, int _month) throws IOException { //If we want terminal output if(_terminal) { System.console().printf("\n\n\nMonth " + String.valueOf(_month+1) + "\n"); System.console().printf("Death:\n\tAdult: %d\n\tJuvenile: %d\n",this.adultDeath,this.juvenileDeath); System.console().printf("Death rate:\n"); if(_previous.maleAdult()+_previous.femaleAdult() != 0) { System.console().printf("\tAdult: %f%%\n",1f - (double)((_previous.maleAdult()+_previous.femaleAdult() - this.adultDeath)/(double)(_previous.maleAdult()+_previous.femaleAdult()))); } else { System.console().printf("\tAdult: 0%%\n"); } if(_previous.maleYoung()+_previous.femaleYoung() != 0) { System.console().printf("\tJuvenile: %f%%\n",1f-(double)((_previous.maleYoung()+_previous.femaleYoung() - this.juvenileDeath)/(double)(_previous.maleYoung()+_previous.femaleYoung()))); } else { System.console().printf("\tJuvenile: 0%%\n"); } System.console().printf("New born:%d\n",this.newBorn); System.console().printf("Population: %d\n\tAdult male: %d\n\tAdult female: %d\n\tYoung male: %d\n\tYoung female: %d\n",this.popSize,this.maleAdult,this.femaleAdult,this.maleYoung,this.femaleYoung); System.console().printf("Index:\n\tFood: %d\n\tPredator: %d\n",this.foodInd,this.predaInd); } //Open file FileWriter fw = new FileWriter(_path, true); BufferedWriter bw = new BufferedWriter(fw); //Write in file bw.write("Month " + String.valueOf(_month+1) + "\n"); bw.write("Death:\n \tAdult: " + String.valueOf(this.adultDeath) + "\n\tJuvenile: " + String.valueOf(this.juvenileDeath) + "\n"); bw.write("Death rate:\n"); if(_previous.maleAdult()+_previous.femaleAdult() != 0) { bw.write("\tAdult: " + String.valueOf(1f-(double)(_previous.maleAdult()+_previous.femaleAdult() - this.adultDeath)/(double)(_previous.maleAdult()+_previous.femaleAdult())) + "%\n"); } else { bw.write("\tAdult: 0%%\n"); } if(_previous.maleYoung()+_previous.femaleYoung() != 0) { bw.write("\tJuvenile: " + String.valueOf(1f-(double)(_previous.maleYoung()+_previous.femaleYoung() - this.juvenileDeath)/(double)(_previous.maleYoung()+_previous.femaleYoung())) + "%\n"); } else { bw.write("\tJuvenile: 0%%\n"); } bw.write("New born: " + String.valueOf(this.newBorn) + "\n"); bw.write("Population: " + String.valueOf(this.popSize) + "\n\tAdult male: " + String.valueOf(this.maleAdult) + "\n\tAdult female: " + String.valueOf(this.femaleAdult) + "\n\tYoung male: " + String.valueOf(this.maleYoung) + "\n\tYoung female: " + String.valueOf(this.femaleYoung) + "\n"); bw.write("Index:\n\tFood: " + String.valueOf(this.foodInd) + "\n\tPredator: " + String.valueOf(this.predaInd) + "\n\n\n\n"); bw.close(); } /*----------------------------------------------------------------------* * Getter maleYoung * * * * Output : * * - a int representing the number of young male rabbit * *----------------------------------------------------------------------*/ private int maleYoung() { return this.maleYoung; } /*----------------------------------------------------------------------* * Getter maleAdult * * * * Output : * * - a int representing the number of adult male rabbit * *----------------------------------------------------------------------*/ private int maleAdult() { return this.maleAdult; } /*----------------------------------------------------------------------* * Getter femaleYoung * * * * Output : * * - a int representing the number of young fmmale rabbit * *----------------------------------------------------------------------*/ private int femaleYoung() { return this.femaleYoung; } /*----------------------------------------------------------------------* * Getter femaleAdult * * * * Output : * * - a int representing the number of adult female rabbit * *----------------------------------------------------------------------*/ private int femaleAdult() { return this.femaleAdult; } } }