diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java index 1cf89653fbc8e469e235f1f8a9ba3fddc836b6b0..db764189db577ec62828f2bcf9cc7876c1a36dbc 100644 --- a/src/main/java/controller/Controller.java +++ b/src/main/java/controller/Controller.java @@ -21,14 +21,15 @@ import javafx.util.Duration; import javafx.util.Pair; import model.Board; import model.EntityFactory; +import model.Model; import model.Square; import model.firefighterscenario.Cloud; import model.firefighterscenario.Fire; import model.firefighterscenario.FireFighter; -import model.firefighterscenario.FireFighterScenario; import model.firefighterscenario.MotorizedFireFighter; import model.firefighterscenario.Mountain; import model.firefighterscenario.Rockery; +import model.rockpapercisor.RockPaperCisorScenario; import util.Position; import view.Grid; import view.ViewElement; @@ -50,6 +51,7 @@ public class Controller { private Grid<ViewElement> grid; private Timeline timeline; private Board<Square> board; + private Model model; @FXML private void initialize() { @@ -63,12 +65,13 @@ public class Controller { pauseToggleButton.setSelected(true); } - private void setModel(Board<Square> board) { - this.board = requireNonNull(board, "board is null"); + private void setModel(Model model) { + this.board = requireNonNull(model.getBoard(), "board is null"); + this.model = model; } private void updateBoard() { - List<Position> updatedPositions = board.updateToNextGeneration(); + List<Position> updatedPositions = model.updateToNextGeneration(); List<Pair<Position, ViewElement>> updatedSquares = new ArrayList<>(); for (Position updatedPosition : updatedPositions) { Square squareState = board.getStates(updatedPosition); @@ -128,7 +131,7 @@ public class Controller { public void initialize(int squareWidth, int squareHeight, int columnCount, int rowCount, int initialFireCount, int initialFirefighterCount, int initialMotorizedFirefightersCount, int initialcloudCount, int initialmountaincount, int turnsForSpawningAirTanker) { grid.setDimensions(columnCount, rowCount, squareWidth, squareHeight); - Board<Square> model = new FireFighterScenario(columnCount, rowCount); + Map<EntityFactory, Integer> entityCounts = new HashMap<EntityFactory, Integer>(); entityCounts.put((pos, b) -> new Fire(pos), initialFireCount); @@ -137,8 +140,7 @@ public class Controller { entityCounts.put((pos, b) -> new Cloud(pos, b), initialcloudCount); entityCounts.put((pos, b) -> new Mountain(pos), initialmountaincount); entityCounts.put((pos, b) -> new Rockery(pos), 3); - - model.placeInitialEntities(entityCounts); + Model model = new RockPaperCisorScenario(columnCount, rowCount, entityCounts); this.setModel(model); repaintGrid(); } diff --git a/src/main/java/model/Board.java b/src/main/java/model/Board.java index 6d51304610a1f242df6974939c6a4b92a5841c52..ba9d84bd84408c3383ea156d11c69c9a09b8dbe3 100644 --- a/src/main/java/model/Board.java +++ b/src/main/java/model/Board.java @@ -1,6 +1,5 @@ package model; -import java.util.List; import java.util.Map; import util.Position; @@ -43,15 +42,6 @@ public interface Board<S> { */ int columnCount(); - /** - * Update the board to its next generation or state. This method may modify the - * internal state of the board and return a list of positions that have changed - * during the update. - * - * @return A list of positions that have changed during the update. - */ - List<Position> updateToNextGeneration(); - /** * Reset the board to its initial state. */ diff --git a/src/main/java/model/EntityScenario.java b/src/main/java/model/EntityScenario.java deleted file mode 100644 index fdbedaac570216fd1e5fb9626d1f0fb78b17c1b7..0000000000000000000000000000000000000000 --- a/src/main/java/model/EntityScenario.java +++ /dev/null @@ -1,15 +0,0 @@ -package model; - -import util.Matrix; -import util.Position; - -public abstract class EntityScenario implements Scenario{ - public void initScenario(Matrix<Square> matrix){ - for(int x = 0; x < matrix.getRows(); x++){ - for(int y = 0; y < matrix.getColumns(); y++){ - Square s = new Square(new Position(x, y), new EmptySquare(new Position(x,y))); - matrix.set(x,y, s); - } - } - } -} diff --git a/src/main/java/model/Model.java b/src/main/java/model/Model.java new file mode 100644 index 0000000000000000000000000000000000000000..64bd75a7a9d95ae0a82f2fdfc0cc90e7034dec88 --- /dev/null +++ b/src/main/java/model/Model.java @@ -0,0 +1,10 @@ +package model; + +import java.util.List; + +import util.Position; + +public interface Model { + public List<Position> updateToNextGeneration(); + public Board<Square> getBoard(); +} diff --git a/src/main/java/model/Scenario.java b/src/main/java/model/Scenario.java index 03d319a9325df2547e011ba58d5243e34f116b13..eda8cc583ec2b46be4f46f739ada86e626290bb3 100644 --- a/src/main/java/model/Scenario.java +++ b/src/main/java/model/Scenario.java @@ -1,8 +1,207 @@ package model; + +import java.util.List; +import java.util.Map; +import java.util.Random; + +import app.SimulatorApplication; +import model.firefighterscenario.Fire; +import model.firefighterscenario.Mountain; +import model.firefighterscenario.Road; +import model.firefighterscenario.Rockery; import util.Matrix; +import util.PathGenerator; +import util.Position; +import util.PositionUtil; + +public class Scenario implements Board<Square>{ + + private Matrix<Square> matrix; + protected int step; + protected int turnsToSpawnAirTanker; + + private Map<EntityFactory, Integer> initialMap; + + public Scenario(int columns, int rows, Map<EntityFactory, Integer> initialMap) { + this.matrix = new Matrix<Square>(columns, rows); + initScenario(matrix); + this.turnsToSpawnAirTanker = SimulatorApplication.TURNS_FOR_SPAWNING_AIRTANKER; + this.step = 0; + this.initialMap = initialMap; + placeInitialEntities(initialMap); + } + public void initScenario(Matrix<Square> matrix){ + for(int x = 0; x < matrix.getRows(); x++){ + for(int y = 0; y < matrix.getColumns(); y++){ + Square s = new Square(new Position(x, y), new EmptySquare(new Position(x,y))); + matrix.set(x,y, s); + } + } +} + protected Matrix<Square> getMatrix(){ + return this.matrix; + } + + public void placeInitialEntities(Map<EntityFactory, Integer> initialMap) { + EntitySpawner spawner = new EntitySpawner(this); + spawner.spawnEntities(initialMap); + generateRoads(); + + } + + public Square getStates(Position position) { + if (position.x() > matrix.size() || position.y() > matrix.size()) { + throw new IllegalArgumentException( + "The position x:" + position.x() + " y:" + position.y() + " is out of the board."); + } + return matrix.get(position.x(), position.y()); + } + + public void setSquare(Square square) { + Position position = square.getPosition(); + if (!(getStates(position).isEmpty())) { + return; + } + if (doesPositionExist(position)) { + matrix.set(position.x(), position.y(), square); + } + } + + public void setSquare(Square square, boolean replaceStates) { + Position position = square.getPosition(); + if (!(getStates(position).isEmpty()) && !replaceStates) { + return; + } + matrix.set(position.x(), position.y(), square); + } + + public void addEntityAtSquare(Entity entity, Position position) { + if (doesPositionExist(position)) { + matrix.get(position.x(), position.y()).addEntity(entity); + } + } + + public int rowCount() { + return matrix.getRows(); + } + + public int columnCount() { + return matrix.getColumns(); + } + + @Override + public void clearCaseFrom(Entity entity, Position position) { + matrix.get(position.x(), position.y()).getEntities().removeIf(element -> element.equals(entity)); + } + + public Position getNearestEntity(Position fromPos, Class<?> entityType) { + int rows = matrix.getRows(); + int cols = matrix.getColumns(); + Position nearestPosition = fromPos; + + // Définir la distance maximale possible + int maxDistance = rows + cols; + // Parcourir les distances croissantes à partir de 1 + for (int distance = 1; distance < maxDistance; distance++) { + List<Position> positionsAtDistance = PositionUtil.getPositionsAtManhattanDistance(fromPos, distance, rows, cols); + + for (Position currentPos : positionsAtDistance) { + Square currentSquare = matrix.get(currentPos.x(), currentPos.y()); + for (Entity currentEntity : currentSquare.getEntities()) { + if (entityType.isInstance(currentEntity)) { + // Dès qu'une entité est trouvée à cette distance, elle est la plus proche + // possible + return currentPos; + } + } + } + } + + return nearestPosition; // Retourne null si aucune entité n'est trouvée + } + + public void reset() { + step = 0; + matrix.clear(); + initScenario(matrix); + placeInitialEntities(initialMap); + } + + public int stepNumber() { + return this.step; + } + + @Override + public boolean doesPositionExist(Position position) { + return matrix.validateIndex(position); + } + + @Override + public int getStepNumber() { + return step; + } + + @Override + public boolean doesSquareContainEntity(Position squarePos, Class<?> entityType) { + return getStates(squarePos).getEntities().stream().anyMatch(entityType::isInstance); + } + + @Override + public boolean isPositionEmpty(Position position) { + return getStates(position).isEmpty(); + } + + @Override + public boolean isPositionFree(Position position, int priority) { + List<Entity> entities = matrix.get(position.x(), position.y()).getEntities(); + for (Entity e : entities) { + if (e.getPriority() == priority) { + return false; + } + } + return true; + } + + private void generateRoads() { + if(columnCount() < 10 || rowCount() < 10){ + return; + } + Random random = new Random(); + + // Get board dimensions + int rowCount = rowCount(); // Number of rows (vertical axis) + int columnCount = columnCount(); // Number of columns (horizontal axis) + + // Decide randomly whether to set x or y to 0 + boolean setXToZero = random.nextBoolean(); + + int x = 0; + int y = 0; + + if (setXToZero) { + // x is set to 0, y is random within column bounds + x = 0; + y = random.nextInt(columnCount); + } else { + // y is set to 0, x is random within row bounds + x = random.nextInt(rowCount); + y = 0; + } -public interface Scenario { - public void initScenario(Matrix<Square> matrix); + Position startPosition = new Position(x, y); + PathGenerator pathGenerator = new PathGenerator(this, startPosition, 4, columnCount()); + // Call generateEntitiesInLine to place the roads + List<Position> snake = pathGenerator.generate(); + for(Position p : snake){ + List<Entity> entitiesAtSquare = List.copyOf(getStates(p).getEntities()); + for(Entity e: entitiesAtSquare){ + if(e instanceof Mountain || e instanceof Rockery || e instanceof Fire){ + clearCaseFrom(e, e.getPosition()); + } + } + addEntityAtSquare(new Road(p), p); + } +} -} \ No newline at end of file +} diff --git a/src/main/java/model/firefighterscenario/FireFighterScenario.java b/src/main/java/model/firefighterscenario/FireFighterScenario.java index 658e958f83b44936128658603b802895a69197a7..6604278540ee3baccfb9db7232c67a26543228c7 100644 --- a/src/main/java/model/firefighterscenario/FireFighterScenario.java +++ b/src/main/java/model/firefighterscenario/FireFighterScenario.java @@ -6,88 +6,24 @@ import java.util.List; import java.util.Map; import java.util.Random; -import app.SimulatorApplication; import model.Board; import model.Entity; import model.EntityFactory; -import model.EntityScenario; -import model.EntitySpawner; +import model.Model; +import model.Scenario; import model.Square; -import util.Matrix; import util.PathGenerator; import util.Position; -import util.PositionUtil; -public class FireFighterScenario extends EntityScenario implements Board<Square> { - - private Matrix<Square> matrix; - private int step; - private int turnsToSpawnAirTanker; - - private Map<EntityFactory, Integer> initialMap; - - public FireFighterScenario(int columns, int rows) { - this.matrix = new Matrix<Square>(columns, rows); - initScenario(matrix); - this.turnsToSpawnAirTanker = SimulatorApplication.TURNS_FOR_SPAWNING_AIRTANKER; - this.step = 0; - } - - public void placeInitialEntities(Map<EntityFactory, Integer> entityCounts) { - EntitySpawner spawner = new EntitySpawner(this); - spawner.spawnEntities(entityCounts); +public class FireFighterScenario extends Scenario implements Model{ + public FireFighterScenario(int columns, int rows, Map<EntityFactory, Integer> initialMap) { + super(columns, rows, initialMap); generateRoads(); - this.initialMap = entityCounts; - } - - public Square getStates(Position position) { - if (position.x() > matrix.size() || position.y() > matrix.size()) { - throw new IllegalArgumentException( - "The position x:" + position.x() + " y:" + position.y() + " is out of the board."); - } - return matrix.get(position.x(), position.y()); - } - - public void setSquare(Square square) { - Position position = square.getPosition(); - if (!(getStates(position).isEmpty())) { - return; - } - if (doesPositionExist(position)) { - matrix.set(position.x(), position.y(), square); - } - } - - public void setSquare(Square square, boolean replaceStates) { - Position position = square.getPosition(); - if (!(getStates(position).isEmpty()) && !replaceStates) { - return; - } - matrix.set(position.x(), position.y(), square); - } - - public void addEntityAtSquare(Entity entity, Position position) { - if (doesPositionExist(position)) { - matrix.get(position.x(), position.y()).addEntity(entity); - } - } - - public int rowCount() { - return matrix.getRows(); - } - - public int columnCount() { - return matrix.getColumns(); - } - - @Override - public void clearCaseFrom(Entity entity, Position position) { - matrix.get(position.x(), position.y()).getEntities().removeIf(element -> element.equals(entity)); } public List<Position> updateToNextGeneration() { ArrayList<Position> changedPositions = new ArrayList<>(); - Iterator<Square> iterator = matrix.iterator(); + Iterator<Square> iterator = getMatrix().iterator(); while (iterator.hasNext()) { Square s = iterator.next(); @@ -115,7 +51,6 @@ public class FireFighterScenario extends EntityScenario implements Board<Square> // Check if it's time to spawn an AirTanker if (this.step % this.turnsToSpawnAirTanker == 0) { - System.out.println("apparation"); // Spawn an AirTanker at a random edge position spawnAirTanker(changedPositions); } @@ -156,74 +91,6 @@ public class FireFighterScenario extends EntityScenario implements Board<Square> changedPositions.add(position); } - public Position getNearestEntity(Position fromPos, Class<?> entityType) { - int rows = matrix.getRows(); - int cols = matrix.getColumns(); - Position nearestPosition = fromPos; - - // Définir la distance maximale possible - int maxDistance = rows + cols; - // Parcourir les distances croissantes à partir de 1 - for (int distance = 1; distance < maxDistance; distance++) { - List<Position> positionsAtDistance = PositionUtil.getPositionsAtManhattanDistance(fromPos, distance, rows, cols); - - for (Position currentPos : positionsAtDistance) { - Square currentSquare = matrix.get(currentPos.x(), currentPos.y()); - for (Entity currentEntity : currentSquare.getEntities()) { - if (entityType.isInstance(currentEntity)) { - // Dès qu'une entité est trouvée à cette distance, elle est la plus proche - // possible - return currentPos; - } - } - } - } - - return nearestPosition; // Retourne null si aucune entité n'est trouvée - } - - public void reset() { - step = 0; - matrix.clear(); - initScenario(matrix); - placeInitialEntities(initialMap); - } - - public int stepNumber() { - return this.step; - } - - @Override - public boolean doesPositionExist(Position position) { - return matrix.validateIndex(position); - } - - @Override - public int getStepNumber() { - return step; - } - - @Override - public boolean doesSquareContainEntity(Position squarePos, Class<?> entityType) { - return getStates(squarePos).getEntities().stream().anyMatch(entityType::isInstance); - } - - @Override - public boolean isPositionEmpty(Position position) { - return getStates(position).isEmpty(); - } - - @Override - public boolean isPositionFree(Position position, int priority) { - List<Entity> entities = matrix.get(position.x(), position.y()).getEntities(); - for (Entity e : entities) { - if (e.getPriority() == priority) { - return false; - } - } - return true; - } - private void generateRoads() { if(columnCount() < 10 || rowCount() < 10){ return; @@ -265,4 +132,9 @@ public class FireFighterScenario extends EntityScenario implements Board<Square> } } + @Override + public Board<Square> getBoard() { + return this; + } + } diff --git a/src/main/java/model/rockpapercisor/RockPaperCisorScenario.java b/src/main/java/model/rockpapercisor/RockPaperCisorScenario.java new file mode 100644 index 0000000000000000000000000000000000000000..2d977b112aa2dc6bbc5563f830ccbd8e9cd12068 --- /dev/null +++ b/src/main/java/model/rockpapercisor/RockPaperCisorScenario.java @@ -0,0 +1,26 @@ +package model.rockpapercisor; + +import java.util.List; +import java.util.Map; + +import model.Board; +import model.EntityFactory; +import model.Model; +import model.Scenario; +import model.Square; +import util.Position; + +public class RockPaperCisorScenario extends Scenario implements Model{ + public RockPaperCisorScenario(int columns, int rows, Map<EntityFactory, Integer> initialMap) { + super(columns, rows, initialMap); + } + + public List<Position> updateToNextGeneration(){ + return List.of(); + } + + @Override + public Board<Square> getBoard() { + return this; + } +} diff --git a/src/main/java/model/virus/Doctor.java b/src/main/java/model/virus/Doctor.java new file mode 100644 index 0000000000000000000000000000000000000000..81469f4000f78e00eb110b4138e55e2ed09eee95 --- /dev/null +++ b/src/main/java/model/virus/Doctor.java @@ -0,0 +1,61 @@ +package model.virus; + +import java.util.List; + +import javafx.scene.paint.Color; +import model.Board; +import model.Entity; +import model.Square; +import util.Position; + +public class Doctor implements Entity{ + + private Position position; + private final Color VIEW_COLOR = Color.RED; + private int age; + private final int PRIORITY = 1; + public Doctor(Position position){ + this.position = position; + this.age = 0; + } + @Override + public List<Position> nextTurn(Board<Square> board) { + return List.of(); + } + + @Override + public Position getPosition() { + return this.position; + } + + @Override + public void setPosition(Position p) { + this.position = p; + } + + @Override + public int getAge() { + return age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + + @Override + public void incrementAge() { + this.age = age + 1; + } + + @Override + public Color getViewColor() { + return this.VIEW_COLOR; + } + + @Override + public int getPriority() { + return this.PRIORITY; + } + +} diff --git a/src/main/java/model/virus/Patient.java b/src/main/java/model/virus/Patient.java new file mode 100644 index 0000000000000000000000000000000000000000..28c7c7cfa83381602f841b9276b13acd4cba1d33 --- /dev/null +++ b/src/main/java/model/virus/Patient.java @@ -0,0 +1,67 @@ +package model.rockpapercisor; + +import java.util.List; + +import javafx.scene.paint.Color; +import model.Board; +import model.Entity; +import model.Square; +import util.Position; + +public class Patient implements Entity{ + + private Position position; + private final Color VIEW_COLOR = Color.BLUE; + private int age; + private final int PRIORITY = 1; + private final boolean isSick; + public Patient(Position position){ + this.position = position; + this.age = 0; + this.isSick = false; + } + @Override + public List<Position> nextTurn(Board<Square> board) { + if(isSick){ + return List.of(); + }else{ + return List.of(); + } + } + + @Override + public Position getPosition() { + return this.position; + } + + @Override + public void setPosition(Position p) { + this.position = p; + } + + @Override + public int getAge() { + return age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + + @Override + public void incrementAge() { + this.age = age + 1; + } + + @Override + public Color getViewColor() { + return this.VIEW_COLOR; + } + + @Override + public int getPriority() { + return this.PRIORITY; + } + +} diff --git a/src/main/java/model/virus/Virus.java b/src/main/java/model/virus/Virus.java new file mode 100644 index 0000000000000000000000000000000000000000..cf558b157a92d88c3d366bf088d5cc2f0a45e44b --- /dev/null +++ b/src/main/java/model/virus/Virus.java @@ -0,0 +1,61 @@ +package model.virus; + +import java.util.List; + +import javafx.scene.paint.Color; +import model.Board; +import model.Entity; +import model.Square; +import util.Position; + +public class Virus implements Entity{ + + private Position position; + private final Color VIEW_COLOR = Color.LIMEGREEN; + private int age; + private final int PRIORITY = 1; + public Virus(Position position){ + this.position = position; + this.age = 0; + } + @Override + public List<Position> nextTurn(Board<Square> board) { + return List.of(); + } + + @Override + public Position getPosition() { + return this.position; + } + + @Override + public void setPosition(Position p) { + this.position = p; + } + + @Override + public int getAge() { + return age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + + @Override + public void incrementAge() { + this.age = age + 1; + } + + @Override + public Color getViewColor() { + return this.VIEW_COLOR; + } + + @Override + public int getPriority() { + return this.PRIORITY; + } + +}