This commit is contained in:
Utilisateur 2024-06-02 20:32:54 +02:00
commit c9c98a14d3
12 changed files with 727 additions and 0 deletions

10
OOP_A2_Project/.classpath Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>

1
OOP_A2_Project/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/bin/

17
OOP_A2_Project/.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>OOP_A2_Project</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,12 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -0,0 +1,35 @@
package backend;
import java.awt.Color;
public abstract class Agent {
protected int x;
protected int y;
protected World world;
public Agent(int x, int y, World world) {
this.x = x;
this.y = y;
this.world = world;
}
public abstract void step();
public int getX() {
return x;
}
public int getY() {
return y;
}
public abstract Color getDisplayColor();
protected int[] getRandomAdjacentPosition() {
int newX = x + (int)(Math.random() * 3) - 1; // -1, 0, or 1
int newY = y + (int)(Math.random() * 3) - 1; // -1, 0, or 1
newX = Math.max(0, Math.min(world.getCols() - 1, newX));
newY = Math.max(0, Math.min(world.getRows() - 1, newY));
return new int[]{newX, newY};
}
}

View File

@ -0,0 +1,21 @@
package backend;
public class Cell {
private boolean isAlive;
public Cell() {
this.isAlive = false;
}
public boolean isAlive() {
return isAlive;
}
public void setAlive(boolean isAlive) {
this.isAlive = isAlive;
}
public void toggle() {
this.isAlive = !this.isAlive;
}
}

View File

@ -0,0 +1,22 @@
package backend;
import java.awt.Color;
public class Sheep extends Agent {
public Sheep(int x, int y, World world) {
super(x, y, world);
}
@Override
public void step() {
int[] newPos = getRandomAdjacentPosition();
x = newPos[0];
y = newPos[1];
}
@Override
public Color getDisplayColor() {
return Color.white;
}
}

View File

