package backend; import java.util.ArrayList; import java.util.Random; import windowInterface.MyInterface; public class Simulator extends Thread { private MyInterface mjf; private final int COL_NUM = 100; private final int LINE_NUM = 100; private final int LIFE_TYPE_NUM = 4; //Conway Radius : 1 private final int LIFE_AREA_RADIUS = 1; //Animal Neighborhood Radius : 5 private final int ANIMAL_AREA_RADIUS = 2; private ArrayList fieldSurviveValues; private ArrayList fieldBirthValues; private ArrayList agents; private boolean stopFlag; private boolean pauseFlag; private boolean loopingBorder; private boolean clickActionFlag; private int loopDelay = 150; private int[][] world; //TODO : add missing attribute(s) public Simulator(MyInterface mjfParam) { mjf = mjfParam; stopFlag=false; pauseFlag=false; loopingBorder=false; clickActionFlag=false; agents = new ArrayList(); fieldBirthValues = new ArrayList(); fieldSurviveValues = new ArrayList(); world =new int[getWidth()][getHeight()]; //TODO : add missing attribute initialization //Default rule : Survive always, birth never for(int i =0; i<9; i++) { fieldSurviveValues.add(i); } } public int getWidth() { return COL_NUM; } public int getHeight() { return LINE_NUM; } //Should probably stay as is public void run() { int stepCount=0; while(!stopFlag) { stepCount++; makeStep(); mjf.update(stepCount); try { Thread.sleep(loopDelay); } catch (InterruptedException e) { e.printStackTrace(); } while(pauseFlag && !stopFlag) { try { Thread.sleep(loopDelay); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * method called at each step of the simulation * makes all the actions to go from one step to the other */ private int countAliveNeighbors(int x, int y) { int count = 0; int[][] directions = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; for (int[] dir : directions) { int nx = x + dir[0]; int ny = y + dir[1]; if (nx >= 0 && nx < getWidth() && ny >= 0 && ny < getHeight()) { count += world[nx][ny]; } else if (loopingBorder) { nx = (nx + getWidth()) % getWidth(); ny = (ny + getHeight()) % getHeight(); count += world[nx][ny]; } } return count; } public void makeStep() { // agent behaviors first // only modify if sure of what you do // to modify agent behavior, see liveTurn method // in agent classes int[][] newWorld = new int[getWidth()][getHeight()]; // 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; } } } world = newWorld; ArrayList newAgents = new ArrayList<>(); for(Agent agent : agents) { ArrayList neighbors = this.getNeighboringAnimals( agent.getX(), agent.getY(), ANIMAL_AREA_RADIUS);} //if(!agent.liveTurn( // neighbors, // this)) { // agents.remove(agent); //{ } //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() { stopFlag=true; } /* * method called when clicking pause button */ public void togglePause() { pauseFlag= ! pauseFlag; // It changes the boolean value associated to pauseFlag (pauseFlag= not pauseFlag) } /** * method called when clicking on a cell in the interface */ public void clickCell(int x, int y) { setCell(x, y, getCell(x, y) == 1 ? 0 : 1); } /** * 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) { return world[x][y]; //get the value (dead or alive) of my cell at x y } /** * * @return list of Animals in simulated world */ public ArrayList getAnimals(){ return agents; } /** * selects Animals in a circular area of simulated world * @param x center * @param y center * @param radius * @return list of agents in area */ public ArrayList getNeighboringAnimals(int x, int y, int radius){ ArrayList inArea = new ArrayList(); for(int i=0;i getSaveState() { ArrayList saveState = new ArrayList<>(); for (int i = 0; i < getHeight(); i++) { StringBuilder lineState = new StringBuilder(); for (int j = 0 ; j < getHeight() ; j++) { lineState.append(getCell(i, j)); if (j < getWidth() - 1) { lineState.append(";"); } } saveState.add(lineState.toString()); } return saveState; //TODO : complete method with proper return } /** * * @param lines of file representing saved world state */ public void loadSaveState(ArrayList 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) { return; } String firstLine = lines.get(0); String[] firstLineElements = firstLine.split(";"); if(firstLineElements.length<=0) { return; } /* * now we fill in the world * with the content of the file */ for(int y =0; y lines) { if(lines.size()<=0) { System.out.println("empty rule file"); return; } //TODO : remove previous rule (=emptying lists) String surviveLine = lines.get(0); String birthLine = lines.get(1); String[] surviveElements = surviveLine.split(";"); for(int x=0; x getAgentsSave() { //TODO : Same idea as the other save method, but for agents return null; } public void loadAgents(ArrayList stringArray) { //TODO : Same idea as other load methods, but for agent list } /** * used by label in interface to show the active click action * @return String representation of click action */ public String clickActionName() { // TODO : initially return "sheep" or "cell" // depending on clickActionFlag return ""; } }