diff --git a/scenariovirus.txt b/scenariovirus.txt new file mode 100644 index 0000000000000000000000000000000000000000..d43e533bb6bbb2ca17d9d80a418b2e6f13b7b03b --- /dev/null +++ b/scenariovirus.txt @@ -0,0 +1,15 @@ +Patients : +- Interactions et mouvement : Se déplacent et interagissent socialement, augmentant ainsi les chances de transmission du virus. Certains peuvent être asymptomatiques. +- Réaction en cas de maladie : S'ils se rendent compte qu'ils sont malades, ils cherchent un docteur pour se faire soigner. Sinon, ils continuent leur vie normalement, pouvant transmettre le virus sans le savoir. + + +Virus : +- Mouvement et infection : Entité unique sur le plateau qui se déplace aléatoirement, infectant les patients lorsqu'il passe à proximité. +- Le virus infecte les patients lorsqu'il passe à proximité. +- Évolue tous les 30 tours pour donner un nouveau variant, lorsqu'un nouveau variant est détecté, les médecins mettent plus de temps à le soigner au début + + +Docteurs : +- Traitement des patients : Traitent les patients malades qui se trouvent dans des cases adjacentes à leur position. +- Statique : Ne se déplacent pas entre les tours, ce qui nécessite que les patients viennent à eux pour être soignés. + diff --git a/src/main/java/app/SimulatorApplication.java b/src/main/java/app/SimulatorApplication.java index a2d7b95bdd1335ff818e23b64d4d5cf1b574323e..bbd21177c5517a1dc4bc9761b70892cca494217a 100644 --- a/src/main/java/app/SimulatorApplication.java +++ b/src/main/java/app/SimulatorApplication.java @@ -13,8 +13,8 @@ import javafx.stage.Stage; public class SimulatorApplication extends javafx.application.Application { private static final String VIEW_RESOURCE_PATH = "/view/view.fxml"; private static final String APP_NAME = "Firefighter simulator"; - private static final int ROW_COUNT = 40; - private static final int COLUMN_COUNT = 40; + private static final int ROW_COUNT = 50; + private static final int COLUMN_COUNT = 50; private static final int BOX_WIDTH = 15; private static final int BOX_HEIGHT = 15; public static final int INITIAL_FIRE_COUNT = 8; diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java index 2a95d8e59d7e0363aa347c8e73e49d185ab84f55..0976e4f7632dcd050dd95e6e19222ef98ec37e75 100644 --- a/src/main/java/controller/Controller.java +++ b/src/main/java/controller/Controller.java @@ -22,14 +22,12 @@ import javafx.util.Pair; import model.Board; import model.Entity; 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.doctorviruspatient.Doctor; +import model.doctorviruspatient.DoctorVirusPatientScenario; +import model.doctorviruspatient.Patient; +import model.doctorviruspatient.Virus; import util.Position; import view.Grid; import view.ViewElement; @@ -51,6 +49,7 @@ public class Controller { private Grid<ViewElement> grid; private Timeline timeline; private Board<Square> board; + private Model model; @FXML private void initialize() { @@ -64,12 +63,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); @@ -135,21 +135,33 @@ 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); entityCounts.put((pos, b) -> new FireFighter(pos,b), initialFirefighterCount); entityCounts.put((pos, b) -> new MotorizedFireFighter(pos, b), initialMotorizedFirefightersCount); 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); + */ + + /* + entityCounts.put((pos, b) -> new Rock(pos), 10); + entityCounts.put((pos, b) -> new Cisor(pos), 10); + entityCounts.put((pos, b) -> new Paper(pos), 10); + */ + + + entityCounts.put((pos, b) -> new Patient(pos), 70); + entityCounts.put((pos, b) -> new Virus(pos), 6); + entityCounts.put((pos, b) -> new Doctor(pos), 3); + + Model model = new DoctorVirusPatientScenario(columnCount, rowCount, entityCounts); this.setModel(model); repaintGrid(); } - + public void oneStepButtonAction() { this.pause(); updateBoard(); diff --git a/src/main/java/model/Board.java b/src/main/java/model/Board.java index 6d51304610a1f242df6974939c6a4b92a5841c52..6fc78ddca79a959bf915ed614020208bd9016cc4 100644 --- a/src/main/java/model/Board.java +++ b/src/main/java/model/Board.java @@ -43,15 +43,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. */ @@ -73,7 +64,7 @@ public interface Board<S> { public void clearCaseFrom(Entity entity, Position position); - public Position getNearestEntity(Position fromPos, Class<?> entityType); + public Position getNearestEntity(Position fromPos, Class<?> entityType, List<Entity> exclusionList); public boolean doesSquareContainEntity(Position squarePos, Class<?> entityType); diff --git a/src/main/java/model/EntityNotFoundException.java b/src/main/java/model/EntityNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..9902ad982952d8d34e0ceb55266b8782b9901a98 --- /dev/null +++ b/src/main/java/model/EntityNotFoundException.java @@ -0,0 +1,7 @@ +package model; + +class EntityNotFoundException extends Exception { + public EntityNotFoundException(String message) { + super(message); + } +} \ No newline at end of file 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/EntitySpawner.java b/src/main/java/model/EntitySpawner.java index c8f0de6aaa1e51b620125129ff323268c92f6d96..bd6fa6e39196e6ffd798760bc8546e96887694f2 100644 --- a/src/main/java/model/EntitySpawner.java +++ b/src/main/java/model/EntitySpawner.java @@ -12,6 +12,7 @@ import java.util.Set; import util.Direction; import util.Position; +import util.PositionUtil; public class EntitySpawner { private final Board<Square> board; @@ -120,7 +121,7 @@ public class EntitySpawner { int roadLength = 1; // Déterminer la direction interdite (opposée à la direction initiale) - Direction forbiddenDirection = getOppositeDirection(initialDirection); + Direction forbiddenDirection = PositionUtil.getOppositeDirection(initialDirection); // Initialiser la direction courante Direction currentDirection = initialDirection; @@ -163,7 +164,7 @@ public class EntitySpawner { // Mettre à jour la direction courante currentDirection = newDirection; - forbiddenDirection = getOppositeDirection(currentDirection); + forbiddenDirection = PositionUtil.getOppositeDirection(currentDirection); stepsInCurrentDirection = 0; continue; // Recommencer avec la nouvelle direction } else { @@ -185,7 +186,7 @@ public class EntitySpawner { // Mettre à jour la direction courante currentDirection = newDirection; - forbiddenDirection = getOppositeDirection(currentDirection); + forbiddenDirection = PositionUtil.getOppositeDirection(currentDirection); stepsInCurrentDirection = 0; } } @@ -249,15 +250,7 @@ public class EntitySpawner { } } - private static Direction getOppositeDirection(Direction direction) { - switch (direction) { - case NORTH: return Direction.SOUTH; - case SOUTH: return Direction.NORTH; - case EAST: return Direction.WEST; - case WEST: return Direction.EAST; - default: throw new IllegalArgumentException("Direction non supportée : " + direction); - } - } + 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..b0943a4088cf9a90a66edee097db249ae2295476 100644 --- a/src/main/java/model/Scenario.java +++ b/src/main/java/model/Scenario.java @@ -1,8 +1,166 @@ package model; + +import java.util.List; +import java.util.Map; + +import app.SimulatorApplication; import util.Matrix; +import util.Position; +import util.PositionUtil; + +public class Scenario implements Board<Square>{ + + private Matrix<Square> matrix; + protected int step; + protected int turnsToSpawnAirTanker; + + protected 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); + + } + + 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) { + if(!matrix.get(position.x(), position.y()).getEntities().removeIf(element -> element.equals(entity))){ + System.out.println("didn't clear, tried to clear : x:" + position.x() + " y : " + position.y()); + for(Entity e : getStates(position).getEntities()){ + System.out.println(e); + } + } + } + + public Position getNearestEntity(Position fromPos, Class<?> entityType, List<Entity> exclusionList) { + int rows = matrix.getRows(); + int cols = matrix.getColumns(); + if(exclusionList == null){ + exclusionList = List.of(); + } + // 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) { + if(isPositionEmpty(currentPos))continue; + Square currentSquare = matrix.get(currentPos.x(), currentPos.y()); + for (Entity currentEntity : currentSquare.getEntities()) { + if (entityType.isInstance(currentEntity) && exclusionList != null && !exclusionList.contains(currentEntity)) { + // Vérifie si l'entité actuelle n'est pas dans la liste des exclusions + // Dès qu'une entité éligible est trouvée à cette distance, elle est la plus proche possible + return currentPos; + } + } + } + } + return null; // Retourne null si aucune entité éligible 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(); + } -public interface Scenario { - public void initScenario(Matrix<Square> matrix); + @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; + } -} \ No newline at end of file +} diff --git a/src/main/java/model/doctorviruspatient/Doctor.java b/src/main/java/model/doctorviruspatient/Doctor.java new file mode 100644 index 0000000000000000000000000000000000000000..e84b6ab140944ebaa39ef62c5c137524286616b3 --- /dev/null +++ b/src/main/java/model/doctorviruspatient/Doctor.java @@ -0,0 +1,155 @@ +package model.doctorviruspatient; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import javafx.scene.paint.Color; +import model.Board; +import model.Entity; +import model.Square; +import util.Position; +import util.PositionUtil; + +public class Doctor implements Entity { + private final int priority = 1; + private Position position; + private int age; + private final Color viewColor = Color.RED; + + // Statique car les médecins partagent les connaissances et les recherches + private static List<Integer> knownVirusVariant = new ArrayList<Integer>(); + private static Map<Integer, Double> currentResearch = new HashMap<>(); // Map<variantId, % de recherche> + + public Doctor(Position p) { + this.position = p; + } + + public Doctor(Position p, int age) { + this.position = p; + this.age = age; + } + + @Override + public List<Position> nextTurn(Board<Square> board) { + // Mettre à jour les recherches en cours + updateCurrentResearch(); + + // Interagir avec les positions adjacentes + interactWithAdjacentPositions(PositionUtil.generateAllAdjacentPositions(position, board), board); + + return List.of(); + } + + /** + * Met à jour toutes les recherches en cours en augmentant leur avancement de x%. + * Si une recherche atteint ou dépasse 100%, elle est terminée. + */ + private void updateCurrentResearch() { + List<Integer> completedResearch = new ArrayList<>(); + + for (Map.Entry<Integer, Double> entry : currentResearch.entrySet()) { + int variantId = entry.getKey(); + double progress = entry.getValue() + 2.0; + if (progress >= 100.0) { + progress = 100.0; + completedResearch.add(variantId); + } + currentResearch.put(variantId, progress); + } + + // Traiter les recherches complétées + for (int variantId : completedResearch) { + currentResearch.remove(variantId); + knownVirusVariant.add(variantId); + System.out.println("Recherche terminée pour le variant ID: " + variantId); + } + } + + private List<Position> interactWithAdjacentPositions(List<Position> adjacentPositions, Board<Square> board) { + List<Position> result = new ArrayList<>(); + for (Position p : adjacentPositions) { + if (board.doesSquareContainEntity(p, Patient.class)) { + handleEncounterWithPatient(p, board); + } + } + return result; + } + + private void handleEncounterWithPatient(Position p, Board<Square> board) { + if (board.doesSquareContainEntity(p, Patient.class)) { + Patient patient = (Patient) board.getStates(p).getEntities().stream() + .filter(e -> e instanceof Patient) + .findFirst() + .orElse(null); + if (patient != null && patient.isInfected()) { + Virus virus = patient.getVirus(); + if (virus != null) { + int variantId = virus.getVariantId(); + if (knownVirusVariant.contains(variantId)) { + patient.cure(); + } else { + // Si la variante n'est pas connue et pas en cours de recherche, l'ajouter à la recherche + if (!currentResearch.containsKey(variantId)) { + currentResearch.put(variantId, 0.0); + System.out.println("Nouvelle variante détectée! Variant ID: " + variantId + ". Recherche commencée."); + } + } + } + } + } + } + + @Override + public Position getPosition() { + return this.position; + } + + @Override + public void setPosition(Position p) { + this.position = p; + } + + @Override + public int getAge() { + return this.age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + + @Override + public void incrementAge() { + this.age += 1; + } + + @Override + public Color getViewColor() { + return this.viewColor; + } + + @Override + public int getPriority() { + return this.priority; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Doctor) { + Doctor other = (Doctor) obj; + return this.position.equals(other.getPosition()); + } else { + return false; + } + } + + @Override + public int hashCode() { + return Objects.hash(position); + } + +} diff --git a/src/main/java/model/doctorviruspatient/DoctorVirusPatientScenario.java b/src/main/java/model/doctorviruspatient/DoctorVirusPatientScenario.java new file mode 100644 index 0000000000000000000000000000000000000000..b22bf7352198b90989490ec5881bb85b3efe5d52 --- /dev/null +++ b/src/main/java/model/doctorviruspatient/DoctorVirusPatientScenario.java @@ -0,0 +1,55 @@ +package model.doctorviruspatient; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import model.Board; +import model.Entity; +import model.EntityFactory; +import model.Model; +import model.Scenario; +import model.Square; +import util.Position; + +public class DoctorVirusPatientScenario extends Scenario implements Model{ + public DoctorVirusPatientScenario(int columns, int rows, Map<EntityFactory, Integer> initialMap) { + super(columns, rows, initialMap); + } + + public List<Position> updateToNextGeneration() { + ArrayList<Position> changedPositions = new ArrayList<>(); + Iterator<Square> iterator = getMatrix().iterator(); + while (iterator.hasNext()) { + Square s = iterator.next(); + if (s.isEmpty()) + continue; + if (s.getMaxAge() == 0) { + s.incrementAllAges(); + continue; + } + if(s.getMaxAge()>stepNumber()+1){ + continue; + } + List<Entity> entities = new ArrayList<>(s.getEntities()); + for (Entity e : entities) { + e.incrementAge(); + changedPositions.addAll(e.nextTurn(this)); + } + } + + // Increment the step counter + this.step = this.step + 1; + return changedPositions; + } + + + + @Override + public Board<Square> getBoard() { + return this; + } + + +} diff --git a/src/main/java/model/doctorviruspatient/Patient.java b/src/main/java/model/doctorviruspatient/Patient.java new file mode 100644 index 0000000000000000000000000000000000000000..4db575421dced2d7678e497273242ae14793b812 --- /dev/null +++ b/src/main/java/model/doctorviruspatient/Patient.java @@ -0,0 +1,324 @@ +package model.doctorviruspatient; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Random; + +import javafx.scene.paint.Color; +import model.Board; +import model.Entity; +import model.Square; +import util.PathGenerator; +import util.Position; +import util.PositionUtil; + +public class Patient implements Entity { + private final int priority = 1; + private Position position; + private int age; + private final Color viewColor = Color.BLUE; + private Virus carriedVirus; + private List<Entity> visitedPatients; + private static int patientsCount = 0; + private int patientID; + private Position ennemy; + private boolean isAsymptomatic; + private boolean wandering; + + // Attributs pour le chemin + private List<Position> path; + private int pathIndex; + private static final int MAX_STEPS_IN_DIRECTION = 5; + private static final int MINIMUM_ROAD_LENGTH = 10; + + public Patient(Position p) { + this.wandering = true; + patientID = patientsCount; + patientsCount += 1; + this.visitedPatients = new ArrayList<>(); + this.position = p; + Random r = new Random(); + int randomNumber = r.nextInt(10); + this.isAsymptomatic = randomNumber == 1; + // Initialiser le chemin + this.path = new ArrayList<>(); + this.pathIndex = 0; + } + + public Patient(Position p, int age) { + this.wandering = true; + patientID = patientsCount; + patientsCount += 1; + this.visitedPatients = new ArrayList<>(); + this.position = p; + this.age = age; + Random r = new Random(); + int randomNumber = r.nextInt(10); + this.isAsymptomatic = randomNumber == 1; + // Initialiser le chemin + this.path = new ArrayList<>(); + this.pathIndex = 0; + } + + @Override + public List<Position> nextTurn(Board<Square> board) { + if (isInfected() && !isAsymptomatic) { + return moveToDoctor(board); + } + updateWanderingStatus(board); + + if (wandering) { + return performWandering(board); + } + + resetVisitedPatientsIfNecessary(); + + Position target = determineTarget(board); + + if (target == null) { + visitedPatients.clear(); + return List.of(); + } + + Position nextPos = determineNextPosition(target, board); + + if (nextPos != null && board.doesPositionExist(nextPos)) { + + List<Position> adjacentPositions = PositionUtil.generateAllAdjacentPositions(nextPos, board); + List<Position> result = interactWithAdjacentPositions(adjacentPositions, board); + result.addAll(moveToPosition(nextPos, board)); + result.addAll(adjacentPositions); + result.add(position); + return result; + } + + return List.of(); + } + + private void updateWanderingStatus(Board<Square> board) { + if (board.getStepNumber() % 8 == 0) { + wandering = false; + // Réinitialiser le chemin lorsque le patient arrête d'errer + this.path.clear(); + this.pathIndex = 0; + } + } + + private List<Position> moveToDoctor(Board<Square> board) { + for (Position p : PositionUtil.generateAllAdjacentPositions(position, board)) { + if (!board.doesPositionExist(p)) continue; + if (board.doesSquareContainEntity(p, Doctor.class)) return List.of(); + } + Position nearestDoctor = board.getNearestEntity(position, Doctor.class, null); + Position nextPos = PositionUtil.getNextPositionTowards(position, nearestDoctor, board); + if (nextPos == null) return List.of(); + + List<Position> changedPositions = new ArrayList<>(); + changedPositions.addAll(moveToPosition(nextPos, board)); + return changedPositions; + } + + private List<Position> performWandering(Board<Square> board) { + if (path == null || path.isEmpty() || pathIndex >= path.size()) { + generateNewPath(board); + if (path.isEmpty()) { + return List.of(); + } + } + + Position nextPosition = path.get(pathIndex); + + if (board.doesPositionExist(nextPosition) && board.isPositionFree(nextPosition, priority)) { + List<Position> changedPositions = moveSelfOnBoard(nextPosition, board); + pathIndex++; + return changedPositions; + } else { + // Si la position n'est pas libre ou n'existe pas, générer un nouveau chemin + generateNewPath(board); + return List.of(); + } + } + + private void generateNewPath(Board<Square> board) { + PathGenerator pathGenerator = new PathGenerator(board, position, MAX_STEPS_IN_DIRECTION, MINIMUM_ROAD_LENGTH); + this.path = pathGenerator.generate(); + // Supprimer la position actuelle du chemin si elle est présente + if (!path.isEmpty() && path.get(0).equals(position)) { + path.remove(0); + } + this.pathIndex = 0; + } + + private void resetVisitedPatientsIfNecessary() { + if (visitedPatients.size() - 1 >= patientsCount) { + visitedPatients.clear(); + } + } + + private Position determineTarget(Board<Square> board) { + return board.getNearestEntity(position, Patient.class, getVisitedPatients()); + } + + private Position determineNextPosition(Position target, Board<Square> board) { + int enemyDistance = PositionUtil.getManhattanDistance(target, position); + + if (ennemy != null && enemyDistance < 2) { + return PositionUtil.getNextPositionAwayFrom(position, target, board); + } else if (target != null) { + return PositionUtil.getNextPositionTowards(position, target, board); + } + return null; + } + + private List<Position> moveToPosition(Position nextPos, Board<Square> board) { + List<Position> changedPosition = new ArrayList<>(); + if (!board.isPositionFree(nextPos, priority)) { + nextPos = findAlternativePosition(nextPos, board); + } + + if (nextPos != null) { + changedPosition.addAll(moveSelfOnBoard(nextPos, board)); + } + + return changedPosition; + } + + private Position findAlternativePosition(Position currentPos, Board<Square> board) { + List<Position> adjacentPositions = PositionUtil.generateAdjacentPositions(position, board); + for (Position p : adjacentPositions) { + if (ennemy != null) { + Position awayPos = PositionUtil.getNextPositionAwayFrom(p, ennemy, board); + if (p.equals(awayPos)) { + continue; + } + } + if (board.isPositionFree(p, priority)) { + return p; + } + } + return null; + } + + private List<Position> moveSelfOnBoard(Position newPosition, Board<Square> board) { + if(!board.isPositionFree(newPosition, priority))return List.of(); + Position oldPosition = new Position(this.position.x(), this.position.y()); + board.clearCaseFrom(this, oldPosition); + board.addEntityAtSquare(this, newPosition); + this.position = newPosition; + return List.of(oldPosition, this.position); + } + + private List<Position> interactWithAdjacentPositions(List<Position> adjacentPositions, Board<Square> board) { + List<Position> result = new ArrayList<>(); + for (Position p : adjacentPositions) { + if (board.doesSquareContainEntity(p, Patient.class)) { + handleEncounterWithPatient(p, board); + if (isInfected()) { + result.addAll(adjacentPositions); + } + } + } + return result; + } + + private void handleEncounterWithPatient(Position p, Board<Square> board) { + this.wandering = true; + // Réinitialiser le chemin lorsqu'un patient est rencontré + this.path.clear(); + this.pathIndex = 0; + Patient patient = (Patient) board.getStates(p).getEntities().stream() + .filter(entity -> entity instanceof Patient) + .findFirst() + .orElse(null); + if (isInfected()) { + patient.infect(carriedVirus); + } + if (patient != null) { + this.ennemy = patient.getPosition(); + visitedPatients.add(patient); + } + } + + @Override + public Position getPosition() { + return this.position; + } + + @Override + public void setPosition(Position p) { + this.position = p; + } + + @Override + public int getAge() { + return this.age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + + @Override + public void incrementAge() { + this.age += 1; + } + + @Override + public Color getViewColor() { + return isInfected() ? Color.CYAN : this.viewColor; + } + + @Override + public int getPriority() { + return this.priority; + } + + public boolean isInfected() { + return this.carriedVirus != null; + } + + public void infect(Virus virus) { + if (this.carriedVirus != null) return; + this.carriedVirus = virus; + } + + public Virus getVirus() { + return this.carriedVirus; + } + + public List<Entity> getVisitedPatients() { + return this.visitedPatients; + } + + public boolean hasVisited(Patient patient) { + return this.getVisitedPatients().contains(patient); + } + + public int getPatientId() { + return this.patientID; + } + + public void cure() { + if (this.carriedVirus.tryToKill()) { + this.carriedVirus = null; + } + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Patient) { + Patient other = (Patient) obj; + return this.patientID == other.getPatientId(); + } else { + return false; + } + + } + + @Override + public int hashCode() { + return Objects.hash(patientID); + } +} diff --git a/src/main/java/model/doctorviruspatient/Virus.java b/src/main/java/model/doctorviruspatient/Virus.java new file mode 100644 index 0000000000000000000000000000000000000000..73bb433f50fdaf2d250da63418fd62104ecebbdb --- /dev/null +++ b/src/main/java/model/doctorviruspatient/Virus.java @@ -0,0 +1,149 @@ +package model.doctorviruspatient; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javafx.scene.paint.Color; +import model.Board; +import model.Entity; +import model.Square; +import util.PathGenerator; +import util.Position; +import util.PositionUtil; + +public class Virus implements Entity { + private final int priority = 2; + private Position position; + private int age; + private final Color viewColor = Color.LIMEGREEN; + private List<Position> path; + private int pathIndex; + private static final int MAX_STEPS_IN_DIRECTION = 5; + private static final int MINIMUM_ROAD_LENGTH = 10; + private int health; + private int variantId; + + public Virus(Position p) { + this.variantId = 0; + this.health = 50; + this.position = p; + this.path = new ArrayList<>(); + this.age = 0; + this.pathIndex = 0; + } + + public Virus(Position p, int age) { + this.health = 8; + this.position = p; + this.age = age; + this.path = new ArrayList<>(); + this.pathIndex = 0; + } + + @Override + public List<Position> nextTurn(Board<Square> board) { + if(board.getStepNumber() % 100 == 0){ + evolve(); + } + // Génère un nouveau chemin si nécessaire + if (path == null || path.isEmpty() || pathIndex >= path.size()) { + generateNewPath(board); + if (path.isEmpty()) { + return List.of(); + } + } + List<Position> adjacentPosition = PositionUtil.generateAllAdjacentPositions(position, board); + for(Position p : adjacentPosition){ + if(board.doesSquareContainEntity(p, Patient.class)){ + Patient patient = (Patient) board.getStates(p).getEntities().stream().filter(e -> e instanceof Patient).findFirst().get(); + patient.infect(this); + } + } + // Se déplace vers la prochaine position du chemin + Position nextPosition = path.get(pathIndex); + if (board.doesPositionExist(nextPosition)) { + // Vérifier si la position est libre + if (board.isPositionFree(nextPosition, priority)) { + Position oldPosition = position; + position = nextPosition; + board.clearCaseFrom(this, oldPosition); + board.addEntityAtSquare(this, position); + pathIndex = pathIndex + 1; + return List.of(oldPosition, position); + } else { + // Si la position n'est pas libre, génère un nouveau chemin + generateNewPath(board); + return List.of(); + } + } else { + // Si la prochaine position n'existe pas, génère un nouveau chemin + generateNewPath(board); + return List.of(); + } + } + + private void generateNewPath(Board<Square> board) { + PathGenerator pathGenerator = new PathGenerator(board, position, MAX_STEPS_IN_DIRECTION, MINIMUM_ROAD_LENGTH); + this.path = pathGenerator.generate(); + // Supprime la position actuelle du chemin si elle est présente au début + if (!path.isEmpty() && path.get(0).equals(position)) { + path.remove(0); + } + this.pathIndex = 0; // Réinitialise l'index du chemin + } + + // Les autres méthodes restent inchangées + private void evolve(){ + this.variantId++; + Random r = new Random(); + this.health = r.nextInt(100); + } + + public int getVariantId(){ + return this.variantId; + } + + @Override + public Position getPosition() { + return this.position; + } + + @Override + public void setPosition(Position p) { + this.position = p; + } + + @Override + public int getAge() { + return this.age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + + @Override + public void incrementAge() { + this.age += 1; + } + + @Override + public Color getViewColor() { + return this.viewColor; + } + + @Override + public int getPriority() { + return this.priority; + } + + public boolean tryToKill(){ + if(health <= 0){ + return true; + } + health--; + return false; + } +} diff --git a/src/main/java/model/firefighterscenario/FireFighter.java b/src/main/java/model/firefighterscenario/FireFighter.java index 4b20790a8db498e4612b0e1a859fae3b146769e8..8b8973f7f62f7da244e15b170609b84d73d8397c 100644 --- a/src/main/java/model/firefighterscenario/FireFighter.java +++ b/src/main/java/model/firefighterscenario/FireFighter.java @@ -116,7 +116,12 @@ public class FireFighter implements Entity { List<Position> positions = new ArrayList<>(); // Find the nearest fire - Position nearestFirePos = b.getNearestEntity(position, Fire.class); + Position nearestFirePos; + try { + nearestFirePos = b.getNearestEntity(position, Fire.class, null); + } catch (Exception e) { + return List.of(); + } if (nearestFirePos != null) { // Get the next position towards the fire Position nextPos = getNextPositionTowards(position, nearestFirePos, b); diff --git a/src/main/java/model/firefighterscenario/FireFighterScenario.java b/src/main/java/model/firefighterscenario/FireFighterScenario.java index 450dee5ff682cbbc09959634812baaab67019256..675d548bae13f56e45021b56c56862f7eadc3c94 100644 --- a/src/main/java/model/firefighterscenario/FireFighterScenario.java +++ b/src/main/java/model/firefighterscenario/FireFighterScenario.java @@ -6,90 +6,25 @@ 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(); + List<Entity> updatedEntities = new ArrayList<Entity>(); while (iterator.hasNext()) { Square s = iterator.next(); if (s.isEmpty()) @@ -103,10 +38,12 @@ public class FireFighterScenario extends EntityScenario implements Board<Square> } List<Entity> entities = new ArrayList<>(s.getEntities()); for (Entity e : entities) { + if(updatedEntities.contains(e))continue; if (e.getAge() >= stepNumber() - 1) { continue; } e.incrementAge(); + updatedEntities.add(e); changedPositions.addAll(e.nextTurn(this)); } } @@ -156,74 +93,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 +134,17 @@ public class FireFighterScenario extends EntityScenario implements Board<Square> } } + @Override + public Board<Square> getBoard() { + return this; + } + + public void reset() { + step = 0; + super.getMatrix().clear(); + initScenario(super.getMatrix()); + placeInitialEntities(initialMap); + generateRoads(); + } + } diff --git a/src/main/java/model/firefighterscenario/MotorizedFireFighter.java b/src/main/java/model/firefighterscenario/MotorizedFireFighter.java index 0fbab0ccf9cd7ee6cc12010e0837d152f5403bcf..ac2c24c5e690da642c92de5ba8beb0901ed82236 100644 --- a/src/main/java/model/firefighterscenario/MotorizedFireFighter.java +++ b/src/main/java/model/firefighterscenario/MotorizedFireFighter.java @@ -64,7 +64,12 @@ public class MotorizedFireFighter extends FireFighter { List<Position> positions = new ArrayList<>(); // Find the nearest fire - Position nearestFirePos = b.getNearestEntity(getPosition(), Fire.class); + Position nearestFirePos; + try { + nearestFirePos = b.getNearestEntity(getPosition(), Fire.class, null); + } catch (Exception e) { + return List.of(); + } if (nearestFirePos != null) { // Get the next position after moving up to two steps towards the fire Position nextPos = getNextPositionTowards(getPosition(), nearestFirePos, b, 2); diff --git a/src/main/java/model/rockpapercisor/Cisor.java b/src/main/java/model/rockpapercisor/Cisor.java new file mode 100644 index 0000000000000000000000000000000000000000..10566b83a405ab02f81b79343e278ef4539b3c5b --- /dev/null +++ b/src/main/java/model/rockpapercisor/Cisor.java @@ -0,0 +1,124 @@ +package model.rockpapercisor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import javafx.scene.paint.Color; +import model.Board; +import model.Entity; +import model.Square; +import util.Position; +import util.PositionUtil; + +public class Cisor implements Entity { + private final int priority = 0; + Position position; + private int age; + private final Color viewColor = Color.RED; + + public Cisor(Position p) { + this.position = p; + } + + public Cisor(Position p, int age) { + this.position = p; + this.age = age; + } + + @Override + public List<Position> nextTurn(Board<Square> board) { + Position target = null; + target = board.getNearestEntity(position, Paper.class, null); + + Position ennemy = null; + + ennemy = board.getNearestEntity(position, Rock.class, null); + if(ennemy == null && target == null){ + return List.of(); + } + Position nextPos = null; + // Vérifier la proximité d'un ennemi avant de choisir la direction. + if (ennemy != null && PositionUtil.getManhattanDistance(position, ennemy) < 5) { + nextPos = PositionUtil.getNextPositionAwayFrom(position, ennemy, board); + } else if(target != null){ + nextPos = PositionUtil.getNextPositionTowards(position, target, board); + } + + if (nextPos != null && board.doesPositionExist(nextPos)) { + board.addEntityAtSquare(this, nextPos); + board.clearCaseFrom(this, position); + Position oldPosition = new Position(position.x(), position.y()); + this.position = nextPos; + if (board.doesSquareContainEntity(nextPos, Paper.class)) { + List<Entity> entities = board.getStates(nextPos).getEntities(); + entities.removeIf(p -> p instanceof Paper); + } + + List<Position> result = new ArrayList<>(); + if (target != null) + result.add(target); + if (oldPosition != null) + result.add(oldPosition); + if (position != null) + result.add(position); + if (ennemy != null) + result.add(ennemy); + return result; + + } + return List.of(); + } + + @Override + public Position getPosition() { + return this.position; + } + + @Override + public void setPosition(Position p) { + this.position = p; + + } + + @Override + public int getAge() { + return this.age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + + @Override + public void incrementAge() { + this.age += 1; + } + + @Override + public Color getViewColor() { + return this.viewColor; + } + + @Override + public int getPriority() { + return this.priority; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + Cisor cisor = (Cisor) obj; + return age == cisor.age && + Objects.equals(position, cisor.position); + } + + @Override + public int hashCode() { + return Objects.hash(position, age); + } +} diff --git a/src/main/java/model/rockpapercisor/Paper.java b/src/main/java/model/rockpapercisor/Paper.java new file mode 100644 index 0000000000000000000000000000000000000000..1c9117caa03204ea4659d9d367e4c5f0cc8b1da5 --- /dev/null +++ b/src/main/java/model/rockpapercisor/Paper.java @@ -0,0 +1,106 @@ +package model.rockpapercisor; + +import java.util.ArrayList; +import java.util.List; + +import javafx.scene.paint.Color; +import model.Board; +import model.Entity; +import model.Square; +import util.Position; +import util.PositionUtil; + +public class Paper implements Entity { + private final int priority = 0; + Position position; + private int age; + private final Color viewColor = Color.GRAY; + + public Paper(Position p) { + this.position = p; + } + + public Paper(Position p, int age) { + this.position = p; + this.age = age; + } + + @Override + public List<Position> nextTurn(Board<Square> board) { + Position target = null; + target = board.getNearestEntity(position, Rock.class, null); + + Position ennemy = null; + ennemy = board.getNearestEntity(position, Cisor.class, null); + if(ennemy == null && target == null){ + return List.of(); + } + Position nextPos = null; + // Vérifier la proximité d'un ennemi avant de choisir la direction. + if (ennemy != null && PositionUtil.getManhattanDistance(position, ennemy) < 5) { + nextPos = PositionUtil.getNextPositionAwayFrom(position, ennemy, board); + } else if(target != null){ + nextPos = PositionUtil.getNextPositionTowards(position, target, board); + } + + if (nextPos != null && board.doesPositionExist(nextPos)) { + board.addEntityAtSquare(this, nextPos); + board.clearCaseFrom(this, position); + Position oldPosition = new Position(position.x(), position.y()); + this.position = nextPos; + if (board.doesSquareContainEntity(nextPos, Rock.class)) { + List<Entity> entities = board.getStates(nextPos).getEntities(); + entities.removeIf(p -> p instanceof Rock); + } + + List<Position> result = new ArrayList<>(); + if (target != null) + result.add(target); + if (oldPosition != null) + result.add(oldPosition); + if (position != null) + result.add(position); + if (ennemy != null) + result.add(ennemy); + return result; + + } + return List.of(); + } + + @Override + public Position getPosition() { + return this.position; + } + + @Override + public void setPosition(Position p) { + this.position = p; + + } + + @Override + public int getAge() { + return this.age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + + @Override + public void incrementAge() { + this.age += 1; + } + + @Override + public Color getViewColor() { + return this.viewColor; + } + + @Override + public int getPriority() { + return this.priority; + } +} diff --git a/src/main/java/model/rockpapercisor/Rock.java b/src/main/java/model/rockpapercisor/Rock.java new file mode 100644 index 0000000000000000000000000000000000000000..1671a13eb4968187201b905a6e2648614e9b0b24 --- /dev/null +++ b/src/main/java/model/rockpapercisor/Rock.java @@ -0,0 +1,107 @@ +package model.rockpapercisor; + +import java.util.ArrayList; +import java.util.List; + +import javafx.scene.paint.Color; +import model.Board; +import model.Entity; +import model.Square; +import util.Position; +import util.PositionUtil; + +public class Rock implements Entity { + private final int priority = 0; + Position position; + private int age; + private final Color viewColor = Color.CHOCOLATE; + + public Rock(Position p) { + this.position = p; + } + + public Rock(Position p, int age) { + this.position = p; + this.age = age; + } + + @Override + public List<Position> nextTurn(Board<Square> board) { + Position target = null; + target = board.getNearestEntity(position, Cisor.class, null); + + Position ennemy = null; + ennemy = board.getNearestEntity(position, Paper.class, null); + + if(ennemy == null && target == null){ + return List.of(); + } + Position nextPos = null; + // Vérifier la proximité d'un ennemi avant de choisir la direction. + if (ennemy != null && PositionUtil.getManhattanDistance(position, ennemy) < 5) { + nextPos = PositionUtil.getNextPositionAwayFrom(position, ennemy, board); + } else if(target != null){ + nextPos = PositionUtil.getNextPositionTowards(position, target, board); + } + + if (nextPos != null && board.doesPositionExist(nextPos)) { + board.addEntityAtSquare(this, nextPos); + board.clearCaseFrom(this, position); + Position oldPosition = new Position(position.x(), position.y()); + this.position = nextPos; + if (board.doesSquareContainEntity(nextPos, Cisor.class)) { + List<Entity> entities = board.getStates(nextPos).getEntities(); + entities.removeIf(p -> p instanceof Cisor); + } + + List<Position> result = new ArrayList<>(); + if (target != null) + result.add(target); + if (oldPosition != null) + result.add(oldPosition); + if (position != null) + result.add(position); + if (ennemy != null) + result.add(ennemy); + return result; + + } + return List.of(); + } + + @Override + public Position getPosition() { + return this.position; + } + + @Override + public void setPosition(Position p) { + this.position = p; + + } + + @Override + public int getAge() { + return this.age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + + @Override + public void incrementAge() { + this.age += 1; + } + + @Override + public Color getViewColor() { + return this.viewColor; + } + + @Override + public int getPriority() { + return this.priority; + } +} diff --git a/src/main/java/model/rockpapercisor/RockPaperCisorScenario.java b/src/main/java/model/rockpapercisor/RockPaperCisorScenario.java new file mode 100644 index 0000000000000000000000000000000000000000..c6808fbe5ce58fc660df3e4b324aa2df7af80b57 --- /dev/null +++ b/src/main/java/model/rockpapercisor/RockPaperCisorScenario.java @@ -0,0 +1,51 @@ +package model.rockpapercisor; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import model.Board; +import model.Entity; +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() { + ArrayList<Position> changedPositions = new ArrayList<>(); + Iterator<Square> iterator = getMatrix().iterator(); + while (iterator.hasNext()) { + Square s = iterator.next(); + if (s.isEmpty()) + continue; + if (s.getMaxAge() == 0) { + s.incrementAllAges(); + continue; + } + if(s.getMaxAge()>stepNumber()+1){ + continue; + } + List<Entity> entities = new ArrayList<>(s.getEntities()); + for (Entity e : entities) { + e.incrementAge(); + changedPositions.addAll(e.nextTurn(this)); + } + } + + // Increment the step counter + this.step = this.step + 1; + return changedPositions; + } + + @Override + public Board<Square> getBoard() { + return this; + } +} diff --git a/src/main/java/util/Matrix.java b/src/main/java/util/Matrix.java index 36a06da1550e9d89446c4f936d695a8bdab698fe..5ed290f0c31f3134d241fb49e3d716fb3bd0f874 100644 --- a/src/main/java/util/Matrix.java +++ b/src/main/java/util/Matrix.java @@ -6,6 +6,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; import model.Square; +import model.doctorviruspatient.Patient; import model.firefighterscenario.Fire; import model.firefighterscenario.FireFighter; @@ -83,8 +84,11 @@ public class Matrix<E> implements Iterable<E> { else if(s.getEntities().stream().anyMatch(p -> p instanceof FireFighter)){ System.out.print(" ff | "); } - else if(s.getEntities().stream().anyMatch(p -> p instanceof FireFighter)){ - System.out.print(" A | "); + else if(s.getEntities().stream().anyMatch(p -> p instanceof Patient)){ + System.out.print(" P | "); + } + else if(s.getEntities().stream().anyMatch(p -> p instanceof model.doctorviruspatient.Virus)){ + System.out.print(" V | "); }else{ System.out.print(" | "); } diff --git a/src/main/java/util/PathGenerator.java b/src/main/java/util/PathGenerator.java index 149c4ca1633a286e84915cf3c75c7405607470da..148116237eb0cc1ac4c04c91d23be3b5cb836543 100644 --- a/src/main/java/util/PathGenerator.java +++ b/src/main/java/util/PathGenerator.java @@ -10,7 +10,7 @@ import java.util.Set; import model.Board; public class PathGenerator { - private final Board<?> board; + private Board<?> board; private final Random random = new Random(); private final int maxStepsInDirection; private final int minimumRoadLength; @@ -59,7 +59,9 @@ public class PathGenerator { } return roadLength >= minimumRoadLength ? path : regeneratePath(); } - + public void setBoard(Board<?> board){ + this.board = board; + } /** Initialise le chemin avec l'ancre et choisit la première direction. */ private void initializePath() { path.clear(); diff --git a/src/main/java/util/PositionUtil.java b/src/main/java/util/PositionUtil.java index 0a3f9011468dbeb11e6b8b2f4fb3549f0f083328..096c290d4560c1edbf0d73da67370422515e64da 100644 --- a/src/main/java/util/PositionUtil.java +++ b/src/main/java/util/PositionUtil.java @@ -2,11 +2,14 @@ package util; import java.util.ArrayList; import java.util.List; +import java.util.Random; import java.util.stream.Collectors; import java.util.stream.Stream; import model.Board; import model.Square; +import model.firefighterscenario.FireFighter; +import model.firefighterscenario.Mountain; public class PositionUtil { /** @@ -153,4 +156,169 @@ public class PositionUtil { return positions; } + + public static Position getNextPositionTowards(Position currentPos, Position targetPos, Board<Square> b) { + // Generate adjacent positions + List<Position> possibleMoves = PositionUtil.generateAllAdjacentPositions(currentPos, b); + + // Filter out positions that are not empty or contain obstacles + possibleMoves.removeIf(p -> b.doesSquareContainEntity(p, Mountain.class)); + + // If no possible moves, return null + if (possibleMoves.isEmpty()) { + return null; + } + + // Calculate the current distance to the target + int currentDistance = PositionUtil.getManhattanDistance(currentPos, targetPos); + + // Initialize variables to find the best moves + int minDistance = Integer.MAX_VALUE; + List<Position> bestMoves = new ArrayList<>(); + + for (Position move : possibleMoves) { + int distance = PositionUtil.getManhattanDistance(move, targetPos); + + // Skip positions occupied by other firefighters + if (b.doesSquareContainEntity(move, FireFighter.class)) { + continue; + } + + // Find positions that minimize the distance + if (distance < minDistance) { + minDistance = distance; + bestMoves.clear(); + bestMoves.add(move); + } else if (distance == minDistance) { + bestMoves.add(move); + } + } + + // If no better move is found, consider moves that maintain the same distance + if (bestMoves.isEmpty()) { + minDistance = currentDistance; + for (Position move : possibleMoves) { + int distance = PositionUtil.getManhattanDistance(move, targetPos); + if (distance == minDistance) { + bestMoves.add(move); + } + } + } + + // If still no move is found, stay in the current position + if (bestMoves.isEmpty()) { + return currentPos; + } + + // Select a move from the best moves (e.g., randomly or based on additional criteria) + Random r = new Random(); + + Position nextMove = bestMoves.get(r.nextInt(bestMoves.size())); + + return nextMove; + } + + public static Position getNextPositionAwayFrom(Position currentPos, Position targetPos, Board<Square> b) { + // Générer les positions adjacentes + List<Position> possibleMoves = PositionUtil.generateAllAdjacentPositions(currentPos, b); + + // Filtrer les positions qui ne sont pas vides ou contiennent des obstacles + possibleMoves.removeIf(p -> b.doesSquareContainEntity(p, Mountain.class)); + + // Si aucune possibilité de déplacement, retourner null + if (possibleMoves.isEmpty()) { + return null; + } + + // Calculer la distance actuelle par rapport à la cible + int currentDistance = PositionUtil.getManhattanDistance(currentPos, targetPos); + + // Initialiser les variables pour trouver les meilleurs déplacements + int maxDistance = Integer.MIN_VALUE; + List<Position> bestMoves = new ArrayList<>(); + + for (Position move : possibleMoves) { + int distance = PositionUtil.getManhattanDistance(move, targetPos); + + // Ignorer les positions occupées par d'autres entités, comme les pompiers + if (b.doesSquareContainEntity(move, FireFighter.class)) { + continue; + } + + // Trouver les positions qui maximisent la distance + if (distance > maxDistance) { + maxDistance = distance; + bestMoves.clear(); + bestMoves.add(move); + } else if (distance == maxDistance) { + bestMoves.add(move); + } + } + + // Si aucun meilleur déplacement n'est trouvé, considérer les mouvements qui maintiennent la même distance + if (bestMoves.isEmpty()) { + maxDistance = currentDistance; + for (Position move : possibleMoves) { + int distance = PositionUtil.getManhattanDistance(move, targetPos); + if (distance == maxDistance) { + bestMoves.add(move); + } + } + } + + // Si toujours aucun mouvement n'est trouvé, rester à la position actuelle + if (bestMoves.isEmpty()) { + return currentPos; + } + + // Sélectionner un mouvement parmi les meilleurs mouvements (par exemple aléatoirement ou selon des critères supplémentaires) + Random r = new Random(); + + Position nextMove = bestMoves.get(r.nextInt(bestMoves.size())); + + return nextMove; + } + public static Direction getOppositeDirection(Direction direction) { + switch (direction) { + case NORTH: return Direction.SOUTH; + case SOUTH: return Direction.NORTH; + case EAST: return Direction.WEST; + case WEST: return Direction.EAST; + default: throw new IllegalArgumentException("Direction non supportée : " + direction); + } + } + + /** + * Détermine la direction principale (NORTH, SOUTH, EAST, WEST) de toPos par rapport à fromPos. + * + * @param fromPos la position de départ. + * @param toPos la position de destination. + * @return la direction principale de toPos par rapport à fromPos. + */ +public static Direction getDirectionFromTwoPoints(Position fromPos, Position toPos) { + int deltaX = toPos.x() - fromPos.x(); + int deltaY = toPos.y() - fromPos.y(); + + if (deltaX == 0 && deltaY == 0) { + return null; // Les positions sont identiques + } + + if (Math.abs(deltaX) > Math.abs(deltaY)) { + // Mouvement principalement vers l'Est ou l'Ouest + if (deltaX > 0) { + return Direction.EAST; + } else { + return Direction.WEST; + } + } else { + // Mouvement principalement vers le Nord ou le Sud + if (deltaY > 0) { + return Direction.SOUTH; + } else { + return Direction.NORTH; + } + } +} + + } \ No newline at end of file