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