@ -0,0 +1,88 @@
package backend;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import windowInterface.MyInterface;
public class Simulator extends Thread {
private MyInterface myInterface;
private World world;
private boolean running = false;
private boolean paused = false;
private int loopDelay = 500;
private int clickAction = 0;
public Simulator(MyInterface myInterface, World world) {
this.myInterface = myInterface;
this.world = world;
}
public void setWorld(World world) {
this.world = world;
myInterface.update(world.getStepCount()); // Update interface with new world's step count
myInterface.printMessage("Changed to new world."); // Inform the user about the world change
}
public void run() {
running = true;
while (running) {
if (!paused) {
world.step();
myInterface.update(world.getStepCount());
}
try {
Thread.sleep(loopDelay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stopSimu() {
running = false;
}
public void togglePause() {
paused = !paused;
}
public boolean isRunning() {
return running;
}
public int getWidth() {
return world.getCols();
}
public int getHeight() {
return world.getRows();
}
public int getCell(int x, int y) {
return world.isCellAlive(y, x) ? 1 : 0;
}
public void clickCell(int x, int y) {
world.toggleCell(y, x);
}
public void addAgent(Agent agent) {
world.addAgent(agent);
}
public List<Agent> getAnimals() {
return world.getAgents();
}
public void setLoopDelay(int loopDelay) {
this.loopDelay = loopDelay;
}
public void setClickAction(int action) {
this.clickAction = action;
}
public World getWorld() {
return world;
}
}

View File

@ -0,0 +1,74 @@
package backend;
import java.awt.Color;
import java.util.List;
import javax.swing.JOptionPane;
public class Wolf extends Agent {
public Wolf(int x, int y, World world) {
super(x, y, world);
}
@Override
public void step() {
Sheep closestSheep = findClosestSheep();
if (closestSheep != null) {
moveTowards(closestSheep);
if (x == closestSheep.getX() && y == closestSheep.getY()) {
world.removeAgent(closestSheep);
showMessage("A wolf caught a sheep at (" + x + ", " + y + ")");
}
} else {
int[] newPos = getRandomAdjacentPosition();
x = newPos[0];
y = newPos[1];
}
}
private Sheep findClosestSheep() {
List<Agent> agents = world.getAgents();
Sheep closestSheep = null;
double minDistance = Double.MAX_VALUE;
for (Agent agent : agents) {
if (agent instanceof Sheep) {
double distance = Math.sqrt(Math.pow(agent.getX() - x, 2) + Math.pow(agent.getY() - y, 2));
if (distance < minDistance) {
minDistance = distance;
closestSheep = (Sheep) agent;
}
}
}
return closestSheep;
}
private void moveTowards(Sheep sheep) {
if (sheep.getX() > x) x++;
else if (sheep.getX() < x) x--;
if (sheep.getY() > y) y++;
else if (sheep.getY() < y) y--;
}
@Override
protected int[] getRandomAdjacentPosition() {
int newX = x + (int)(Math.random() * 3) - 1; // -1, 0, or 1
int newY = y + (int)(Math.random() * 3) - 1; // -1, 0, or 1
newX = Math.max(0, Math.min(world.getCols() - 1, newX));
newY = Math.max(0, Math.min(world.getRows() - 1, newY));
return new int[]{newX, newY};
}
@Override
public Color getDisplayColor() {
return Color.GRAY;
}
private void showMessage(String message) {
// Create a new thread to show the message so it doesn't block the simulation
new Thread(() -> {
JOptionPane.showMessageDialog(null, message);
}).start();
}
}

View File

@ -0,0 +1,182 @@
package backend;
import java.awt.Color;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
public class World {
private int rows;
private int cols;
private Cell[][] grid;
private boolean looping;
private int stepCount = 0;
private List<Agent> agents;
private Color backgroundColor;
public World(int rows, int cols, boolean looping, Color backgroundColor) {
this.rows = rows;
this.cols = cols;
this.looping = looping;
this.grid = new Cell[rows][cols];
this.agents = new CopyOnWriteArrayList<>();
this.backgroundColor = backgroundColor;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
grid[i][j] = new Cell();
}
}
}
private Color generateRandomColor() {
Random random = new Random();
int black = random.nextInt(256);
int green = random.nextInt(256);
int blue = random.nextInt(256);
return new Color(black, green, blue);
}
public int getRows() {
return rows;
}
public int getCols() {
return cols;
}
public boolean isLooping() {
return looping;
}
public void setLooping(boolean looping) {
this.looping = looping;
}
public int getStepCount() {
return stepCount;
}
public void step() {
Cell[][] newGrid = new Cell[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
newGrid[i][j] = new Cell();
int liveNeighbors = countLiveNeighbors(i, j);
if (grid[i][j].isAlive()) {
newGrid[i][j].setAlive(liveNeighbors == 2 || liveNeighbors == 3);
} else {
newGrid[i][j].setAlive(liveNeighbors == 3);
}
}
}
grid = newGrid;
stepCount++;
for (Agent agent : agents) {
agent.step();
}
checkCollisions();
}
private int countLiveNeighbors(int row, int col) {
int count = 0;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (i == 0 && j == 0) continue;
int r = row + i;
int c = col + j;
if (looping) {
r = (r + rows) % rows;
c = (c + cols) % cols;
}
if (r >= 0 && r < rows && c >= 0 && c < cols && grid[r][c].isAlive()) {
count++;
}
}
}
return count;
}
public void toggleCell(int row, int col) {
grid[row][col].toggle();
}
public boolean isCellAlive(int row, int col) {
return grid[row][col].isAlive();
}
public void setRandomState(float chanceOfLife) {
Random rand = new Random();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
grid[i][j].setAlive(rand.nextFloat() < chanceOfLife);
}
}
}
public void setState(int row, int col, boolean isAlive) {
grid[row][col].setAlive(isAlive);
}
public void loadStateFromStrings(String[] stateStrings) {
for (int i = 0; i < stateStrings.length; i++) {
String[] cells = stateStrings[i].split(";");
for (int j = 0; j < cells.length; j++) {
grid[i][j].setAlive(cells[j].equals("1"));
}
}
}
public String[] getStateAsStrings() {
String[] stateStrings = new String[rows];
for (int i = 0; i < rows; i++) {
StringBuilder sb = new StringBuilder();
for (int j = 0; j < cols; j++) {
sb.append(grid[i][j].isAlive() ? "1" : "0").append(";");
}
stateStrings[i] = sb.toString();
}
return stateStrings;
}
public boolean isInsideWorld(int x, int y) {
return (x >= 0 && x < cols && y >= 0 && y < rows);
}
public void addAgent(Agent agent) {
agents.add(agent);
}
public void removeAgent(Agent agent) {
agents.remove(agent);
}
public List<Agent> getAgents() {
return agents;
}
private void checkCollisions() {
for (Agent agent1 : agents) {
if (agent1 instanceof Wolf) {
for (Agent agent2 : agents) {
if (agent2 instanceof Sheep && agent1.getX() == agent2.getX() && agent1.getY() == agent2.getY()) {
System.out.println("A wolf caught a sheep at (" + agent1.getX() + ", " + agent1.getY() + ")");
agents.remove(agent2);
break;
}
}
}
}
}
public Color getBackgroundColor() {
return backgroundColor;
}
public void setBackgroundColor(Color backgroundColor) {
this.backgroundColor = backgroundColor;
}
}

