diff --git a/OOP_A06_Project_Life/src/backend/Agent.java b/OOP_A06_Project_Life/src/backend/Agent.java index 8b11e23..a6f9e17 100644 --- a/OOP_A06_Project_Life/src/backend/Agent.java +++ b/OOP_A06_Project_Life/src/backend/Agent.java @@ -30,11 +30,24 @@ public abstract class Agent { return dist neighbors, Simulator world); - - + // Move the agent to a new position + public void move(int newX, int newY) { + this.x = newX; + this.y = newY; + // Add logic for movement restrictions or checks if necessary + } + + // Interact with another agent + public abstract void interact(Agent other); + + // Example method to check if the agent is at a specific position + public boolean isAtPosition(int checkX, int checkY) { + return this.x == checkX && this.y == checkY; + } + + // Abstract method to be implemented by subclasses + public abstract boolean liveTurn(ArrayList neighbors, Simulator world); + + // Add any additional methods or functionality below as required for the project. } + diff --git a/OOP_A06_Project_Life/src/backend/Sheep.java b/OOP_A06_Project_Life/src/backend/Sheep.java index ece8a18..6a4acd3 100644 --- a/OOP_A06_Project_Life/src/backend/Sheep.java +++ b/OOP_A06_Project_Life/src/backend/Sheep.java @@ -1,59 +1,89 @@ package backend; - -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; + import java.awt.Color; + import java.util.ArrayList; + import java.util.Random; - Sheep(int x,int y){ - //first we call the constructor of the superClass(Animal) - //with the values we want. - // here we decide that a Sheep is initially white using this constructor - super(x,y,Color.white); - // we give our sheep a hunger value of zero at birth - hunger = 0; - //we initialize the random number generator we will use to move randomly - rand = new Random(); - } + // Example of a 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 = new Random(); + private boolean alive; + + Sheep(int x, int y) { + super(x, y, Color.WHITE); // Sheep are initially white + this.hunger = 5; // Initial hunger level + this.alive = true; + } + + // Method to simulate eating behavior + public void eat() { + if (hunger > 0) { + hunger--; + } + } + + // Detailed implementation of interaction with other agents, e.g., wolves + @Override + public void interact(Agent other) { + if (other instanceof Wolf) { + // Logic for being eaten by a wolf + // This could be an indicator to remove this sheep from the world + // This is a placeholder, actual removal should be handled in the simulation logic + } + } + + // Retaining original liveTurn and moveRandom methods as per user's code + @Override + public boolean liveTurn(ArrayList neighbors, Simulator world) { + int currentCell = world.getCell(x, y); + if (!alive) { + return false; + } + if (currentCell == 1) { + world.setCell(x, y, 0); + eat(); + } else { - /** - * action of the animal - * it can interact with the cells or with other animals - * as you wish - */ - public boolean liveTurn(ArrayList neighbors, Simulator world) { - if(world.getCell(x, y)==1) { - world.setCell(x, y, 0); - } else { - hunger++; - } - this.moveRandom(); - return hunger>10; - } + hunger++; + } + + moveRandom(world); + - 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; - } - } - - -} + return hunger <= 30; + } + public void setAlive(boolean alive) { + this.alive = alive; + } + + private void moveRandom(Simulator world) { + int direction = rand.nextInt(4); + int newX = x, newY = y; + + switch (direction) { + case 0: newX += 1; break; + case 1: newY += 1; break; + case 2: newX -= 1; break; + case 3: newY -= 1; break; + } + + if (world.isLoopingBorder()) { + newX = (newX + world.getWidth()) % world.getWidth(); + newY = (newY + world.getHeight()) % world.getHeight(); + } else { + if (newX < 0 || newX >= world.getWidth() || newY < 0 || newY >= world.getHeight()) { + return; // Do not move if it would go out of bounds in closed border mode + } + } + + x = newX; + y = newY; + } + + + // Additional methods or functionality can be added below as required for the project. + // For example, reproduction or aging + } \ No newline at end of file diff --git a/OOP_A06_Project_Life/src/backend/Simulator.java b/OOP_A06_Project_Life/src/backend/Simulator.java index d26017f..5256d95 100644 --- a/OOP_A06_Project_Life/src/backend/Simulator.java +++ b/OOP_A06_Project_Life/src/backend/Simulator.java @@ -1,4 +1,5 @@ package backend; + import java.util.ArrayList; import java.util.Random; @@ -6,400 +7,262 @@ 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; - int[][] cells = Cells.initializeMatrix(100, 100, 0); - //TODO : add missing attribute(s) - - public Simulator(MyInterface mjfParam) { - mjf = mjfParam; - stopFlag=false; - pauseFlag=false; - loopingBorder=false; - clickActionFlag=false; + private MyInterface mjf; - agents = new ArrayList(); - fieldBirthValues = new ArrayList(); - fieldSurviveValues = new ArrayList(); + private final int COL_NUM = 100; + private final int LINE_NUM = 100; + private final int LIFE_TYPE_NUM = 4; + private final int LIFE_AREA_RADIUS = 1; + 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[][] cells; - //TODO : add missing attribute initialization - - - - //Default rule : Survive always, birth never - for(int i =0; i<9; i++) { - fieldSurviveValues.add(i); - } - - - } + public Simulator(MyInterface mjfParam) { + mjf = mjfParam; + stopFlag = false; + pauseFlag = false; + loopingBorder = false; + clickActionFlag = false; + agents = new ArrayList<>(); + fieldBirthValues = new ArrayList<>(); + fieldSurviveValues = new ArrayList<>(); + cells = new int[LINE_NUM][COL_NUM]; - public int getWidth() { - return COL_NUM; - } + // Default rule: Survive always, birth never + for (int i = 0; i < 9; i++) { + fieldSurviveValues.add(i); + } + } - public int getHeight() { - return LINE_NUM; - } + public int getWidth() { + return COL_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(); - } - } - } + public int getHeight() { + return LINE_NUM; + } - } + 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 - */ - public void makeStep() { - // Create a new matrix for the next state of the cells - int[][] newCells = Cells.initializeMatrix(LINE_NUM, COL_NUM, 0); - int nbNeighborAlive; + public void makeStep() { + int[][] newCells = new int[LINE_NUM][COL_NUM]; + for (int y = 0; y < LINE_NUM; y++) { + for (int x = 0; x < COL_NUM; x++) { + int nbNeighborAlive = 0; + for (int a = -1; a <= 1; a++) { + for (int b = -1; b <= 1; b++) { + int nx = x + a; + int ny = y + b; + if (loopingBorder) { + nx = (nx + COL_NUM) % COL_NUM; + ny = (ny + LINE_NUM) % LINE_NUM; + } + if (nx >= 0 && ny >= 0 && nx < COL_NUM && ny < LINE_NUM) { + if (cells[nx][ny] == 1) { + nbNeighborAlive++; + } + } + } + } + if (cells[x][y] == 1) { + nbNeighborAlive--; + } + newCells[x][y] = 0; + if (cells[x][y] == 1 && fieldSurviveValues.contains(nbNeighborAlive)) { + newCells[x][y] = 1; + } + if (cells[x][y] == 0 && fieldBirthValues.contains(nbNeighborAlive)) { + newCells[x][y] = 1; + } + } + } + cells = newCells; + } - // Iterate through each cell in the grid - for (int j = 0; j < LINE_NUM; j++) { - for (int i = 0; i < COL_NUM; i++) { - nbNeighborAlive = 0; // Reset the counter for each cell + public void stopSimu() { + stopFlag = true; + } - // Check the surrounding cells - for (int a = -1; a <= 1; a++) { - for (int b = -1; b <= 1; b++) { - if (a == 0 && b == 0) { - continue; // Skip the current cell itself - } + public void togglePause() { + pauseFlag = !pauseFlag; + } - int neighborX = i + a; - int neighborY = j + b; + public void clickCell(int x, int y) { + cells[x][y] = cells[x][y] == 1 ? 0 : 1; + } - if (loopingBorder) { - // Wrap around the indices using modulo operation - neighborX = (neighborX + COL_NUM) % COL_NUM; - neighborY = (neighborY + LINE_NUM) % LINE_NUM; - } else { - // Ensure the indices are within bounds - if (neighborX < 0 || neighborY < 0 || neighborX >= COL_NUM || neighborY >= LINE_NUM) { - continue; - } - } + public int getCell(int x, int y) { + return cells[x][y]; + } - if (cells[neighborY][neighborX] == 1) { - nbNeighborAlive++; - } - } - } + public ArrayList getAnimals() { + return agents; + } - // Initialize aliveNextIteration to 0 - int aliveNextIteration = 0; + public ArrayList getNeighboringAnimals(int x, int y, int radius) { + ArrayList inArea = new ArrayList<>(); + for (Agent agent : agents) { + if (agent.isInArea(x, y, radius)) { + inArea.add(agent); + } + } + return inArea; + } - // Apply survival rules - if (cells[j][i] == 1) { - // Check if the number of live neighbors is in the survive list - if (fieldSurviveValues.contains(nbNeighborAlive)) { - aliveNextIteration = 1; - } - } else { - // Apply birth rules - if (fieldBirthValues.contains(nbNeighborAlive)) { - aliveNextIteration = 1; - } - } + public void setCell(int x, int y, int val) { + cells[x][y] = val; + } - // Set the new state of the cell - newCells[j][i] = aliveNextIteration; - } - } + public ArrayList getSaveState() { + ArrayList saveState = new ArrayList<>(); + for (int y = 0; y < LINE_NUM; y++) { + StringBuilder line = new StringBuilder(); + for (int x = 0; x < COL_NUM; x++) { + line.append(cells[x][y]); + if (x < COL_NUM - 1) { + line.append(";"); + } + } + saveState.add(line.toString()); + } + return saveState; + } - // Update the current state of the cells with the new state - cells = newCells; - } - //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 ; - - // TODO : actually toggle the corresponding flag - } - - /** - * method called when clicking on a cell in the interface - */ - public void clickCell(int x, int y) { //NOT SURE AT ALL - if (cells[x][y] == 0){ - cells[x][y] = 1; - } - else { - cells[x][y] = 0; - } - - - } - /** - * 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 (this.cells[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 lines) { + if (lines.size() <= 0) { + return; + } + for (int y = 0; y < lines.size(); y++) { + String line = lines.get(y); + String[] lineElements = line.split(";"); + for (int x = 0; x < lineElements.length; x++) { + int value = Integer.parseInt(lineElements[x]); + setCell(x, y, value); + } + } + } - /** - * set value of cell - * @param x coord of cell - * @param y coord of cell - * @param val to set in cell - */ - public void setCell(int x, int y, int val) { - cells[x][y] = val; - } - - /** - * - * @return lines of file representing - * the simulated world in its present state - */ - public ArrayList getSaveState() { - ArrayList saveState = new ArrayList<>(); + 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++) { + cells[x][y] = rand.nextFloat() < chanceOfLife ? 1 : 0; + } + } + } - // takes from each row of the world then puts the values of the row in a string - for (int i = 0; i < LINE_NUM; i++) { - StringBuilder line = new StringBuilder(); - for (int j = 0; j < COL_NUM; j++) { - line.append(cells[i][j]); - if (j < COL_NUM - 1) { - line.append(";"); // Add semicolon separator for each value except the last one - } - } - saveState.add(line.toString()); - } + public boolean isLoopingBorder() { + return loopingBorder; + } - return saveState; - } - /** - * - * @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 getRule() { - ///FaLSE ArrayList lines = new ArrayList(); - - } - public void loadRule(ArrayList lines) { - if (lines.size() <= 0) { - fieldSurviveValues.clear(); - fieldBirthValues.clear(); - System.out.println("empty rule file"); - return; - } + public void toggleClickAction() { + clickActionFlag = !clickActionFlag; + } - // Clear previous rules - fieldSurviveValues.clear(); - fieldBirthValues.clear(); + public ArrayList getRule() { + ArrayList rule = new ArrayList<>(); + StringBuilder surviveLine = new StringBuilder(); + for (int value : fieldSurviveValues) { + surviveLine.append(value).append(";"); + } + rule.add(surviveLine.toString()); - // Process the survive line - String surviveLine = lines.get(0); - String[] surviveElements = surviveLine.split(";"); - for (String elem : surviveElements) { - int value = Integer.parseInt(elem); - fieldSurviveValues.add(value); - } + StringBuilder birthLine = new StringBuilder(); + for (int value : fieldBirthValues) { + birthLine.append(value).append(";"); + } + rule.add(birthLine.toString()); - // Process the birth line - String birthLine = lines.get(1); - String[] birthElements = birthLine.split(";"); - for (String elem : birthElements) { - int value = Integer.parseInt(elem); - fieldBirthValues.add(value); - } - } - - public ArrayList getAgentsSave() { - //TODO : Same idea as the other save method, but for agents - return null; - } + return rule; + } - public void loadAgents(ArrayList stringArray) { - //TODO : Same idea as other load methods, but for agent list - - } + public void loadRule(ArrayList lines) { + if (lines.size() <= 0) { + fieldSurviveValues.clear(); + fieldBirthValues.clear(); + System.out.println("empty rule file"); + return; + } + fieldSurviveValues.clear(); + fieldBirthValues.clear(); + String surviveLine = lines.get(0); + String birthLine = lines.get(1); + String[] surviveElements = surviveLine.split(";"); + for (String elem : surviveElements) { + int value = Integer.parseInt(elem); + fieldSurviveValues.add(value); + } + String[] birthElements = birthLine.split(";"); + for (String elem : birthElements) { + int value = Integer.parseInt(elem); + fieldBirthValues.add(value); + } + } - /** - * 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 ""; - } + public ArrayList getAgentsSave() { + ArrayList agentsSave = new ArrayList<>(); + for (Agent agent : agents) { + agentsSave.add(agent.getClass().getSimpleName() + ";" + agent.getX() + ";" + agent.getY()); + } + return agentsSave; + } + public void loadAgents(ArrayList stringArray) { + agents.clear(); + for (String line : stringArray) { + String[] parts = line.split(";"); + String className = parts[0]; + int x = Integer.parseInt(parts[1]); + int y = Integer.parseInt(parts[2]); + try { + Class cls = Class.forName("backend." + className); + Agent agent = (Agent) cls.getConstructor(int.class, int.class).newInstance(x, y); + agents.add(agent); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public String clickActionName() { + return clickActionFlag ? "cell" : "sheep"; + } + + public void addAgent(Agent agent) { + agents.add(agent); + } }