From 4be08dcb6a7623041b0598d4ce836d2e34c96962 Mon Sep 17 00:00:00 2001 From: Yanis O <oualanyanis01@gmail.com> Date: Wed, 27 Nov 2024 13:13:18 +0100 Subject: [PATCH] =?UTF-8?q?Ajout=20du=20sc=C3=A9nario=20Docteur=20Virus=20?= =?UTF-8?q?Patient,=20et=20d=C3=A9but=20impl=C3=A9mentation=20de=20la=20lo?= =?UTF-8?q?gique=20des=20Patients?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scenariovirus.txt | 15 ++ src/main/java/controller/Controller.java | 15 +- src/main/java/model/Board.java | 3 +- src/main/java/model/EntitySpawner.java | 17 +- src/main/java/model/Scenario.java | 15 +- .../DoctorVirusPatientScenario.java | 55 ++++ .../model/doctorviruspatient/Patient.java | 254 ++++++++++++++++++ .../java/model/doctorviruspatient/Virus.java | 69 +++++ .../firefighterscenario/FireFighter.java | 2 +- .../MotorizedFireFighter.java | 2 +- src/main/java/model/rockpapercisor/Cisor.java | 13 +- src/main/java/model/rockpapercisor/Paper.java | 12 +- src/main/java/model/rockpapercisor/Rock.java | 13 +- src/main/java/util/PositionUtil.java | 43 ++- 14 files changed, 468 insertions(+), 60 deletions(-) create mode 100644 scenariovirus.txt create mode 100644 src/main/java/model/doctorviruspatient/DoctorVirusPatientScenario.java create mode 100644 src/main/java/model/doctorviruspatient/Patient.java create mode 100644 src/main/java/model/doctorviruspatient/Virus.java diff --git a/scenariovirus.txt b/scenariovirus.txt new file mode 100644 index 0000000..d43e533 --- /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/controller/Controller.java b/src/main/java/controller/Controller.java index 7ebb8ba..7ad1c20 100644 --- a/src/main/java/controller/Controller.java +++ b/src/main/java/controller/Controller.java @@ -23,10 +23,9 @@ import model.Board; import model.EntityFactory; import model.Model; import model.Square; -import model.rockpapercisor.Cisor; -import model.rockpapercisor.Paper; -import model.rockpapercisor.Rock; -import model.rockpapercisor.RockPaperCisorScenario; +import model.doctorviruspatient.DoctorVirusPatientScenario; +import model.doctorviruspatient.Patient; +import model.virus.Virus; import util.Position; import view.Grid; import view.ViewElement; @@ -138,14 +137,18 @@ public class Controller { entityCounts.put((pos, b) -> new Mountain(pos), initialmountaincount); entityCounts.put((pos, b) -> new Rockery(pos), 3); */ + /* entityCounts.put((pos, b) -> new Rock(pos), 10); entityCounts.put((pos, b) -> new Cisor(pos), 10); entityCounts.put((pos, b) -> new Paper(pos), 10); - Model model = new RockPaperCisorScenario(columnCount, rowCount, entityCounts); + */ + entityCounts.put((pos, b) -> new Patient(pos), 10); + entityCounts.put((pos, b) -> new Virus(pos), 1); + 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 be1fcb8..6fc78dd 100644 --- a/src/main/java/model/Board.java +++ b/src/main/java/model/Board.java @@ -1,5 +1,6 @@ package model; +import java.util.List; import java.util.Map; import util.Position; @@ -63,7 +64,7 @@ public interface Board<S> { public void clearCaseFrom(Entity entity, Position position); - public Position getNearestEntity(Position fromPos, Class<?> entityType) throws EntityNotFoundException; + public Position getNearestEntity(Position fromPos, Class<?> entityType, List<Entity> exclusionList); public boolean doesSquareContainEntity(Position squarePos, Class<?> entityType); diff --git a/src/main/java/model/EntitySpawner.java b/src/main/java/model/EntitySpawner.java index c8f0de6..bd6fa6e 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/Scenario.java b/src/main/java/model/Scenario.java index 6f04bbc..e58abb8 100644 --- a/src/main/java/model/Scenario.java +++ b/src/main/java/model/Scenario.java @@ -88,29 +88,28 @@ public class Scenario implements Board<Square>{ matrix.get(position.x(), position.y()).getEntities().removeIf(element -> element.equals(entity)); } - public Position getNearestEntity(Position fromPos, Class<?> entityType) throws EntityNotFoundException { + public Position getNearestEntity(Position fromPos, Class<?> entityType, List<Entity> exclusionList) { int rows = matrix.getRows(); int cols = matrix.getColumns(); - // 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)) { - // Dès qu'une entité est trouvée à cette distance, elle est la plus proche possible + 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; } } } } - - // Lever une exception si aucune entité n'est trouvée - throw new EntityNotFoundException("Aucune entité de type " + entityType.getSimpleName() + " trouvée à proximité de " + fromPos); + return null; // Retourne null si aucune entité éligible n'est trouvée } diff --git a/src/main/java/model/doctorviruspatient/DoctorVirusPatientScenario.java b/src/main/java/model/doctorviruspatient/DoctorVirusPatientScenario.java new file mode 100644 index 0000000..b22bf73 --- /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 0000000..0d17595 --- /dev/null +++ b/src/main/java/model/doctorviruspatient/Patient.java @@ -0,0 +1,254 @@ +package model.doctorviruspatient; + +import java.util.ArrayList; +import java.util.Collections; +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 Patient implements Entity { + private final int priority = 0; + Position position; + private int age; + private final Color viewColor = Color.BLUE; + private Virus carriedVirus; + List<Entity> visitedPatients; + private static int patientsCount = 0; + private int patientID; + private Position ennemy; + private boolean wandering; + + public Patient(Position p) { + this.wandering = true; + patientID = patientsCount; + patientsCount += 1; + this.visitedPatients = new ArrayList<Entity>(); + this.position = p; + } + + public Patient(Position p, int age) { + this.wandering = true; + patientID = patientsCount; + patientsCount += 1; + this.visitedPatients = new ArrayList<Entity>(); + this.position = p; + this.age = age; + } + + @Override + public List<Position> nextTurn(Board<Square> 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; + } +} + +private List<Position> performWandering(Board<Square> board) { + List<Position> adjacentPositions = PositionUtil.generateAdjacentPositions(position, board); + Collections.shuffle(adjacentPositions); + + Position oldPosition = position; + Position newPosition = adjacentPositions.get(0); + + moveEntityOnBoard(oldPosition, newPosition, board); + return List.of(newPosition, oldPosition); +} + +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) { + if (!board.isPositionFree(nextPos, priority)) { + nextPos = findAlternativePosition(nextPos, board); + } + + if (nextPos != null) { + Position oldPosition = position; + moveEntityOnBoard(oldPosition, nextPos, board); + } + + return List.of(new Position(this.position.x(), this.position.y()), nextPos); +} + +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)) { + // Si la position reste la même après avoir tenté de s'éloigner, on continue + continue; + } + } + if (board.isPositionFree(p, priority)) { + return p; + } + } + return null; +} + + +private void moveEntityOnBoard(Position oldPosition, Position newPosition, Board<Square> board) { + board.clearCaseFrom(this, oldPosition); + board.addEntityAtSquare(this, newPosition); + this.position = newPosition; +} + +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; + Patient patient = (Patient) board.getStates(p).getEntities().stream() + .filter(entity -> entity instanceof Patient) + .findFirst() + .orElse(null); + + 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 this.viewColor; + } + + @Override + public int getPriority() { + return this.priority; + } + + public boolean isInfected(){ + return this.carriedVirus != null; + } + + public void infect(Virus virus){ + 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; + } + + @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 0000000..8ea8b6b --- /dev/null +++ b/src/main/java/model/doctorviruspatient/Virus.java @@ -0,0 +1,69 @@ +package model.doctorviruspatient; + +import java.util.ArrayList; +import java.util.List; + +import javafx.scene.paint.Color; +import model.Board; +import model.Entity; +import model.Square; +import model.rockpapercisor.Rock; +import util.Position; +import util.PositionUtil; + +public class Virus implements Entity { + private final int priority = 0; + Position position; + private int age; + private final Color viewColor = Color.LIMEGREEN; + + public Virus(Position p) { + this.position = p; + } + + public Virus(Position p, int age) { + this.position = p; + this.age = age; + } + + @Override + public List<Position> nextTurn(Board<Square> board) { + + } + + @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/firefighterscenario/FireFighter.java b/src/main/java/model/firefighterscenario/FireFighter.java index 8238c6e..37e658f 100644 --- a/src/main/java/model/firefighterscenario/FireFighter.java +++ b/src/main/java/model/firefighterscenario/FireFighter.java @@ -109,7 +109,7 @@ public class FireFighter implements Entity { // Find the nearest fire Position nearestFirePos; try { - nearestFirePos = b.getNearestEntity(position, Fire.class); + nearestFirePos = b.getNearestEntity(position, Fire.class, null); } catch (Exception e) { return List.of(); } diff --git a/src/main/java/model/firefighterscenario/MotorizedFireFighter.java b/src/main/java/model/firefighterscenario/MotorizedFireFighter.java index 7487e31..b870768 100644 --- a/src/main/java/model/firefighterscenario/MotorizedFireFighter.java +++ b/src/main/java/model/firefighterscenario/MotorizedFireFighter.java @@ -56,7 +56,7 @@ public class MotorizedFireFighter extends FireFighter { // Find the nearest fire Position nearestFirePos; try { - nearestFirePos = b.getNearestEntity(getPosition(), Fire.class); + nearestFirePos = b.getNearestEntity(getPosition(), Fire.class, null); } catch (Exception e) { return List.of(); } diff --git a/src/main/java/model/rockpapercisor/Cisor.java b/src/main/java/model/rockpapercisor/Cisor.java index efbcfa7..10566b8 100644 --- a/src/main/java/model/rockpapercisor/Cisor.java +++ b/src/main/java/model/rockpapercisor/Cisor.java @@ -29,18 +29,11 @@ public class Cisor implements Entity { @Override public List<Position> nextTurn(Board<Square> board) { Position target = null; - try { - target = board.getNearestEntity(position, Paper.class); - } catch (Exception e) { - - } + target = board.getNearestEntity(position, Paper.class, null); Position ennemy = null; - try { - ennemy = board.getNearestEntity(position, Rock.class); - } catch (Exception ignored) { - // Si aucune entité Rock n'est trouvée, ennemy reste null. - } + + ennemy = board.getNearestEntity(position, Rock.class, null); if(ennemy == null && target == null){ return List.of(); } diff --git a/src/main/java/model/rockpapercisor/Paper.java b/src/main/java/model/rockpapercisor/Paper.java index 2d28a91..1c9117c 100644 --- a/src/main/java/model/rockpapercisor/Paper.java +++ b/src/main/java/model/rockpapercisor/Paper.java @@ -28,18 +28,10 @@ public class Paper implements Entity { @Override public List<Position> nextTurn(Board<Square> board) { Position target = null; - try { - target = board.getNearestEntity(position, Rock.class); - } catch (Exception e) { - - } + target = board.getNearestEntity(position, Rock.class, null); Position ennemy = null; - try { - ennemy = board.getNearestEntity(position, Cisor.class); - } catch (Exception ignored) { - // Si aucune entité Cisor n'est trouvée, ennemy reste null. - } + ennemy = board.getNearestEntity(position, Cisor.class, null); if(ennemy == null && target == null){ return List.of(); } diff --git a/src/main/java/model/rockpapercisor/Rock.java b/src/main/java/model/rockpapercisor/Rock.java index 57a0d3e..1671a13 100644 --- a/src/main/java/model/rockpapercisor/Rock.java +++ b/src/main/java/model/rockpapercisor/Rock.java @@ -28,18 +28,11 @@ public class Rock implements Entity { @Override public List<Position> nextTurn(Board<Square> board) { Position target = null; - try { - target = board.getNearestEntity(position, Cisor.class); - } catch (Exception e) { - - } + target = board.getNearestEntity(position, Cisor.class, null); Position ennemy = null; - try { - ennemy = board.getNearestEntity(position, Paper.class); - } catch (Exception ignored) { - // Si aucune entité Paper n'est trouvée, ennemy reste null. - } + ennemy = board.getNearestEntity(position, Paper.class, null); + if(ennemy == null && target == null){ return List.of(); } diff --git a/src/main/java/util/PositionUtil.java b/src/main/java/util/PositionUtil.java index 39a8910..096c290 100644 --- a/src/main/java/util/PositionUtil.java +++ b/src/main/java/util/PositionUtil.java @@ -278,6 +278,47 @@ public class PositionUtil { 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 -- GitLab