View File

@ -0,0 +1,93 @@
package windowInterface;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
import backend.Agent;
import backend.Sheep;
import backend.Wolf;
import backend.Simulator;
import backend.World;
public class JPanelDraw extends JPanel {
private static final long serialVersionUID = 1L;
private Simulator mySimu;
private MyInterface interfaceGlobal;
public JPanelDraw(MyInterface itf) {
super();
mySimu = null;
interfaceGlobal = itf;
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
if (mySimu == null) {
interfaceGlobal.instantiateSimu();
}
int x = (me.getX() * mySimu.getWidth()) / getWidth();
int y = (me.getY() * mySimu.getHeight()) / getHeight();
if (interfaceGlobal.getClickAction() == 1) {
mySimu.addAgent(new Sheep(x, y, mySimu.getWorld()));
} else if (interfaceGlobal.getClickAction() == 2) {
mySimu.addAgent(new Wolf(x, y, mySimu.getWorld()));
} else {
mySimu.clickCell(x, y);
}
repaint();
}
});
}
public void setSimu(Simulator simu) {
mySimu = simu;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (mySimu != null) {
World currentWorld = mySimu.getWorld();
Color backgroundColor = currentWorld.getBackgroundColor();
this.setBackground(backgroundColor);
float cellWidth = (float) this.getWidth() / (float) mySimu.getWidth();
float cellHeight = (float) this.getHeight() / (float) mySimu.getHeight();
g.setColor(Color.gray);
for (int x = 0; x < mySimu.getWidth(); x++) {
int graphX = Math.round(x * cellWidth);
g.drawLine(graphX, 0, graphX, this.getHeight());
}
for (int y = 0; y < mySimu.getHeight(); y++) {
int graphY = Math.round(y * cellHeight);
g.drawLine(0, graphY, this.getWidth(), graphY);
}
for (int x = 0; x < mySimu.getWidth(); x++) {
for (int y = 0; y < mySimu.getHeight(); y++) {
int cellContent = mySimu.getCell(x, y);
if (cellContent == 0) {
continue;
}
if (cellContent == 1) {
g.setColor(Color.green);
}
g.fillRect(
(int) Math.round(x * cellWidth),
(int) Math.round(y * cellHeight),
(int) Math.round(cellWidth),
(int) Math.round(cellHeight)
);
}
}
for (Agent animal : mySimu.getAnimals()) {
g.setColor(animal.getDisplayColor());
int animalSizeMultiplier = 2; // Adjust this value to change the size of the animals
int animalSize = Math.min((int) Math.round(Math.min(cellWidth, cellHeight) * animalSizeMultiplier), Math.min((int) Math.round(cellWidth), (int) Math.round(cellHeight)));
g.fillOval((int) Math.round(animal.getX() * cellWidth),
(int) Math.round(animal.getY() * cellHeight),
animalSize,
animalSize);
}
}
}
}

