Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
  • melissa
  • yanis
  • variant
4 results

Target

Select target project
No results found
Select Git revision
  • main
  • variant
2 results
Show changes

Commits on Source 29

26 files
+ 903
346
Compare changes
  • Side-by-side
  • Inline

Files

+8 −0
Original line number Diff line number Diff line
@@ -32,3 +32,11 @@ fabric.properties
.idea/caches/build_file_checksums.ser


.gradle/
*.class
bin/
.gradle
*.bin
*.lock
.gradle/8.10.2/executionHistory/executionHistory.bin
build/
 No newline at end of file
+142 −0
Original line number Diff line number Diff line
.background {
    -fx-background-color: #1d1d1d;
}

.label {
    -fx-font-size: 11pt;
    -fx-font-family: "Segoe UI Semibold";
    -fx-text-fill: white;
    -fx-opacity: 0.6;
}

.label-bright {
    -fx-font-size: 11pt;
    -fx-font-family: "Segoe UI Semibold";
    -fx-text-fill: white;
    -fx-opacity: 1;
}

.label-header {
    -fx-font-size: 32pt;
    -fx-font-family: "Segoe UI Light";
    -fx-text-fill: white;
    -fx-opacity: 1;
}

.table-view {
    -fx-base: #1d1d1d;
    -fx-control-inner-background: #1d1d1d;
    -fx-background-color: #1d1d1d;
    -fx-table-cell-border-color: transparent;
    -fx-table-header-border-color: transparent;
    -fx-padding: 5;
}

.table-view .column-header-background {
    -fx-background-color: transparent;
}

.table-view .column-header, .table-view .filler {
    -fx-border-width: 0 0 1 0;
    -fx-background-color: transparent;
    -fx-border-color: 
        transparent
        transparent
        derive(-fx-base, 80%) 
        transparent;
    -fx-border-insets: 0 10 1 0;
}

.table-view .column-header .label {
    -fx-font-size: 20pt;
    -fx-font-family: "Segoe UI Light";
    -fx-text-fill: white;
    -fx-alignment: center-left;
    -fx-opacity: 1;
}

.table-view:focused .table-row-cell:filled:focused:selected {
    -fx-background-color: -fx-focus-color;
}

