Final Version of the Game of Life Project

This commit is contained in:
Maxime LOBIETTI 2024-05-31 23:41:15 +02:00
parent df9cec1421
commit 606ed35b2a
5 changed files with 262 additions and 73 deletions

View File

@ -1,6 +0,0 @@
public class GameOfLife {
int cells[];
}

View File

@ -4,23 +4,25 @@ import java.awt.Color;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Random; import java.util.Random;
// example of basic animal. // 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 { public class Sheep extends Agent {
int hunger; int hunger;
Random rand; Random rand;
int height;
int width;
private final int REPRODUCTION_RADIUS = 1; // Radius within which sheep can reproduce
private final double REPRODUCTION_PROBABILITY = 0.1; // Probability of reproduction per turn
Sheep(int x,int y){ Sheep(int x,int y){
//first we call the constructor of the superClass(Animal) // First we call the constructor of the superClass(Animal) with the values we want.
//with the values we want. // Here, we decide that a Sheep is initially white using this constructor
// here we decide that a Sheep is initially white using this constructor
super(x,y,Color.white); super(x,y,Color.white);
// we give our sheep a hunger value of zero at birth // We give our sheep a hunger value of zero at birth
hunger = 0; hunger = 0;
//we initialize the random number generator we will use to move randomly // We initialize the random number generator we will use to move randomly
rand = new Random(); rand = new Random();
} }
@ -35,25 +37,56 @@ public class Sheep extends Agent {
} else { } else {
hunger++; hunger++;
} }
height = world.getHeight();
width = world.getHeight();
// Check for reproduction
for (Agent neighbor : neighbors) {
if (neighbor instanceof Sheep && this.isInArea(neighbor.getX(), neighbor.getY(), REPRODUCTION_RADIUS)) {
if (rand.nextDouble() < REPRODUCTION_PROBABILITY) {
reproduce(world);
break;
}
}
}
this.moveRandom(); this.moveRandom();
return hunger>10; return hunger>10;
} }
private void reproduce(Simulator world) {
// Find a random adjacent cell
int newX = x + rand.nextInt(3) - 1;
int newY = y + rand.nextInt(3) - 1;
// Ensure the new position is within bounds and empty
if (newX >= 0 && newX < world.getWidth() && newY >= 0 && newY < world.getHeight() && !world.getOccupied(newX, newY)) {
world.setAgent(newX, newY, new Sheep(newX, newY));
}
}
private void moveRandom() { private void moveRandom() {
int direction = rand.nextInt(4); int direction = rand.nextInt(4);
int ux = x;
int uy = y;
if(direction == 0) { if(direction == 0) {
x+=1; ux+=1;
} }
if(direction == 1) { if(direction == 1) {
y+=1; uy+=1;
} }
if(direction == 2) { if(direction == 2) {
x-=1; ux-=1;
} }
if(direction == 3) { if(direction == 3) {
y-=1; uy-=1;
} }
// Ensure the sheep does not move out of bounds
if (ux >= 0 && ux < width && uy >= 0 && uy < height) {
x = ux;
y = uy;
}
} }
} }

View File