View File

@ -0,0 +1,172 @@
package windowInterface;
import javax.swing.*;
import backend.Simulator;
import backend.Sheep;
import backend.Wolf;
import backend.World;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MyInterface extends JFrame {
private static final long serialVersionUID = 1L;
private JPanelDraw panelDraw;
private Simulator simulator;
private JButton startButton;
private JButton pauseButton;
private JButton stopButton;
private JButton addSheepButton;
private JButton addWolfButton;
private JButton changeWorldButton;
private JSlider speedSlider;
private JLabel stepCountLabel;
private JTextArea messageArea;
private int clickAction = 0;
private int currentWorldIndex = 0;
private World[] worlds;
public MyInterface() {
setTitle("Game of Life Simulator");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
// Initialize worlds
worlds = new World[7];
worlds[0] = new World(50, 50, true, Color.BLACK); // World 1
worlds[1] = new World(40, 40, true, Color.CYAN); // World 2
worlds[2] = new World(60, 60, true, Color.ORANGE); // World 3
worlds[3] = new World(70, 70, true, Color.MAGENTA); // World 4
worlds[4] = new World(45, 45, true, Color.YELLOW); // World 5
worlds[5] = new World(55, 55, true, Color.PINK); // World 6
worlds[6] = new World(35, 35, true, Color.GREEN); // World 7
panelDraw = new JPanelDraw(this);
add(panelDraw, BorderLayout.CENTER);
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new GridLayout(2, 1));
JPanel buttonPanel = new JPanel();
startButton = new JButton("Start");
pauseButton = new JButton("Pause");
stopButton = new JButton("Stop");
addSheepButton = new JButton("Add Sheep");
addWolfButton = new JButton("Add Wolf");
changeWorldButton = new JButton("Change World");
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (simulator != null && !simulator.isRunning()) {
simulator.start();
}
}
});
pauseButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (simulator != null) {
simulator.togglePause();
}
}
});
stopButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (simulator != null) {
simulator.stopSimu();
}
}
});
addSheepButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
clickAction = 1;
}
});
addWolfButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
clickAction = 2;
}
});
changeWorldButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (simulator != null) {
currentWorldIndex = (currentWorldIndex + 1) % worlds.length; // Cycle through worlds
simulator.setWorld(worlds[currentWorldIndex]); // Set the next world
}
}
});
buttonPanel.add(startButton);
buttonPanel.add(pauseButton);
buttonPanel.add(stopButton);
buttonPanel.add(addSheepButton);
buttonPanel.add(addWolfButton);
buttonPanel.add(changeWorldButton);
controlPanel.add(buttonPanel);
JPanel sliderPanel = new JPanel();
speedSlider = new JSlider(0, 1000, 500);
speedSlider.setMajorTickSpacing(100);
speedSlider.setPaintTicks(true);
speedSlider.setPaintLabels(true);
speedSlider.addChangeListener(e -> {
if (simulator != null) {
simulator.setLoopDelay(speedSlider.getValue());
}
});
sliderPanel.add(new JLabel("Speed:"));
sliderPanel.add(speedSlider);
stepCountLabel = new JLabel("Step Count: 0");
sliderPanel.add(stepCountLabel);
messageArea = new JTextArea(5, 20);
messageArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(messageArea);
controlPanel.add(sliderPanel);
add(controlPanel, BorderLayout.SOUTH);
add(scrollPane, BorderLayout.EAST);
instantiateSimu();
}
public void instantiateSimu() {
// Initialize with the first world
simulator = new Simulator(this, worlds[0]);
panelDraw.setSimu(simulator);
}
public void update(int stepCount) {
stepCountLabel.setText("Step Count: " + stepCount);
panelDraw.repaint();
}
public void printMessage(String message) {
messageArea.append(message + "\n");
}
public int getClickAction() {
return clickAction;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
MyInterface myInterface = new MyInterface();
myInterface.setVisible(true);
});
}
}