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.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
// Example of basic animal.
public class Sheep extends Agent {
int hunger;
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){
//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
// 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
// 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
// We initialize the random number generator we will use to move randomly
rand = new Random();
}
@ -35,24 +37,55 @@ public class Sheep extends Agent {
} else {
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();
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() {
int direction = rand.nextInt(4);
int ux = x;
int uy = y;
if(direction == 0) {
x+=1;
ux+=1;
}
if(direction == 1) {
y+=1;
uy+=1;
}
if(direction == 2) {
x-=1;
ux-=1;
}
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;
import java.util.ArrayList;
import java.util.Iterator;
import windowInterface.MyInterface;
@ -10,14 +11,15 @@ public class Simulator extends Thread {
private final int COL_NUM = 100;
private final int LINE_NUM = 100;
private final int LIFE_TYPE_NUM = 4;
//Conway Radius : 1
// Conway 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 ArrayList<Integer> fieldSurviveValues;
private ArrayList<Integer> fieldBirthValues;
private ArrayList<Agent> agents;
ArrayList<ArrayList<Integer>> rule = new ArrayList<>();
private boolean stopFlag;
private boolean pauseFlag;
@ -26,8 +28,6 @@ public class Simulator extends Thread {
private int loopDelay = 150;
Grid maingrid = new Grid(COL_NUM, LINE_NUM);
//TODO : add missing attribute(s)
public Simulator(MyInterface mjfParam) {
mjf = mjfParam;
stopFlag=false;
@ -89,20 +89,15 @@ public class Simulator extends Thread {
// only modify if sure of what you do
// to modify agent behavior, see liveTurn method
// in agent classes
for(Agent agent : agents) {
ArrayList<Agent> neighbors =
this.getNeighboringAnimals(
agent.getX(),
agent.getY(),
ANIMAL_AREA_RADIUS);
if(!agent.liveTurn(
neighbors,
this)) {
agents.remove(agent);
}
for (int i = 0; i < agents.size(); i++) {
Agent agent = agents.get(i);
ArrayList<Agent> neighbors = this.getNeighboringAnimals(agent.getX(), agent.getY(), ANIMAL_AREA_RADIUS);
if (agent.liveTurn(neighbors, this)) {
agents.remove(i);
i--; // Adjust the index to account for the removed element
}
}
//then evolution of the field
// TODO : apply game rule to all cells of the field
// Then evolution of the field
/* you should distribute this action in methods/classes
* don't write everything here !
@ -122,7 +117,7 @@ public class Simulator extends Thread {
for (int y = 0; y < getHeight(); y++) {
int actualState = getCell(x,y);
int futureState =0;
// high life
// High life
if(actualState==0) {
for (int i = 1; i<=5; 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() {
stopFlag=true;
}
/*
* method called when clicking pause button
* Method called when clicking pause button
*/
public void togglePause() {
if (pauseFlag == true) {
@ -191,17 +186,55 @@ public class Simulator extends Thread {
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) {
//TODO : complete method
if(clickActionFlag) {
if (getCell(x, y)==0) {
setCell(x, y,1);
}else {
setCell(x, y,0);
}
if (clickActionFlag) {
setAgent(x, y);
} else {
setCell(x, y,0);
}
}
@ -212,9 +245,9 @@ public class Simulator extends Thread {
* @return value of cell
*/
public int getCell(int x, int y) {
//TODO : complete method with proper retur
return maingrid.getValue(x, y);
}
/**
*
* @return list of Animals in simulated world
@ -222,6 +255,15 @@ public class Simulator extends Thread {
public ArrayList<Agent> getAnimals(){
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
* @param x center
@ -247,7 +289,6 @@ public class Simulator extends Thread {
* @param val to set in cell
*/
public void setCell(int x, int y, int val) {
//TODO : complete method
maingrid.setValue(x, y, val);
}
@ -257,7 +298,6 @@ public class Simulator extends Thread {
* the simulated world in its present state
*/
public ArrayList<String> getSaveState() {
//TODO : complete method with proper return
ArrayList<String> saveState = new ArrayList<>();
for (int y = 0; y < LINE_NUM; y++) {
StringBuilder rowBuilder = new StringBuilder();
@ -291,8 +331,7 @@ public class Simulator extends Thread {
return;
}
/*
* now we fill in the world
* with the content of the file
* Now we fill in the world with the content of the file
*/
for(int y =0; y<lines.size();y++) {
String line = lines.get(y);
@ -312,7 +351,6 @@ public class Simulator extends Thread {
* to be alive in new state
*/
public void generateRandom(float chanceOfLife) {
//TODO : complete method
/*
* Advice :
* as you should probably have a separate class
@ -324,22 +362,18 @@ public class Simulator extends Thread {
}
public boolean isLoopingBorder() {
//TODO : complete method with proper return
return loopingBorder;
}
public void toggleLoopingBorder() {
//TODO : complete method
loopingBorder = !loopingBorder;
}
public void setLoopDelay(int delay) {
//TODO : complete method
loopDelay = delay;
}
public void toggleClickAction() {
//TODO : complete method
if(clickActionFlag) {
clickActionFlag=false;
}else {
@ -356,8 +390,6 @@ public class Simulator extends Thread {
* @see loadRule for inverse process
*/
public ArrayList<String> getRule() {
//TODO : complete method with proper return
StringBuilder birthValues = new StringBuilder();
StringBuilder surviveValues = new StringBuilder();
@ -387,7 +419,7 @@ public class Simulator extends Thread {
System.out.println("empty rule file");
return;
}
//TODO : remove previous rule (=emptying lists)
fieldSurviveValues.clear();
fieldBirthValues.clear();
@ -397,28 +429,65 @@ public class Simulator extends Thread {
for(int x=0; x<surviveElements.length;x++) {
String elem = surviveElements[x];
int value = Integer.parseInt(elem);
//TODO : add value to possible survive values
fieldSurviveValues.add(value);
}
String[] birthElements = birthLine.split(";");
for(int x=0; x<birthElements.length;x++) {
String elem = birthElements[x];
int value = Integer.parseInt(elem);
//TODO : add value to possible birth values
fieldBirthValues.add(value);
}
}
public ArrayList<String> getAgentsSave() {
//TODO : Same idea as the other save method, but for agents
ArrayList<String> lines = new ArrayList<>();
StringBuilder sheepCoordinates = new StringBuilder();
StringBuilder wolfCoordinates = new StringBuilder();
return null;
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) {
//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
*/
public String clickActionName() {
// TODO : initially return "sheep" or "cell"
// depending on clickActionFlag
if (clickActionFlag) return "cell"; else return "sheep";
// Initially return "on" or "off" depending on clickActionFlag
if (clickActionFlag) return "on"; else return "off";
}
}

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