@ -1,5 +1,6 @@
package backend; package backend;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import windowInterface.MyInterface; import windowInterface.MyInterface;
@ -10,14 +11,15 @@ public class Simulator extends Thread {
private final int COL_NUM = 100; private final int COL_NUM = 100;
private final int LINE_NUM = 100; private final int LINE_NUM = 100;
private final int LIFE_TYPE_NUM = 4; private final int LIFE_TYPE_NUM = 4;
//Conway Radius : 1 // Conway Radius : 1
private final int LIFE_AREA_RADIUS = 1; private final int LIFE_AREA_RADIUS = 1;
//Animal Neighborhood Radius : 5 // Animal Neighborhood Radius : 5
private final int ANIMAL_AREA_RADIUS = 2; private final int ANIMAL_AREA_RADIUS = 2;
private ArrayList<Integer> fieldSurviveValues; private ArrayList<Integer> fieldSurviveValues;
private ArrayList<Integer> fieldBirthValues; private ArrayList<Integer> fieldBirthValues;
private ArrayList<Agent> agents; private ArrayList<Agent> agents;
ArrayList<ArrayList<Integer>> rule = new ArrayList<>();
private boolean stopFlag; private boolean stopFlag;
private boolean pauseFlag; private boolean pauseFlag;
@ -26,8 +28,6 @@ public class Simulator extends Thread {
private int loopDelay = 150; private int loopDelay = 150;
Grid maingrid = new Grid(COL_NUM, LINE_NUM); Grid maingrid = new Grid(COL_NUM, LINE_NUM);
//TODO : add missing attribute(s)
public Simulator(MyInterface mjfParam) { public Simulator(MyInterface mjfParam) {
mjf = mjfParam; mjf = mjfParam;
stopFlag=false; stopFlag=false;
@ -89,20 +89,15 @@ public class Simulator extends Thread {
// only modify if sure of what you do // only modify if sure of what you do
// to modify agent behavior, see liveTurn method // to modify agent behavior, see liveTurn method
// in agent classes // in agent classes
for(Agent agent : agents) { for (int i = 0; i < agents.size(); i++) {
ArrayList<Agent> neighbors = Agent agent = agents.get(i);
this.getNeighboringAnimals( ArrayList<Agent> neighbors = this.getNeighboringAnimals(agent.getX(), agent.getY(), ANIMAL_AREA_RADIUS);
agent.getX(), if (agent.liveTurn(neighbors, this)) {
agent.getY(), agents.remove(i);
ANIMAL_AREA_RADIUS); i--; // Adjust the index to account for the removed element
if(!agent.liveTurn( }
neighbors,
this)) {
agents.remove(agent);
}
} }
//then evolution of the field // Then evolution of the field
// TODO : apply game rule to all cells of the field
/* you should distribute this action in methods/classes /* you should distribute this action in methods/classes
* don't write everything here ! * don't write everything here !
@ -122,7 +117,7 @@ public class Simulator extends Thread {
for (int y = 0; y < getHeight(); y++) { for (int y = 0; y < getHeight(); y++) {
int actualState = getCell(x,y); int actualState = getCell(x,y);
int futureState =0; int futureState =0;
// high life // High life
if(actualState==0) { if(actualState==0) {
for (int i = 1; i<=5; i++) { for (int i = 1; i<=5; i++) {
if(fieldBirthValues.contains(countNeighbors(x,y,i))) { if(fieldBirthValues.contains(countNeighbors(x,y,i))) {
@ -175,14 +170,14 @@ public class Simulator extends Thread {
} }
/* /*
* leave this as is * Leave this as is
*/ */
public void stopSimu() { public void stopSimu() {
stopFlag=true; stopFlag=true;
} }
/* /*
* method called when clicking pause button * Method called when clicking pause button
*/ */
public void togglePause() { public void togglePause() {
if (pauseFlag == true) { if (pauseFlag == true) {
@ -190,20 +185,58 @@ public class Simulator extends Thread {
} }
else pauseFlag = true; else pauseFlag = true;
} }
public void setAgent(int x, int y) {
int cellValue = getCell(x, y); // Assuming you have a method getCell(x, y) to retrieve the cell value
String agentType = null;
int indexOfAgent = 0;
for (int i = 0; i < agents.size(); i++) {
Agent agent = agents.get(i);
if (agent.getX() == x && agent.getY() == y) {
if (agent instanceof Sheep) {
agentType = "Sheep";
} else {
agentType = "Wolf";
}
indexOfAgent = i;
}
}
// If the cell is empty (0), set it to 1 (food)
if (cellValue == 0 && agentType == null) {
setCell(x, y, 1); // Set the cell to indicate food
} else if (cellValue == 1) { // If the cell has food (1), replace it with a sheep
agents.add(new Sheep(x, y)); // Add a new Sheep object to the agents list
setCell(x, y, 0);
} else if (agentType == "Sheep") { // If the cell is occupied by a sheep, turn it into a wolf
agents.remove(indexOfAgent);
agents.add(new Wolf(x, y));
} else if (agentType == "Wolf") { // If the cell is occupied by a wolf, loop back to cell = 0
agents.remove(indexOfAgent);
setCell(x, y, 0);
}
}
public void setAgent(int x, int y, Agent agent) {
agents.add(agent);
setCell(x, y, 0); // Clear the cell if it had food
}
public void removeAgent(Agent agent) {
agents.remove(agent);
}
/** /**
* 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) {
//TODO : complete method if (clickActionFlag) {
if(clickActionFlag) { setAgent(x, y);
if (getCell(x, y)==0) { } else {
setCell(x, y,1); setCell(x, y,0);
}else {
setCell(x, y,0);
}
} }
} }
/** /**
* get cell value in simulated world * get cell value in simulated world
@ -211,10 +244,10 @@ public class Simulator extends Thread {
* @param y coordinate of cell * @param y coordinate of cell
* @return value of cell * @return value of cell
*/ */
public int getCell(int x, int y) { public int getCell(int x, int y) {
//TODO : complete method with proper retur
return maingrid.getValue(x, y); return maingrid.getValue(x, y);
} }
/** /**
* *
* @return list of Animals in simulated world * @return list of Animals in simulated world
@ -222,6 +255,15 @@ public class Simulator extends Thread {
public ArrayList<Agent> getAnimals(){ public ArrayList<Agent> getAnimals(){
return agents; return agents;
} }
public boolean getOccupied(int x, int y) {
for (Agent agent : agents) {
if (agent.getX() == x && agent.getY() == y) {
return true;
}
}
return false;
}
/** /**
* selects Animals in a circular area of simulated world * selects Animals in a circular area of simulated world
* @param x center * @param x center
@ -247,7 +289,6 @@ public class Simulator extends Thread {
* @param val to set in 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) {
//TODO : complete method
maingrid.setValue(x, y, val); maingrid.setValue(x, y, val);
} }
@ -257,7 +298,6 @@ public class Simulator extends Thread {
* the simulated world in its present state * the simulated world in its present state
*/ */
public ArrayList<String> getSaveState() { public ArrayList<String> getSaveState() {
//TODO : complete method with proper return
ArrayList<String> saveState = new ArrayList<>(); ArrayList<String> saveState = new ArrayList<>();
for (int y = 0; y < LINE_NUM; y++) { for (int y = 0; y < LINE_NUM; y++) {
StringBuilder rowBuilder = new StringBuilder(); StringBuilder rowBuilder = new StringBuilder();
@ -291,8 +331,7 @@ public class Simulator extends Thread {
return; return;
} }
/* /*
* now we fill in the world * Now we fill in the world with the content of the file
* 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);
@ -312,7 +351,6 @@ public class Simulator extends Thread {
* to be alive in new state * to be alive in new state
*/ */
public void generateRandom(float chanceOfLife) { public void generateRandom(float chanceOfLife) {
//TODO : complete method
/* /*
* Advice : * Advice :
* as you should probably have a separate class * as you should probably have a separate class
@ -324,22 +362,18 @@ public class Simulator extends Thread {
} }
public boolean isLoopingBorder() { public boolean isLoopingBorder() {
//TODO : complete method with proper return
return loopingBorder; return loopingBorder;
} }
public void toggleLoopingBorder() { public void toggleLoopingBorder() {
//TODO : complete method
loopingBorder = !loopingBorder; loopingBorder = !loopingBorder;
} }
public void setLoopDelay(int delay) { public void setLoopDelay(int delay) {
//TODO : complete method
loopDelay = delay; loopDelay = delay;
} }
public void toggleClickAction() { public void toggleClickAction() {
//TODO : complete method
if(clickActionFlag) { if(clickActionFlag) {
clickActionFlag=false; clickActionFlag=false;
}else { }else {
@ -356,8 +390,6 @@ public class Simulator extends Thread {
* @see loadRule for inverse process * @see loadRule for inverse process
*/ */
public ArrayList<String> getRule() { public ArrayList<String> getRule() {
//TODO : complete method with proper return
StringBuilder birthValues = new StringBuilder(); StringBuilder birthValues = new StringBuilder();
StringBuilder surviveValues = new StringBuilder(); StringBuilder surviveValues = new StringBuilder();
@ -387,7 +419,7 @@ public class Simulator extends Thread {
System.out.println("empty rule file"); System.out.println("empty rule file");
return; return;
} }
//TODO : remove previous rule (=emptying lists)
fieldSurviveValues.clear(); fieldSurviveValues.clear();
fieldBirthValues.clear(); fieldBirthValues.clear();
@ -397,28 +429,65 @@ public class Simulator extends Thread {
for(int x=0; x<surviveElements.length;x++) { for(int x=0; x<surviveElements.length;x++) {
String elem = surviveElements[x]; String elem = surviveElements[x];
int value = Integer.parseInt(elem); int value = Integer.parseInt(elem);
//TODO : add value to possible survive values
fieldSurviveValues.add(value); fieldSurviveValues.add(value);
} }
String[] birthElements = birthLine.split(";"); String[] birthElements = birthLine.split(";");
for(int x=0; x<birthElements.length;x++) { for(int x=0; x<birthElements.length;x++) {
String elem = birthElements[x]; String elem = birthElements[x];
int value = Integer.parseInt(elem); int value = Integer.parseInt(elem);
//TODO : add value to possible birth values
fieldBirthValues.add(value); fieldBirthValues.add(value);
} }
} }
public ArrayList<String> getAgentsSave() { public ArrayList<String> getAgentsSave() {
//TODO : Same idea as the other save method, but for agents ArrayList<String> lines = new ArrayList<>();
return null; StringBuilder sheepCoordinates = new StringBuilder();
StringBuilder wolfCoordinates = new StringBuilder();
for (Agent agent : agents) {
String coordinates = agent.getX() + "," + agent.getY();
if (agent instanceof Sheep) {
if (sheepCoordinates.length() > 0) {
sheepCoordinates.append(";");
}
sheepCoordinates.append(coordinates);
} else if (agent instanceof Wolf) {
if (wolfCoordinates.length() > 0) {
wolfCoordinates.append(";");
}
wolfCoordinates.append(coordinates);
}
}
lines.add(sheepCoordinates.toString());
lines.add(wolfCoordinates.toString());
return lines;
} }
public void loadAgents(ArrayList<String> stringArray) { public void loadAgents(ArrayList<String> stringArray) {
//TODO : Same idea as other load methods, but for agent list agents.clear();
// Load Sheep
String sheepLine = stringArray.get(0);
String[] sheepCoords = sheepLine.split(";");
for (String coord : sheepCoords) {
String[] xy = coord.split(",");
int x = Integer.parseInt(xy[0]);
int y = Integer.parseInt(xy[1]);
agents.add(new Sheep(x, y));
}
// Load Wolf
String wolfLine = stringArray.get(1);
String[] wolfCoords = wolfLine.split(";");
for (String coord : wolfCoords) {
String[] xy = coord.split(",");
int x = Integer.parseInt(xy[0]);
int y = Integer.parseInt(xy[1]);
agents.add(new Wolf(x, y));
}
} }
/** /**
@ -426,9 +495,8 @@ public class Simulator extends Thread {
* @return String representation of click action * @return String representation of click action
*/ */
public String clickActionName() { public String clickActionName() {
// TODO : initially return "sheep" or "cell" // Initially return "on" or "off" depending on clickActionFlag
// depending on clickActionFlag if (clickActionFlag) return "on"; else return "off";
if (clickActionFlag) return "cell"; else return "sheep";
} }
} }

94
src/backend/Wolf.java Normal file
View File

@ -0,0 +1,94 @@
package backend;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Random;
public class Wolf extends Agent {
int hunger;
Random rand;
private final int REPRODUCTION_RADIUS = 1; // Radius within which sheep can reproduce
private final double REPRODUCTION_PROBABILITY = 0.2; // Probability of reproduction per turn
Wolf(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.red);
// 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();
}
/**
* action of the animal
* it can interact with the cells or with other animals
* as you wish
*/
public boolean liveTurn(ArrayList<Agent> neighbors, Simulator world) {
boolean ateSheep = false;
// Check for neighboring sheep to eat
for (Agent neighbor : neighbors) {
if (neighbor instanceof Sheep) {
// Eat the sheep (remove from the list)
world.removeAgent(neighbor);
hunger = 0; // Reset hunger
ateSheep = true;
break;
}
}
// If no sheep were eaten, increase hunger
if (!ateSheep) {
hunger++;
}
// Check for reproduction
for (Agent neighbor : neighbors) {
if (neighbor instanceof Wolf && this.isInArea(neighbor.getX(), neighbor.getY(), REPRODUCTION_RADIUS)) {
if (rand.nextDouble() < REPRODUCTION_PROBABILITY) {
reproduce(world);
break;
}
}
}
// Move randomly
this.moveRandom();
return hunger>10;
}
private void reproduce(Simulator world) {
// Find a random adjacent cell
int newX = x + rand.nextInt(3) - 1;
int newY = y + rand.nextInt(3) - 1;
// Ensure the new position is within bounds and empty
if (newX >= 0 && newX < world.getWidth() && newY >= 0 && newY < world.getHeight() && world.getCell(newX, newY) == 0) {
world.setAgent(newX, newY, new Wolf(newX, newY));
}
}
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;
}
}
}

View File