diff --git a/src/backend/Agent.java b/src/backend/Agent.java index 17bdf17..8f44756 100644 --- a/src/backend/Agent.java +++ b/src/backend/Agent.java @@ -30,15 +30,37 @@ public abstract class Agent { return dist neighbors, Simulator world); - - public static Agent fromString(String line) { - return null; - } - - } + diff --git a/src/backend/Sheep.java b/src/backend/Sheep.java index ece8a18..42fab0c 100644 --- a/src/backend/Sheep.java +++ b/src/backend/Sheep.java @@ -4,15 +4,15 @@ import java.awt.Color; import java.util.ArrayList; import java.util.Random; -// example of basic animal. -// do not hesitate to make it more complex -// and DO add at least another species that interact with it -// for example wolves that eat Sheep public class Sheep extends Agent { int hunger; Random rand; + public Sheep(int x, int y, Color color) { + super(x, y, color); + } + Sheep(int x,int y){ //first we call the constructor of the superClass(Animal) //with the values we want. @@ -32,28 +32,38 @@ public class Sheep extends Agent { public boolean liveTurn(ArrayList neighbors, Simulator world) { if(world.getCell(x, y)==1) { world.setCell(x, y, 0); + hunger = 0; // Reset hunger if the sheep finds food } else { hunger++; } this.moveRandom(); - return hunger>10; + return hunger <= 10; // Sheep survives if hunger is 10 or less } private void moveRandom() { int direction = rand.nextInt(4); - if(direction == 0) { - x+=1; - } - if(direction == 1) { - y+=1; - } - if(direction == 2) { - x-=1; - } - if(direction == 3) { - y-=1; + switch(direction) { + case 0: x += 1; break; + case 1: y += 1; break; + case 2: x -= 1; break; + case 3: y -= 1; break; } } + // Parsing method to create Sheep from a string + public static Sheep parse(String line) { + String[] parts = line.split(";"); + int x = Integer.parseInt(parts[0]); + int y = Integer.parseInt(parts[1]); + // We don't parse color here since Sheep is always white + Sheep sheep = new Sheep(x, y); + sheep.hunger = Integer.parseInt(parts[2]); // Parsing hunger value + return sheep; + } + + @Override + public String toString() { + return x + ";" + y + ";" + hunger; + } } diff --git a/src/backend/Simulator.java b/src/backend/Simulator.java index 072e903..b742c72 100644 --- a/src/backend/Simulator.java +++ b/src/backend/Simulator.java @@ -1,5 +1,6 @@ package backend; import java.util.ArrayList; +import java.util.Random; import windowInterface.MyInterface; @@ -7,13 +8,11 @@ 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 boolean[][] grid; // 2D array representing the current state of the grid + private boolean[][] newGrid; // 2D array representing the next state of the grid + private int LINE_NUM; + private int COL_NUM; + private ArrayList fieldSurviveValues; private ArrayList fieldBirthValues; @@ -25,7 +24,7 @@ public class Simulator extends Thread { private boolean clickActionFlag; private int loopDelay = 150; - public int[][] grid; + private boolean running = false; // New flag to track if the thread is running public Simulator(MyInterface mjfParam) { mjf = mjfParam; @@ -37,13 +36,16 @@ public class Simulator extends Thread { agents = new ArrayList(); fieldBirthValues = new ArrayList(); fieldSurviveValues = new ArrayList(); + + LINE_NUM = mjfParam.getX(); + COL_NUM = mjfParam.getY(); + grid = new boolean[LINE_NUM][COL_NUM]; + newGrid = new boolean[LINE_NUM][COL_NUM]; - grid = new int[LINE_NUM][COL_NUM]; - - // Default rule : Survive always, birth never - for (int i = 0; i < 9; i++) { - fieldSurviveValues.add(i); - } + // Default rule: Survive on 2 or 3 neighbors, birth on 3 neighbors + fieldSurviveValues.add(2); + fieldSurviveValues.add(3); + fieldBirthValues.add(3); } public int getWidth() { @@ -54,81 +56,84 @@ public class Simulator extends Thread { 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(); - } - } - } - - } + // Runs the simulation + public void run() { + if (running) return; // Prevents the thread from being started more than once + running = true; + 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(); + } + } + } + running = false; // Reset the running flag when the thread finishes + } /** * method called at each step of the simulation * makes all the actions to go from one step to the other */ - public void makeStep() { - int[][] newGrid = new int[LINE_NUM][COL_NUM]; + try { + for (Agent agent : agents) { + ArrayList neighbors = getNeighboringAnimals(agent.getX(), agent.getY(), 2); + if (!agent.liveTurn(neighbors, this)) { + agents.remove(agent); + } + } for (int y = 0; y < LINE_NUM; y++) { for (int x = 0; x < COL_NUM; x++) { - int aliveNeighbors = countAliveNeighbors(x, y); - - if (grid[y][x] == 1) { - if (aliveNeighbors < 2 || aliveNeighbors > 3) { - newGrid[y][x] = 0; - } else { - newGrid[y][x] = 1; - } + int liveNeighbors = countLiveNeighbors(y, x); + if (grid[y][x]) { + newGrid[y][x] = fieldSurviveValues.contains(liveNeighbors); } else { - if (aliveNeighbors == 3) { - newGrid[y][x] = 1; - } else { - newGrid[y][x] = 0; - } + newGrid[y][x] = fieldBirthValues.contains(liveNeighbors); } } } - + boolean[][] temp = grid; grid = newGrid; + newGrid = temp; + + } catch (Exception e) { + boolean[][] temp = grid; + grid = newGrid; + newGrid = temp; + } } - - private int countAliveNeighbors(int x, int y) { - int aliveCount = 0; - int[] dx = {-1, -1, -1, 0, 0, 1, 1, 1}; - int[] dy = {-1, 0, 1, -1, 1, -1, 0, 1}; - - for (int i = 0; i < 8; i++) { - int nx = x + dx[i]; - int ny = y + dy[i]; - - if (loopingBorder) { - nx = (nx + COL_NUM) % COL_NUM; - ny = (ny + LINE_NUM) % LINE_NUM; - } - - if (nx >= 0 && nx < COL_NUM && ny >= 0 && ny < LINE_NUM) { - aliveCount += grid[ny][nx]; + // Counts live neighbors + private int countLiveNeighbors(int y, int x) { + int count = 0; + int[] directions = {-1, 0, 1}; + for (int i : directions) { + for (int j : directions) { + if (i == 0 && j == 0) continue; + int neighbory = y + i; + int neighborCol = x + j; + if (loopingBorder) { + neighbory = (neighbory + LINE_NUM) % LINE_NUM; + neighborCol = (neighborCol + COL_NUM) % COL_NUM; + } + if (isInBounds(neighbory, neighborCol) && grid[neighbory][neighborCol]) { + count++; + } } } - - return aliveCount; + return count; } /* @@ -152,8 +157,7 @@ public class Simulator extends Thread { if (clickActionFlag) { agents.add(new Sheep(x, y)); } else { - int currentState = getCell(x, y); - setCell(x, y, currentState == 0 ? 1 : 0); + grid[x][y] = !grid[x][y]; } } @@ -164,10 +168,13 @@ public class Simulator extends Thread { * @return value of cell */ public int getCell(int x, int y) { - if (x >= 0 && x < COL_NUM && y >= 0 && y < LINE_NUM) { - return grid[y][x]; - } - return 0; + int i =1; + try { + return grid[x][y] ? 1 : 0; + }catch (Exception e) { + i = 0; + } + return i; } /** @@ -202,9 +209,7 @@ public class Simulator extends Thread { * @param val to set in cell */ public void setCell(int x, int y, int val) { - if (x >= 0 && x < COL_NUM && y >= 0 && y < LINE_NUM) { - grid[y][x] = val; - } + grid[x][y] = (val == 1); } /** @@ -215,14 +220,11 @@ public class Simulator extends Thread { public ArrayList getSaveState() { ArrayList saveState = new ArrayList(); for (int y = 0; y < LINE_NUM; y++) { - StringBuilder sb = new StringBuilder(); + StringBuilder line = new StringBuilder(); for (int x = 0; x < COL_NUM; x++) { - sb.append(grid[y][x]); - if (x < COL_NUM - 1) { - sb.append(";"); - } + line.append(grid[x][y] ? "1" : "0").append(";"); } - saveState.add(sb.toString()); + saveState.add(line.toString()); } return saveState; } @@ -232,16 +234,13 @@ public class Simulator extends Thread { * @param lines of file representing saved world state */ public void loadSaveState(ArrayList lines) { - if (lines.size() != LINE_NUM) { - return; - } - for (int y = 0; y < LINE_NUM; y++) { + if (lines.size() <= 0) return; + + for (int y = 0; y < lines.size(); y++) { String[] lineElements = lines.get(y).split(";"); - if (lineElements.length != COL_NUM) { - return; - } - for (int x = 0; x < COL_NUM; x++) { - grid[y][x] = Integer.parseInt(lineElements[x]); + for (int x = 0; x < lineElements.length; x++) { + int value = Integer.parseInt(lineElements[x]); + setCell(x, y, value); } } } @@ -253,9 +252,10 @@ public class Simulator extends Thread { * to be alive in new state */ public void generateRandom(float chanceOfLife) { + Random rand = new Random(); for (int y = 0; y < LINE_NUM; y++) { for (int x = 0; x < COL_NUM; x++) { - grid[y][x] = Math.random() < chanceOfLife ? 1 : 0; + grid[x][y] = rand.nextFloat() < chanceOfLife; } } } @@ -286,60 +286,44 @@ public class Simulator extends Thread { */ public ArrayList getRule() { ArrayList rules = new ArrayList(); - StringBuilder surviveBuilder = new StringBuilder(); - StringBuilder birthBuilder = new StringBuilder(); - - for (int value : fieldSurviveValues) { - surviveBuilder.append(value).append(";"); - } - for (int value : fieldBirthValues) { - birthBuilder.append(value).append(";"); - } - - rules.add(surviveBuilder.toString()); - rules.add(birthBuilder.toString()); + rules.add("Survive: " + fieldSurviveValues.toString()); + rules.add("Birth: " + fieldBirthValues.toString()); return rules; } + // Loads the rules of the simulation public void loadRule(ArrayList lines) { - if (lines.size() < 2) { - System.out.println("empty rule file"); - return; - } + if (lines.size() <= 0) return; fieldSurviveValues.clear(); fieldBirthValues.clear(); - - String[] surviveElements = lines.get(0).split(";"); - for (String elem : surviveElements) { - if (!elem.isEmpty()) { - fieldSurviveValues.add(Integer.parseInt(elem)); - } - } - - String[] birthElements = lines.get(1).split(";"); - for (String elem : birthElements) { - if (!elem.isEmpty()) { - fieldBirthValues.add(Integer.parseInt(elem)); + for (String line : lines) { + if (line.startsWith("Survive: ")) { + String[] surviveRules = line.replace("Survive: ", "").replaceAll("[\\[\\]]", "").split(", "); + for (String rule : surviveRules) { + fieldSurviveValues.add(Integer.parseInt(rule)); + } + } else if (line.startsWith("Birth: ")) { + String[] birthRules = line.replace("Birth: ", "").replaceAll("[\\[\\]]", "").split(", "); + for (String rule : birthRules) { + fieldBirthValues.add(Integer.parseInt(rule)); + } } } } public ArrayList getAgentsSave() { - ArrayList saveState = new ArrayList<>(); + ArrayList agentsSave = new ArrayList<>(); for (Agent agent : agents) { - saveState.add(agent.toString()); + agentsSave.add(agent.saveState()); } - return saveState; + return agentsSave; } - public void loadAgents(ArrayList stringArray) { + public void loadAgents(ArrayList lines) { agents.clear(); - for (String line : stringArray) { - Agent agent = Agent.fromString(line); - if (agent != null) { - agents.add(agent); - } + for (String line : lines) { + agents.add(Agent.loadState(line)); } } @@ -350,4 +334,9 @@ public class Simulator extends Thread { public String clickActionName() { return clickActionFlag ? "sheep" : "cell"; } + + // Checks if the coordinates are in bounds + private boolean isInBounds(int y, int x) { + return y >= 0 && y < LINE_NUM && x >= 0 && x < COL_NUM; + } } \ No newline at end of file diff --git a/src/windowInterface/MyInterface.java b/src/windowInterface/MyInterface.java index 9990261..107ac31 100644 --- a/src/windowInterface/MyInterface.java +++ b/src/windowInterface/MyInterface.java @@ -44,7 +44,7 @@ public class MyInterface extends JFrame { */ public MyInterface() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - setBounds(10, 10, 700, 600); + setBounds(100, 100, 700, 600); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); contentPane.setLayout(new BorderLayout(0, 0));