.split-pane:horizontal > .split-pane-divider {
    -fx-border-color: transparent #1d1d1d transparent #1d1d1d;
    -fx-background-color: transparent, derive(#1d1d1d,20%);
}

.split-pane {
    -fx-padding: 1 0 0 0;
}

.menu-bar {
    -fx-background-color: derive(#1d1d1d,20%);
}

.context-menu {
    -fx-background-color: derive(#1d1d1d,50%);
}

.menu-bar .label {
    -fx-font-size: 14pt;
    -fx-font-family: "Segoe UI Light";
    -fx-text-fill: white;
    -fx-opacity: 0.9;
}

.menu .left-container {
    -fx-background-color: black;
}

.text-field {
    -fx-font-size: 12pt;
    -fx-font-family: "Segoe UI Semibold";
}

/* 
 * Metro style Push Button
 * Author: Pedro Duque Vieira
 * http://pixelduke.wordpress.com/2012/10/23/jmetro-windows-8-controls-on-java/
 */
.button {
    -fx-padding: 5 22 5 22;   
    -fx-border-color: #e2e2e2;
    -fx-border-width: 2;
    -fx-background-radius: 0;
    -fx-background-color: #1d1d1d;
    -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif;
    -fx-font-size: 11pt;
    -fx-text-fill: #d8d8d8;
    -fx-background-insets: 0 0 0 0, 0, 1, 2;
}

.button:hover {
    -fx-background-color: #3a3a3a;
}

.button:pressed, .button:default:hover:pressed {
  -fx-background-color: white;
  -fx-text-fill: #1d1d1d;
}

.button:focused {
    -fx-border-color: white, white;
    -fx-border-width: 1, 1;
    -fx-border-style: solid;
    -fx-border-radius: 0, 0;
    -fx-border-insets: 1 1 1 1, 0;
}

.button:disabled, .button:default:disabled {
    -fx-opacity: 0.4;
    -fx-background-color: #1d1d1d;
    -fx-text-fill: white;
}

.button:default {
    -fx-background-color: -fx-focus-color;
    -fx-text-fill: #ffffff;
}

.button:default:hover {
    -fx-background-color: derive(-fx-focus-color,30%);
}
 No newline at end of file
+46 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import view.FirefighterGrid?>

<HBox styleClass="background" stylesheets="@DarkTheme.css"
      xmlns="http://javafx.com/javafx"
      xmlns:fx="http://javafx.com/fxml"
      fx:controller="controller.Controller">
  <VBox>
    <Separator maxHeight="-Infinity" maxWidth="-Infinity"
               prefHeight="24.0" prefWidth="200.0" />
    <Label maxHeight="-Infinity" maxWidth="-Infinity"
           alignment="CENTER" prefHeight="24.0" prefWidth="200.0"
           text="Generation number" />
    <Label fx:id="generationNumberLabel"
           alignment="CENTER" contentDisplay="TEXT_ONLY"
           maxHeight="-Infinity" maxWidth="-Infinity"
           prefHeight="24.0" prefWidth="200.0" />
    <Separator maxHeight="-Infinity" maxWidth="-Infinity"
               prefHeight="24.0" prefWidth="200.0" />
    <Button fx:id="restartButton" maxHeight="-Infinity" maxWidth="-Infinity"
            mnemonicParsing="false" onAction="#restartButtonAction"
            prefHeight="24.0" prefWidth="200.0" text="Restart" />
    <Button fx:id="oneStepButton" maxHeight="-Infinity" maxWidth="-Infinity"
            mnemonicParsing="false" onAction="#oneStepButtonAction"
            prefHeight="24.0" prefWidth="200.0" text="One step" />
    <ToggleButton fx:id="playToggleButton" maxHeight="-Infinity" maxWidth="-Infinity"
                  mnemonicParsing="false" onAction="#playToggleButtonAction"
                  prefHeight="24.0" prefWidth="200.0"
                  styleClass="button" text="Play" />
    <ToggleButton fx:id="pauseToggleButton" maxHeight="-Infinity" maxWidth="-Infinity"
                  mnemonicParsing="false" onAction="#pauseToggleButtonAction"
                  prefHeight="24.0" prefWidth="200.0"
                  styleClass="button" text="Pause" />
  </VBox>
  <FirefighterGrid fx:id="grid"
                   xmlns="http://javafx.com/javafx"
                   xmlns:fx="http://javafx.com/fxml">
  </FirefighterGrid>
</HBox>

gradlew

100755 → 100644
+0 −0

File mode changed from 100755 to 100644.

+89 −89

File changed.

Contains only whitespace changes.

Original line number Diff line number Diff line
package app;

import java.io.IOException;
import java.net.URL;

import controller.Controller;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
@@ -7,16 +10,13 @@ import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;
import java.net.URL;

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 = 20;
  private static final int COLUMN_COUNT = 20;
  private static final int BOX_WIDTH = 50;
  private static final int BOX_HEIGHT = 50;
  private static final int BOX_WIDTH = 25;
  private static final int BOX_HEIGHT = 25;
  public static final int INITIAL_FIRE_COUNT = 3;
  public static final int INITIAL_FIREFIGHTER_COUNT = 6;

@@ -31,7 +31,7 @@ public class SimulatorApplication extends javafx.application.Application {
  }

  @Override
  public void start(Stage primaryStage) throws IOException {
  public void start(@SuppressWarnings("exports") Stage primaryStage) throws IOException {
    initializePrimaryStage(primaryStage);
    initializeView();
    showScene();
Original line number Diff line number Diff line
package controller;

import static java.util.Objects.*;

import java.util.ArrayList;
import java.util.List;

import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
@@ -13,17 +18,12 @@ import javafx.scene.control.ToggleGroup;
import javafx.util.Duration;
import javafx.util.Pair;
import model.Board;
import model.ModelElement;
import model.FirefighterBoard;
import model.Entity;
import model.FireFighterScenario;
import util.Position;
import view.Grid;
import view.ViewElement;

import java.util.ArrayList;
import java.util.List;

import static java.util.Objects.requireNonNull;

public class Controller {

  public static final int PERIOD_IN_MILLISECONDS = 50;
@@ -40,7 +40,7 @@ public class Controller {
  @FXML
  private Grid<ViewElement> grid;
  private Timeline timeline;
  private Board<List<ModelElement>> board;
  private Board<Entity> board;

  @FXML
  private void initialize() {
@@ -54,15 +54,15 @@ public class Controller {
    pauseToggleButton.setSelected(true);
  }

  private void setModel(FirefighterBoard firefighterBoard) {
    this.board = requireNonNull(firefighterBoard, "firefighter.model is null");
  private void setModel(Board<Entity> board) {
    this.board = requireNonNull(board, "board is null");
  }

  private void updateBoard(){
    List<Position> updatedPositions = board.updateToNextGeneration();
    List<Pair<Position, ViewElement>> updatedSquares = new ArrayList<>();
    for(Position updatedPosition : updatedPositions){
      List<ModelElement> squareState = board.getState(updatedPosition);
      Entity squareState = board.getState(updatedPosition);
      ViewElement viewElement = getViewElement(squareState);
      updatedSquares.add(new Pair<>(updatedPosition, viewElement));
    }
@@ -74,6 +74,7 @@ public class Controller {
    int columnCount = board.columnCount();
    int rowCount = board.rowCount();
    ViewElement[][] viewElements = new ViewElement[rowCount][columnCount];
    System.out.println("columnsCOunt : " + columnCount + " rowCount : " + rowCount);
    for(int column = 0; column < columnCount; column++)
      for(int row = 0; row < rowCount; row++)
        viewElements[row][column] = getViewElement(board.getState(new Position(row, column)));
@@ -81,14 +82,8 @@ public class Controller {
    updateGenerationLabel(board.stepNumber());
  }

  private ViewElement getViewElement(List<ModelElement> squareState) {
    if(squareState.contains(ModelElement.FIREFIGHTER)){
      return ViewElement.FIREFIGHTER;
    }
    if (squareState.contains(ModelElement.FIRE)){
      return ViewElement.FIRE;
    }
    return ViewElement.EMPTY;
  private ViewElement getViewElement(Entity entity) {
      return new ViewElement(entity.getViewColor());
  }

  private void initializeTimeline() {
@@ -126,7 +121,7 @@ public class Controller {
  public void initialize(int squareWidth, int squareHeight, int columnCount,
                                int rowCount, int initialFireCount, int initialFirefighterCount) {
    grid.setDimensions(columnCount, rowCount, squareWidth, squareHeight);
    this.setModel(new FirefighterBoard(columnCount, rowCount, initialFireCount, initialFirefighterCount));
    this.setModel(new FireFighterScenario(columnCount, rowCount, initialFireCount, initialFirefighterCount));
    repaintGrid();
  }

Original line number Diff line number Diff line
package model;

import util.Position;

import java.util.List;

import util.Position;

/**
 * This interface represents a generic board for modeling various state-based systems.
 *
@@ -61,5 +61,11 @@ public interface Board<S> {
   * @return The current step number or generation.
   */
  int stepNumber();

  public int getStepNumber();
  // Le booléen replaceState permet de forcer le remplacement des cases vides
  public void setState(Entity state, Position position, boolean replaceStates);

  public boolean doesPositionExist(Position position);
}
+43 −0
Original line number Diff line number Diff line
package model;

import java.util.ArrayList;
import java.util.List;

import javafx.scene.paint.Color;
import util.Position;

public class EmptySquare implements Entity{

    private Position position;
    private final Color viewColor = Color.WHITE;
    public EmptySquare(Position p){
        this.position = p;
    }
    @Override
    public List<Position> nextTurn(Board<Entity> board) {
        return new ArrayList<Position>();
    }

    @Override
    public Position getPosition() {
        return position;
    }

    @Override
    public void setPosition(Position p) {
        this.position = p;
    }
    
    public Color getViewColor(){
        return this.viewColor;
    }
    @Override
    public int getAge() {
        return -999;
    }

    @Override
    public void incrementAge() {
        return;
    }
}
+16 −0
Original line number Diff line number Diff line
package model;

import java.util.List;

import javafx.scene.paint.Color;
import util.Position;

public interface Entity {
    // Calcule ce que l'entité va faire au prochain tour, et retourne la liste des positions affectés
    public List<Position> nextTurn(Board<Entity> board);
    public Position getPosition();
    public void setPosition(Position p);
    public int getAge();
    public void incrementAge();
    public Color getViewColor();
}
+14 −0
Original line number Diff line number Diff line
package model;

import util.Matrix;
import util.Position;

public abstract class EntityScenario implements Scenario{
    public void initScenario(Matrix<Entity> matrix){
        for(int x = 0; x < matrix.getRows(); x++){
            for(int y = 0; y < matrix.getColumns(); y++){
                matrix.set(x,y, new EmptySquare(new Position(x, y)));
            }
        }
    }
}
+75 −0
Original line number Diff line number Diff line
package model;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javafx.scene.paint.Color;
import util.Position;

public class Fire implements Entity{
    Board<Entity> b;
    private Position position;
    private final Color viewColor = Color.RED;
    private int age;
    public Fire(Position position, Board<Entity> b){
        this.b = b;
        this.position = position;
        this.age = 0;
    }
    public Fire(Position position, Board<Entity> b, int age){
        this.b = b;
        this.position = position;
        this.age = age;
    }

    @Override
    public List<Position> nextTurn(Board<Entity> board) {
        age = age +1;
        List<Position> positions = generateAdjacentPosition();
        for(Position p : positions){
            board.setState(new Fire(p, board), p);
            if(!b.doesPositionExist(p)){
                positions.remove(p);
            }
        }
        return positions;
    }

    private List<Position> generateAdjacentPosition(){
        int x = position.x();
        int y = position.y();

        return Stream.of(
                new Position(x, y + 1),
                new Position(x + 1, y),
                new Position(x, y - 1),
                new Position(x - 1, y)
            )
            .filter(p -> b.doesPositionExist(p))
            .collect(Collectors.toList());
    }

    
    @Override
    public void setPosition(Position p) {
        this.position = p;
    }
    @Override
    public Position getPosition() {
        return this.position;
    }

    public Color getViewColor(){
        return this.viewColor;
    }

    @Override
    public int getAge() {
        return this.age;
    }

    @Override
    public void incrementAge() {
        this.age = age + 1 ;
    }
}
+61 −0
Original line number Diff line number Diff line
package model;
import java.util.ArrayList;
import java.util.List;

import javafx.scene.paint.Color;
import util.Position;

public class FireFighter implements Entity{
    private int age;
    private Position position;
    private final Color viewColor = Color.BLUE;
    private Board<Entity> board;

    public FireFighter(Position position, Board<Entity> b){
        this.position = position;
        this.board = b;
        this.age = 0;
    }
    public FireFighter(Position position, Board<Entity> b, int age){
        this.position = position;
        this.board = b;
        this.age = age;
    }
    
    public List<Position> nextTurn(Board<Entity> b){
        age++;
        List<Position> positions = new ArrayList<Position>();
        positions.add(position);
        return positions;
        // Récupérer la position
        //Si un feu est à proximité : éteindre les feux à x + 1 y, x y+1, x+1 y-1, x-1 y+1 
        //Sinon
        //Se déplacer vers le feu le plus proche
        //Si un feu est à proximité : éteindre les feux à x + 1 y, x y+1, x+1 y-1, x-1 y+1 
        // Ajouter un feu à x + 1 y, x y+1, x-1 y, x y-1 
    }

    @Override
    public void setPosition(Position p) {
        this.position = p;
    }

    @Override
    public Position getPosition() {
        return this.position;
    }
    public Color getViewColor(){
        return this.viewColor;
    }

    @Override
    public int getAge() {
        return this.age;
    }
    @Override
    public void incrementAge() {
        this.age = age + 1 ;
    }

    
}
Original line number Diff line number Diff line
package model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import util.Matrix;
import util.Position;
import util.PositionUtil;

public class FireFighterScenario extends EntityScenario implements Board<Entity> {

  private Matrix<Entity> matrix;
  private int step;

  public FireFighterScenario(int columns, int rows, int initialFireCount, int initialFireFightersCount) {
    this.matrix = new Matrix<Entity>(columns, rows);
    initScenario(matrix);
    placeInitialActors(initialFireCount, initialFireFightersCount);
    this.step = 0;
  }

  private void placeInitialActors(int initialFireCount, int initialFireFightersCount) {
    int fireCount = 0;
    int fireFighterCount = 0;
    int chance = 5; // Chance initiale en pourcentage
    Random random = new Random();

    List<Position> positions = new ArrayList<>();
    for (int x = 0; x < matrix.getRows(); x++) {
      for (int y = 0; y < matrix.getColumns(); y++) {
        positions.add(new Position(x, y));
      }
    }

    while (fireCount < initialFireCount || fireFighterCount < initialFireFightersCount) {
      Collections.shuffle(positions); // Mélange les positions pour un parcours aléatoire

      for (Position pos : positions) {
        if (getState(pos) instanceof EmptySquare) {
          if (fireCount < initialFireCount && random.nextInt(100) < chance) {
            setState(new Fire(pos, this, 1), pos);
            fireCount++;
            if (fireCount == initialFireCount && fireFighterCount == initialFireFightersCount) {
              return;
            }
            continue;
          }

          if (fireFighterCount < initialFireFightersCount && random.nextInt(100) < chance) {
            setState(new FireFighter(pos, this, 1), pos);
            fireFighterCount++;
            if (fireCount == initialFireCount && fireFighterCount == initialFireFightersCount) {
              return;
            }
          }
        }
      }

      // Augmente la chance de placement après chaque parcours complet
      chance = Math.min(chance + 5, 100); // Ne dépasse pas 100%
    }
  }

  public Entity getState(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 setState(Entity state, Position position) {
    if (!(getState(position) instanceof EmptySquare)) {
      return;
    }
    if (doesPositionExist(position)) {
      matrix.set(position.x(), position.y(), state);
    }
  }

  public void setState(Entity state, Position position, boolean replaceStates) {
    if (!(getState(position) instanceof EmptySquare) && !replaceStates) {
      return;
    }
    matrix.set(position.x(), position.y(), state);
  }

  public int rowCount() {
    return matrix.getRows();
  }

  public int columnCount() {
    return matrix.getColumns();
  }

  public List<Position> updateToNextGeneration() {
    ArrayList<Position> changedPositions = new ArrayList<>();
    Iterator<Entity> iterator = matrix.iterator();
    while (iterator.hasNext()) {
      Entity e = iterator.next();
      if (e instanceof EmptySquare)
        continue;
      System.out.println("found age : " + e.getAge() + " current age : " + step);
      if (e.getAge() == 0) {
        e.incrementAge();
        continue;
      }
      ;
      List<Position> entityUpdatedPositions = e.nextTurn(this);
      changedPositions.addAll(entityUpdatedPositions);
    }
    return changedPositions;
  }

  public Position getNearestEntity(Position fromPos, Class<?> entityType) {
    int rows = matrix.getRows();
    int cols = matrix.getColumns();
    Position nearestPosition = null;

    // 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) {
        Entity currentEntity = matrix.get(currentPos.x(), currentPos.y());
        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() {
    matrix.clear();
  }

  public int stepNumber() {
    this.step = step + 1;
    return this.step;
  }

  @Override
  public boolean doesPositionExist(Position position) {
    return matrix.validateIndex(position);
  }

  @Override
  public int getStepNumber() {
    return step;
  }
}
+0 −147
Original line number Diff line number Diff line
package model;

import util.Position;

import java.util.*;


public class FirefighterBoard implements Board<List<ModelElement>> {
  private final int columnCount;
  private final int rowCount;
  private final int initialFireCount;
  private final int initialFirefighterCount;
  private final TargetStrategy targetStrategy = new TargetStrategy();
  private List<Position> firefighterPositions;
  private Set<Position> firePositions;
  private Map<Position, List<Position>> neighbors = new HashMap();
  private final Position[][] positions;
  private int step = 0;
  private final Random randomGenerator = new Random();

  public FirefighterBoard(int columnCount, int rowCount, int initialFireCount, int initialFirefighterCount) {
    this.columnCount = columnCount;
    this.rowCount = rowCount;
    this.positions = new Position[rowCount][columnCount];
    for (int column = 0; column < columnCount; column++)
      for (int row = 0; row < rowCount; row++)
        positions[row][column] = new Position(row, column);
    for (int column = 0; column < columnCount; column++)
      for (int row = 0; row < rowCount; row++) {
        List<Position> list = new ArrayList<>();
        if (row > 0) list.add(positions[row - 1][column]);
        if (column > 0) list.add(positions[row][column - 1]);
        if (row < rowCount - 1) list.add(positions[row + 1][column]);
        if (column < columnCount - 1) list.add(positions[row][column + 1]);
        neighbors.put(positions[row][column], list);
      }
    this.initialFireCount = initialFireCount;
    this.initialFirefighterCount = initialFirefighterCount;
    initializeElements();
  }

  public void initializeElements() {
    firefighterPositions = new ArrayList<>();
    firePositions = new HashSet<>();
    for (int index = 0; index < initialFireCount; index++)
      firePositions.add(randomPosition());
    for (int index = 0; index < initialFirefighterCount; index++)
      firefighterPositions.add(randomPosition());
  }

  private Position randomPosition() {
    return new Position(randomGenerator.nextInt(rowCount), randomGenerator.nextInt(columnCount));
  }

  @Override
  public List<ModelElement> getState(Position position) {
    List<ModelElement> result = new ArrayList<>();
    for (Position firefighterPosition : firefighterPositions)
      if (firefighterPosition.equals(position))
        result.add(ModelElement.FIREFIGHTER);
    if (firePositions.contains(position))
      result.add(ModelElement.FIRE);
    return result;
  }

  @Override
  public int rowCount() {
    return rowCount;
  }

  @Override
  public int columnCount() {
    return columnCount;
  }

  public List<Position> updateToNextGeneration() {
    List<Position> modifiedPositions = updateFirefighters();
    modifiedPositions.addAll(updateFires());
    step++;
    return modifiedPositions;
  }

  private List<Position> updateFires() {
    List<Position> modifiedPositions = new ArrayList<>();
    if (step % 2 == 0) {
      List<Position> newFirePositions = new ArrayList<>();
      for (Position fire : firePositions) {
        newFirePositions.addAll(neighbors.get(fire));
      }
      firePositions.addAll(newFirePositions);
      modifiedPositions.addAll(newFirePositions);
    }
    return modifiedPositions;

  }

  @Override
  public int stepNumber() {
    return step;
  }

  private List<Position> updateFirefighters() {
    List<Position> modifiedPosition = new ArrayList<>();
    List<Position> firefighterNewPositions = new ArrayList<>();
    for (Position firefighterPosition : firefighterPositions) {
      Position newFirefighterPosition =
              targetStrategy.neighborClosestToFire(firefighterPosition,
                      firePositions, neighbors);
      firefighterNewPositions.add(newFirefighterPosition);
      extinguish(newFirefighterPosition);
      modifiedPosition.add(firefighterPosition);
      modifiedPosition.add(newFirefighterPosition);
      List<Position> neighborFirePositions = neighbors.get(newFirefighterPosition).stream()
              .filter(firePositions::contains).toList();
      for (Position firePosition : neighborFirePositions)
        extinguish(firePosition);
      modifiedPosition.addAll(neighborFirePositions);
    }
    firefighterPositions = firefighterNewPositions;
    return modifiedPosition;
  }

  @Override
  public void reset() {
    step = 0;
    initializeElements();
  }

  private void extinguish(Position position) {
    firePositions.remove(position);
  }


  @Override
  public void setState(List<ModelElement> state, Position position) {
    firePositions.remove(position);
    for (; ; ) {
      if (!firefighterPositions.remove(position)) break;
    }
    for (ModelElement element : state) {
      switch (element) {
        case FIRE -> firePositions.add(position);
        case FIREFIGHTER -> firefighterPositions.add(position);
      }
    }
  }
}
 No newline at end of file
+7 −0
Original line number Diff line number Diff line
package model;

import util.Matrix;

public interface Scenario {
    public void initScenario(Matrix<Entity> matrix);
}
+128 −0
Original line number Diff line number Diff line
package util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;

public class Matrix<E> implements Iterable<E> {
    private ArrayList<ArrayList<E>> matrix;
    private final int rows;
    private final int columns;

    public Matrix(int rows, int columns) {
        this.rows = rows;
        this.columns = columns;
        this.matrix = new ArrayList<>(rows);
        
        // Initialiser chaque ligne de la matrice
        for (int i = 0; i < rows; i++) {
            ArrayList<E> row = new ArrayList<>(columns);
            // Initialiser chaque colonne avec des valeurs nulles
            for (int j = 0; j < columns; j++) {
                row.add(null);
            }
            this.matrix.add(row);
        }
    }

    public E get(int x, int y) {
        validateIndex(x, y);
        return matrix.get(x).get(y);
    }

    public E set(int x, int y, E object) {
        validateIndex(x, y);
        return matrix.get(x).set(y, object);
    }

    public void clear() {
        this.matrix.clear();
        for (int i = 0; i < rows; i++) {
            ArrayList<E> row = new ArrayList<>(columns);
            for (int j = 0; j < columns; j++) {
                row.add(null);
            }
            this.matrix.add(row);
        }
    }

    public int size() {
        return rows * columns;
    }

    public int getColumns(){
        return this.columns;
    }
    public int getRows(){
        return this.rows;
    }
    /*

    public void displayMatrix() {
        System.out.print("  ");
        for (int j = 0; j < columns; j++) {
            System.out.print("___ ");
        }
        System.out.println();

        for (int i = 0; i < rows; i++) {
            System.out.print("| ");
            for (int j = 0; j < columns; j++) {
                if (matrix.get(i).get(j) != null) {
                    System.out.print(" x | ");
                } else {
                    System.out.print("   | ");
                }
            }
            System.out.println();
            System.out.print("  ");
            for (int j = 0; j < columns; j++) {
                System.out.print("___ ");
            }
            System.out.println();
        }
    }
        */

    private void validateIndex(int x, int y) {
        if (x < 0 || x >= rows || y < 0 || y >= columns) {
            throw new IndexOutOfBoundsException("Indices x: "+ x + " y: " + y + " hors limites pour la matrice.");
        }
    }

    public boolean validateIndex(Position position){
        return position.x() >= 0 && position.x() < rows && position.y() >= 0 && position.y() < columns;
    }
    

    

    @Override
    public Iterator<E> iterator() {
        return new MatrixIterator();
    }

    private class MatrixIterator implements Iterator<E> {
        private int row = 0;
        private int col = 0;

        @Override
        public boolean hasNext() {
            return row < rows && col < columns;
        }

        @Override
        public E next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            E element = matrix.get(row).get(col);
            col++;
            if (col >= columns) {
                col = 0;
                row++;
            }
            return element;
        }
    }
}
Original line number Diff line number Diff line
package util;

public record Position(int row, int column) {
public record Position(int x, int y) {

}
+30 −0
Original line number Diff line number Diff line
package util;

import java.util.ArrayList;
import java.util.List;

public class PositionUtil {
    public static List<Position> getPositionsAtManhattanDistance(Position fromPos, int distance, int rows, int cols) {
        List<Position> positions = new ArrayList<>();
        int x0 = fromPos.x();
        int y0 = fromPos.y();

        // Générer toutes les positions à une distance de Manhattan donnée
        for (int dx = -distance; dx <= distance; dx++) {
            int dy = distance - Math.abs(dx);

            int[] dyOptions = { dy, -dy };
            for (int deltaY : dyOptions) {
                int x = x0 + dx;
                int y = y0 + deltaY;

                // Vérifier si la position est dans les limites de la matrice
                if (x >= 0 && x < rows && y >= 0 && y < cols) {
                    positions.add(new Position(x, y));
                }
            }
        }

        return positions;
    }
}
 No newline at end of file
Original line number Diff line number Diff line
package model;
package util;

import util.Position;

import java.util.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

public class TargetStrategy {

@@ -12,7 +17,7 @@ public class TargetStrategy {
     * @param targets positions that are targeted.
     * @return the position next to the current position that is on the path to the closest target.
     */
    Position neighborClosestToFire(Position position, Collection<Position> targets,
    public Position neighborClosestToFire(Position position, Collection<Position> targets,
                                   Map<Position,List<Position>>neighbors) {
        Set<Position> seen = new HashSet<Position>();
        HashMap<Position, Position> firstMove = new HashMap<Position, Position>();
Original line number Diff line number Diff line
package view;

import java.util.List;

import javafx.scene.canvas.Canvas;
import javafx.scene.paint.Color;
import javafx.util.Pair;
import util.Position;

import java.util.List;

public class FirefighterGrid extends Canvas implements Grid<ViewElement>{

    private void paintElementAtPosition(ViewElement element, Position position) {
        paintBox(position.row(), position.column(), element.color);
        paintBox(position.x(), position.y(), element.getColor());
    }
    private int boxWidth;
    private int boxHeight;
@@ -27,7 +27,7 @@ public class FirefighterGrid extends Canvas implements Grid<ViewElement>{
    private void clear(List<Pair<Position, ViewElement>> positionedElements) {
        for (Pair<Position, ViewElement> positionElement : positionedElements) {
            Position position = positionElement.getKey();
            clearBox(position.row(), position.column());
            clearBox(position.x(), position.y());
        }
    }

Original line number Diff line number Diff line
@@ -2,10 +2,14 @@ package view;

import javafx.scene.paint.Color;

public enum ViewElement {
  FIREFIGHTER(Color.BLUE), FIRE(Color.RED), EMPTY(Color.WHITE);
  final Color color;
  ViewElement(Color color) {
public class ViewElement {
    private final Color color;

    public ViewElement(Color color) {
        this.color = color;
    }

    public Color getColor() {
        return color;
    }
}
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import view.FirefighterGrid?>

<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.Label?>
<HBox styleClass="background" stylesheets="@DarkTheme.css"
      xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
      xmlns="http://javafx.com/javafx"
      xmlns:fx="http://javafx.com/fxml"
      fx:controller="controller.Controller">
  <VBox>
    <Separator maxHeight="-Infinity" maxWidth="-Infinity"
               prefHeight="24.0" prefWidth="200.0" />
    <Label maxHeight="-Infinity" maxWidth="-Infinity" alignment="CENTER" prefHeight="24.0" prefWidth="200.0"
    <Label maxHeight="-Infinity" maxWidth="-Infinity"
           alignment="CENTER" prefHeight="24.0" prefWidth="200.0"
           text="Generation number" />
    <Label fx:id="generationNumberLabel" alignment="CENTER" contentDisplay="TEXT_ONLY"
           maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="24.0" prefWidth="200.0"/>
    <Label fx:id="generationNumberLabel"
           alignment="CENTER" contentDisplay="TEXT_ONLY"
           maxHeight="-Infinity" maxWidth="-Infinity"
           prefHeight="24.0" prefWidth="200.0" />
    <Separator maxHeight="-Infinity" maxWidth="-Infinity"
               prefHeight="24.0" prefWidth="200.0" />
    <Button fx:id="restartButton" maxHeight="-Infinity" maxWidth="-Infinity"
            mnemonicParsing="false" onAction="#restartButtonAction" prefHeight="24.0" prefWidth="200.0"
            text="Restart"/>
            mnemonicParsing="false" onAction="#restartButtonAction"
            prefHeight="24.0" prefWidth="200.0" text="Restart" />
    <Button fx:id="oneStepButton" maxHeight="-Infinity" maxWidth="-Infinity"
            mnemonicParsing="false" onAction="#oneStepButtonAction" prefHeight="24.0" prefWidth="200.0"
            text="One step"/>
            mnemonicParsing="false" onAction="#oneStepButtonAction"
            prefHeight="24.0" prefWidth="200.0" text="One step" />
    <ToggleButton fx:id="playToggleButton" maxHeight="-Infinity" maxWidth="-Infinity"
                  mnemonicParsing="false" onAction="#playToggleButtonAction" prefHeight="24.0"
                  prefWidth="200.0" styleClass="button" text="Play"/>
                  mnemonicParsing="false" onAction="#playToggleButtonAction"
                  prefHeight="24.0" prefWidth="200.0"
                  styleClass="button" text="Play" />
    <ToggleButton fx:id="pauseToggleButton" maxHeight="-Infinity" maxWidth="-Infinity"
                  mnemonicParsing="false" onAction="#pauseToggleButtonAction" prefHeight="24.0"
                  prefWidth="200.0" styleClass="button" text="Pause"/>
                  mnemonicParsing="false" onAction="#pauseToggleButtonAction"
                  prefHeight="24.0" prefWidth="200.0"
                  styleClass="button" text="Pause" />
  </VBox>
  <FirefighterGrid fx:id="grid"
                   xmlns="http://javafx.com/javafx"
+0 −39
Original line number Diff line number Diff line
package model;

import org.junit.jupiter.api.Test;
import util.Position;

import java.util.List;

import static org.assertj.core.api.Assertions.*;

public class FirefighterBoardTest {
  @Test
  void testColumnCount(){
    Board<List<ModelElement>> board = new FirefighterBoard(20, 10, 1, 3);
    assertThat(board.columnCount()).isEqualTo(20);
  }
  @Test
  void testRowCount(){
    Board<List<ModelElement>> board = new FirefighterBoard(20, 10, 1, 3);
    assertThat(board.rowCount()).isEqualTo(10);
  }
  @Test
  void testStepNumber(){
    Board<List<ModelElement>> board = new FirefighterBoard(20, 10, 1, 3);
    for(int index = 0; index < 10; index++){
      assertThat(board.stepNumber()).isEqualTo(index);
      board.updateToNextGeneration();
    }
    assertThat(board.stepNumber()).isEqualTo(10);
  }
  @Test
  void testGetState_afterSet(){
    Board<List<ModelElement>> board = new FirefighterBoard(20, 10, 0, 0);
    Position position = new Position(1,2);
    assertThat(board.getState(position)).isEmpty();
    board.setState(List.of(ModelElement.FIRE), position);
    assertThat(board.getState(position)).containsExactly(ModelElement.FIRE);
  }

}
Original line number Diff line number Diff line
package view;

import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;

public class FirefighterGridTest {
  @Test
  void testColumnCount(){
    Grid<ViewElement> grid = new FirefighterGrid();
    grid.setDimensions(20,10,10,10);
    grid.setDimensions(20,10,5,5);
    assertThat(grid.columnCount()).isEqualTo(20);
  }
  @Test
  void testRowCount(){
    Grid<ViewElement> grid = new FirefighterGrid();
    grid.setDimensions(20,10,10,10);
    grid.setDimensions(20,10,5,5);
    assertThat(grid.rowCount()).isEqualTo(10);
  }
}