cleaned the simulator and MyInterface, and annotated them

This commit is contained in:
Timéo 2024-05-31 17:24:26 +02:00
parent bbd1604b5b
commit a8a6c556b7
2 changed files with 101 additions and 178 deletions

View File

@ -29,15 +29,13 @@ public class Simulator extends Thread {
private int clickActionFlag; private int clickActionFlag;
private int loopDelay = 150; private int loopDelay = 150;
private int[][] world; private int[][] world;
//private int[] survivalRulesArray;
//private int[] birthRulesArray;
private int[] birthRulesArrays = new int[0]; private int[] birthRulesArrays = new int[0];
//this will allow us to store the different rules about the birth of new cells
private int[] surviveRulesArrays = new int[0]; private int[] surviveRulesArrays = new int[0];
//this will allow us to store the different rules about the survival of new cells
//TODO : add missing attribute(s)
private int stepCount; private int stepCount;
public Simulator(MyInterface mjfParam) { public Simulator(MyInterface mjfParam) {
mjf = mjfParam; mjf = mjfParam;
//stopFlag=false; //not necessary since i set the state when pressing the button start //stopFlag=false; //not necessary since i set the state when pressing the button start
@ -49,7 +47,7 @@ public class Simulator extends Thread {
fieldBirthValues = new ArrayList<Integer>(); fieldBirthValues = new ArrayList<Integer>();
fieldSurviveValues = new ArrayList<Integer>(); fieldSurviveValues = new ArrayList<Integer>();
world =new int[getWidth()][getHeight()]; world =new int[getWidth()][getHeight()];
//TODO : add missing attribute initialization //this allows us to define our world and it's size
@ -68,6 +66,11 @@ public class Simulator extends Thread {
return LINE_NUM; return LINE_NUM;
} }
//this method gets the value in our CSV files for the rules
//and places them in the right format in the right array
//it ten tells you whether your file is empty, and if there is at least one survival rule
//if the rules are loaded in the array successfully then it tells you "rules loaded successfully"
public void loadRule(ArrayList<String> row) { public void loadRule(ArrayList<String> row) {
String surviveRulesRow = row.get(0).replace("\"","").trim(); String surviveRulesRow = row.get(0).replace("\"","").trim();
String[] surviveCells = surviveRulesRow.split(";"); String[] surviveCells = surviveRulesRow.split(";");
@ -100,39 +103,16 @@ public class Simulator extends Thread {
System.out.println("Error parsing rule values: " + e.getMessage()); System.out.println("Error parsing rule values: " + e.getMessage());
} }
} }
/*for (int x = 0; x < birthCells.length; x++) {
String[] birthElements = birthCells[x].split(",");
int[] birthRulesArray = new int[birthElements.length];
for (int y = 0; y < birthElements.length; y++) {
String elem = birthElements[y];
int value = Integer.parseInt(elem);
birthRulesArray[y] = value;
}
this.birthRulesArrays[x] = birthRulesArray;
System.out.println("birth rule taken into account");
}
//determines the number of alive neighboring cells needed to birth, and places them in the birthCells list
for (int x = 0; x < surviveCells.length; x++) {
String[] surviveElements = surviveCells[x].split(",");
int[] surviveArray = new int[surviveElements.length];
for (int y = 0; y < surviveElements.length; y++) {
String elem = surviveElements[y];
int value = Integer.parseInt(elem);
surviveArray[y] = value;
}
this.surviveRulesArrays[x] = surviveArray;
System.out.println("survival rule taken into account");
}*/
//determines the number of alive neighboring cells needed to survive, and places them in the surviveCells list
} }
//getter for the birth rules
public int[] getBirthRulesArray() { public int[] getBirthRulesArray() {
return this.birthRulesArrays; return this.birthRulesArrays;
} }
//getter for the survival rules
public int[] getSurvivalRulesArray() { public int[] getSurvivalRulesArray() {
return this.surviveRulesArrays; return this.surviveRulesArrays;
} }
@ -162,13 +142,10 @@ public class Simulator extends Thread {
} }
/**
* method called at each step of the simulation
* makes all the actions to go from one step to the other
*/
//method used to calculate the number of neighbors to one cell that are alive,
//and to return this number
private int countAliveNeighbors(int x, int y) { private int countAliveNeighbors(int x, int y) {
int count = 0; int count = 0;
int[][] directions = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; int[][] directions = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
@ -186,13 +163,15 @@ public class Simulator extends Thread {
return count; return count;
} }
//initiates the world with the right components
public void setWorld(int[][] world, int width, int height) { public void setWorld(int[][] world, int width, int height) {
this.world = world; this.world = world;
this.COL_NUM = width; this.COL_NUM = width;
this.LINE_NUM = height; this.LINE_NUM = height;
} }
//determines whether or not the studied cell should survive
//depending on the number of alive neighbors and the loaded rules
private boolean shouldSurvive(int aliveNeighbors) { private boolean shouldSurvive(int aliveNeighbors) {
for (int value : getSurvivalRulesArray()) { for (int value : getSurvivalRulesArray()) {
if ( value == aliveNeighbors) { if ( value == aliveNeighbors) {
@ -201,6 +180,8 @@ public class Simulator extends Thread {
}return false; }return false;
} }
//determines whether or not the studied cell should become alive
//depending on the number of alive neighbors and the loaded rules
private boolean shouldBeBorn(int aliveNeighbors) { private boolean shouldBeBorn(int aliveNeighbors) {
for(int value : getBirthRulesArray()) { for(int value : getBirthRulesArray()) {
if (value == aliveNeighbors) { if (value == aliveNeighbors) {
@ -212,11 +193,9 @@ public class Simulator extends Thread {
public void makeStep() { public void makeStep() {
// agent behaviors first
// only modify if sure of what you do
// to modify agent behavior, see liveTurn method
// in agent classes
//this part is used to make the agents move and
//according to their own rules, go to the next generation
for (int i = agents.size() - 1; i >= 0; i--) { for (int i = agents.size() - 1; i >= 0; i--) {
Agent agent = agents.get(i); Agent agent = agents.get(i);
ArrayList<Agent> neighbors = this.getNeighboringAnimals(agent.getX(), agent.getY(), ANIMAL_AREA_RADIUS); ArrayList<Agent> neighbors = this.getNeighboringAnimals(agent.getX(), agent.getY(), ANIMAL_AREA_RADIUS);
@ -224,34 +203,10 @@ public class Simulator extends Thread {
agents.remove(i); agents.remove(i);
} }
} }
/*ArrayList<Agent> newAgents = new ArrayList<>();
for(Agent agent : agents) {
ArrayList<Agent> neighbors =
this.getNeighboringAnimals(
agent.getX(),
agent.getY(),
ANIMAL_AREA_RADIUS);}
if(!agent.liveTurn(
neighbors,
this)) {
agents.remove(agent);
}*/
// Apply Game of Life rules
/*for (int x = 0; x < getWidth(); x++) {
for (int y = 0; y < getHeight(); y++) {
int aliveNeighbors = countAliveNeighbors(x, y);
if (world[x][y] == 1) {
newWorld[x][y] = (aliveNeighbors < 2 || aliveNeighbors > 3) ? 0 : 1;
} else {
newWorld[x][y] = (aliveNeighbors == 3) ? 1 : 0;
}
}
}*/
//this part is used for the cells, in order to make them go to the next generation
//according to the loaded rules, and the agents actions
int[][] newWorld = new int[getWidth()][getHeight()]; int[][] newWorld = new int[getWidth()][getHeight()];
for (int x = 0; x < getWidth(); x++) { for (int x = 0; x < getWidth(); x++) {
@ -276,53 +231,29 @@ public class Simulator extends Thread {
//then evolution of the field
// TODO : apply game rule to all cells of the field
/* you should distribute this action in methods/classes
* don't write everything here !
*
* the idea is first to get the surrounding values
* then count how many are alive
* then check if that number is in the lists of rules
* if the cell is alive
* and the count is in the survive list,
* then the cell stays alive
* if the cell is not alive
* and the count is in the birth list,
* then the cell becomes alive
*/
/*
* leave this as is
*/
public void stopSimu() { public void stopSimu() {
stopFlag=true; stopFlag=true;
} }
public void startSimu() { // same as stopSimu but will set the stopFlag value as false. public void startSimu() { // same as stopSimu but will set the stopFlag value as false.
stopFlag=false; stopFlag=false;
} }
/*
* method called when clicking pause button
*/
public void togglePause() { public void togglePause() {
pauseFlag= ! pauseFlag; pauseFlag= ! pauseFlag;
// It changes the boolean value associated to pauseFlag (pauseFlag= not pauseFlag) // It changes the boolean value associated to pauseFlag (pauseFlag= not pauseFlag)
} }
/**
* method called when clicking on a cell in the interface //method called when clicking on a cell in the interface
*/
public void clickCell(int x, int y) { public void clickCell(int x, int y) {
if (clickActionFlag==0) { // cell if (clickActionFlag==0) { // cell
setCell(x, y, getCell(x, y) == 1 ? 0 : 1); setCell(x, y, getCell(x, y) == 1 ? 0 : 1);
} else if (clickActionFlag==1) { // sheep } else if (clickActionFlag==1) { // sheep
ArrayList<Agent> nearby=getNeighboringAnimals(x,y,1); //look if the cell has an agent ArrayList<Agent> nearby=getNeighboringAnimals(x,y,1); //checks if the cell has an agent
if (nearby.isEmpty()) { if (nearby.isEmpty()) {
Sheep sheep = new Sheep(x,y); Sheep sheep = new Sheep(x,y);
agents.add(sheep); agents.add(sheep);
@ -345,30 +276,20 @@ public class Simulator extends Thread {
} }
/**
* get cell value in simulated world
* @param x coordinate of cell
* @param y coordinate of cell
* @return value of cell
*/
public int getCell(int x, int y) { public int getCell(int x, int y) {
return world[x][y]; return world[x][y];
//get the value (dead or alive) of my cell at x y //get the value (dead or alive) of my cell at x y
} }
/**
*
* @return list of Animals in simulated world //returns the list of the animals in the world
*/
public ArrayList<Agent> getAnimals(){ public ArrayList<Agent> getAnimals(){
return agents; return agents;
} }
/**
* selects Animals in a circular area of simulated world
* @param x center //gets the list of the agents in the area around our studied agent
* @param y center
* @param radius
* @return list of agents in area
*/
public ArrayList<Agent> getNeighboringAnimals(int x, int y, int radius){ public ArrayList<Agent> getNeighboringAnimals(int x, int y, int radius){
ArrayList<Agent> inArea = new ArrayList<Agent>(); ArrayList<Agent> inArea = new ArrayList<Agent>();
for(int i=0;i<agents.size();i++) { for(int i=0;i<agents.size();i++) {
@ -379,8 +300,10 @@ public class Simulator extends Thread {
} }
return inArea; return inArea;
} }
//gets the type of the animal
public String typeAnimals(int x , int y,ArrayList<Agent> neighbor) { public String typeAnimals(int x , int y,ArrayList<Agent> neighbor) {
//ArrayList<Agent> neighbor =getNeighboringAnimals(x,y,1);
Agent agent = neighbor.get(0); Agent agent = neighbor.get(0);
if (agent instanceof Wolf) { if (agent instanceof Wolf) {
return "Wolf"; return "Wolf";
@ -388,22 +311,15 @@ public class Simulator extends Thread {
return "Sheep"; return "Sheep";
} }
} }
/**
* set value of cell
* @param x coord of cell //sets the value of the cell at the coordinates x and y
* @param y coord of cell
* @param val to set in cell
*/
public void setCell(int x, int y, int val) { public void setCell(int x, int y, int val) {
world [x][y] = val; world [x][y] = val;
} }
/**
* //stores a world in a CSV files, to be reopened later on
* @return lines of file representing
* the simulated world in its present state
*/
public ArrayList<String> getSaveState() { public ArrayList<String> getSaveState() {
ArrayList<String> saveState = new ArrayList<>(); ArrayList<String> saveState = new ArrayList<>();
for (int j = 0; j < getHeight(); j++) { for (int j = 0; j < getHeight(); j++) {
@ -420,17 +336,11 @@ public class Simulator extends Thread {
} }
/**
*
* @param lines of file representing saved world state //reads and returns the lines of the CSV files that was saved using getSaveState
*/
public void loadSaveState(ArrayList<String> lines) { public void loadSaveState(ArrayList<String> lines) {
/*
* First some checks that the file is usable
* We call early returns in conditions like this
* "Guard clauses", as they guard the method
* against unwanted inputs
*/
if(lines.size()<=0) { if(lines.size()<=0) {
return; return;
} }
@ -439,10 +349,7 @@ public class Simulator extends Thread {
if(firstLineElements.length<=0) { if(firstLineElements.length<=0) {
return; return;
} }
/*
* now we fill in the world
* with the content of the file
*/
for(int y =0; y<lines.size();y++) { for(int y =0; y<lines.size();y++) {
String line = lines.get(y); String line = lines.get(y);
String[] lineElements = line.split(";"); String[] lineElements = line.split(";");
@ -455,11 +362,12 @@ public class Simulator extends Thread {
} }
public ArrayList<String> getRule() { //to check //is used to save a rule in a CSV file
public ArrayList<String> getRule() {
ArrayList<String> rule = new ArrayList<>(); ArrayList<String> rule = new ArrayList<>();
for (int i = 0; i < getHeight(); i++) { for (int i = 0; i < getHeight(); i++) {
StringBuilder lineState = new StringBuilder(); StringBuilder lineState = new StringBuilder();
for (int j = 0 ; j < getHeight() ; j++) { // je crois qu'il y a un probleme, il fau+t mettre getWidth je crois for (int j = 0 ; j < getHeight() ; j++) {
lineState.append(getCell(i, j)); lineState.append(getCell(i, j));
if (j < getWidth() - 1) { if (j < getWidth() - 1) {
lineState.append(";"); lineState.append(";");
@ -471,14 +379,9 @@ public class Simulator extends Thread {
} }
//is used to generate a random world when the game is ran
//or when you click on the random button
public void generateRandom(float chanceOfLife) { public void generateRandom(float chanceOfLife) {
/*
* Advice :
* as you should probably have a separate class
* representing the field of cells...
* maybe just make a constructor in there
* and use it here
*/
Random rand = new Random(); Random rand = new Random();
for (int x = 0; x < COL_NUM; x++) { for (int x = 0; x < COL_NUM; x++) {
for (int y = 0; y < LINE_NUM; y++) { for (int y = 0; y < LINE_NUM; y++) {
@ -487,10 +390,12 @@ public class Simulator extends Thread {
} }
} }
//checks if the border is put as looping
public boolean isLoopingBorder() { public boolean isLoopingBorder() {
return loopingBorder; return loopingBorder;
} }
//allows to change from looping to not looping border
public void toggleLoopingBorder() { public void toggleLoopingBorder() {
if (loopingBorder){ if (loopingBorder){
loopingBorder = false; loopingBorder = false;
@ -499,11 +404,14 @@ public class Simulator extends Thread {
} }
} }
public void setLoopDelay(int delay) { public void setLoopDelay(int delay) {
loopDelay = delay; loopDelay = delay;
} }
//changes the object that will be placed using the toggle click button
public void toggleClickAction() { public void toggleClickAction() {
if (clickActionFlag < 2) { if (clickActionFlag < 2) {
clickActionFlag ++ ; clickActionFlag ++ ;
@ -512,18 +420,7 @@ public class Simulator extends Thread {
} }
} }
/** //stores where and what the agents are on the saved world
* prepare the content of a file saving present ruleSet
* as you might want to save a state,
* initialy written in this class constructor
* as a file for future use
* @return File content as an ArrayList of Lines (String)
* @see loadRule for inverse process
*/
public ArrayList<String> getAgentsSave() { public ArrayList<String> getAgentsSave() {
ArrayList<String> agentsList = new ArrayList<String>(); ArrayList<String> agentsList = new ArrayList<String>();
String sheepLine = "1,"; String sheepLine = "1,";
@ -545,8 +442,9 @@ public class Simulator extends Thread {
return agentsList; return agentsList;
} }
//allows to load a predefined set of agents on the world
public void loadAgents(ArrayList<String> stringArray) { public void loadAgents(ArrayList<String> stringArray) {
//TODO : Same idea as other load methods, but for agent list
for(int y =0; y<stringArray.size();y++) { for(int y =0; y<stringArray.size();y++) {
String line = stringArray.get(y); String line = stringArray.get(y);
String[] lineElements = line.split(","); String[] lineElements = line.split(",");
@ -567,10 +465,7 @@ public class Simulator extends Thread {
} }
} }
/**
* used by label in interface to show the active click action
* @return String representation of click action
*/
public String clickActionName() { public String clickActionName() {
if (clickActionFlag==0) { if (clickActionFlag==0) {
return "cell"; return "cell";
@ -584,7 +479,7 @@ public class Simulator extends Thread {
} }
} }
//used to reset the world, to empty it when the reset button is clicked
public void reset() { public void reset() {
for (int i = 0; i < getHeight(); i++) { for (int i = 0; i < getHeight(); i++) {
for (int j = 0 ; j < getWidth() ; j++) { for (int j = 0 ; j < getWidth() ; j++) {
@ -599,7 +494,7 @@ public class Simulator extends Thread {
} }
//checks whether or not the world is empty
public boolean isWorldEmpty() { public boolean isWorldEmpty() {
for (int x = 0; x < getWidth(); x++) { for (int x = 0; x < getWidth(); x++) {
for (int y = 0; y < getHeight(); y++) { for (int y = 0; y < getHeight(); y++) {
@ -612,7 +507,7 @@ public class Simulator extends Thread {
} }
//starts the simulation
public void startSimulation() { public void startSimulation() {
mjf.generateRandomBoard(); mjf.generateRandomBoard();
} }

View File

@ -219,6 +219,8 @@ public class MyInterface extends JFrame {
return panelDraw; return panelDraw;
} }
public void instantiateSimu() { public void instantiateSimu() {
if(mySimu==null) { if(mySimu==null) {
mySimu = new Simulator(this); mySimu = new Simulator(this);
@ -226,6 +228,8 @@ public class MyInterface extends JFrame {
} }
} }
//allows to check if the world is alive and empty, and if it is to start a random world. If the world is already alive, then it will pause the simulation
public void clicButtonGo() { public void clicButtonGo() {
this.instantiateSimu(); this.instantiateSimu();
if(!mySimu.isAlive()) { if(!mySimu.isAlive()) {
@ -239,6 +243,9 @@ public class MyInterface extends JFrame {
} }
} }
public void clicButtonStop() { public void clicButtonStop() {
mySimu.stopSimu(); // Stop the simulation mySimu.stopSimu(); // Stop the simulation
@ -247,6 +254,8 @@ public class MyInterface extends JFrame {
eraseLabels(); // Reset the labels to their initial state eraseLabels(); // Reset the labels to their initial state
} }
public void clicButtonToggleClickAction() { public void clicButtonToggleClickAction() {
if(mySimu != null) { if(mySimu != null) {
mySimu.toggleClickAction(); mySimu.toggleClickAction();
@ -254,6 +263,8 @@ public class MyInterface extends JFrame {
} }
} }
public void clicButtonBorder() { public void clicButtonBorder() {
if(mySimu != null) { if(mySimu != null) {
mySimu.toggleLoopingBorder(); mySimu.toggleLoopingBorder();
@ -262,6 +273,8 @@ public class MyInterface extends JFrame {
} }
} }
public void generateRandomBoard() { public void generateRandomBoard() {
this.instantiateSimu(); this.instantiateSimu();
float chanceOfLife = ((float)randSlider.getValue())/((float)randSlider.getMaximum()); float chanceOfLife = ((float)randSlider.getValue())/((float)randSlider.getMaximum());
@ -269,6 +282,8 @@ public class MyInterface extends JFrame {
panelDraw.repaint(); panelDraw.repaint();
} }
public void changeSpeed() { public void changeSpeed() {
if(mySimu != null) { if(mySimu != null) {
int delay = (int)Math.pow(2, 10-speedSlider.getValue()); int delay = (int)Math.pow(2, 10-speedSlider.getValue());
@ -278,6 +293,8 @@ public class MyInterface extends JFrame {
} }
} }
public void clicLoadFileButton() { public void clicLoadFileButton() {
Simulator loadedSim = new Simulator(this); Simulator loadedSim = new Simulator(this);
String fileName=SelectFile(); String fileName=SelectFile();
@ -306,12 +323,9 @@ public class MyInterface extends JFrame {
} }
//used to read a CSV file, which we tried to implement in order to create a baseworld that would appear when starting an empty world
//trying to make the baseworld
//to integrate the baseworld
public void clicLoadFileButtonCSV(String fileName) { public void clicLoadFileButtonCSV(String fileName) {
Simulator loadedSim = new Simulator(this); Simulator loadedSim = new Simulator(this);
//String fileName="baseworld.csv";
ArrayList<String> stringArray = new ArrayList<String>(); ArrayList<String> stringArray = new ArrayList<String>();
if (fileName.length()>0) { if (fileName.length()>0) {
try { try {
@ -339,7 +353,6 @@ public class MyInterface extends JFrame {
public void clicLoadRuleFileButton() { public void clicLoadRuleFileButton() {
String fileName=SelectFile(); String fileName=SelectFile();
ArrayList<String> stringArray = new ArrayList<String>(); ArrayList<String> stringArray = new ArrayList<String>();
@ -360,6 +373,8 @@ public class MyInterface extends JFrame {
} }
} }
public void clicLoadAgentsFileButton() { public void clicLoadAgentsFileButton() {
String fileName=SelectFile(); String fileName=SelectFile();
ArrayList<String> stringArray = new ArrayList<String>(); ArrayList<String> stringArray = new ArrayList<String>();
@ -381,6 +396,7 @@ public class MyInterface extends JFrame {
} }
//used to read a world and save it as a file in the computer, to be reopened later on
public void clicSaveToFileButton() { public void clicSaveToFileButton() {
String fileName=SelectFile(); String fileName=SelectFile();
if (fileName.length()>0) { if (fileName.length()>0) {
@ -390,6 +406,9 @@ public class MyInterface extends JFrame {
} }
} }
public void clicSaveRuleToFileButton() { public void clicSaveRuleToFileButton() {
String fileName=SelectFile(); String fileName=SelectFile();
if (fileName.length()>0) { if (fileName.length()>0) {
@ -399,6 +418,8 @@ public class MyInterface extends JFrame {
} }
} }
public void clicSaveAgentsToFileButton() { public void clicSaveAgentsToFileButton() {
String fileName=SelectFile(); String fileName=SelectFile();
if (fileName.length()>0) { if (fileName.length()>0) {
@ -409,6 +430,7 @@ public class MyInterface extends JFrame {
} }
public String SelectFile() { public String SelectFile() {
String s; String s;
JFileChooser chooser = new JFileChooser(); JFileChooser chooser = new JFileChooser();
@ -425,6 +447,8 @@ public class MyInterface extends JFrame {
return s; return s;
} }
public void writeFile(String fileName, String[] content) { public void writeFile(String fileName, String[] content) {
FileWriter csvWriter; FileWriter csvWriter;
try { try {
@ -440,11 +464,15 @@ public class MyInterface extends JFrame {
} }
} }
public void update (int stepCount) { public void update (int stepCount) {
this.setStepBanner("Step : "+ stepCount); this.setStepBanner("Step : "+ stepCount);
this.repaint(); this.repaint();
} }
public void eraseLabels() { public void eraseLabels() {
this.setStepBanner("Step : X"); this.setStepBanner("Step : X");
this.setBorderBanner("border : X"); this.setBorderBanner("border : X");