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
  • variant
2 results

Target

Select target project
  • l22015417/firefighterstarter
  • m19023837/firefighter-starter-mansour-chadi-chahine-rami
  • r24025701/firefighterstarter
  • n24026202/firefighterstarter
  • couetoux.b/firefighterstarter
  • b23027938/firefighterstarter
  • z20039716/fire-fighter
  • a18023913/firefighterstarter
  • o22010261/firefighterstarter
  • b22015516/firefighterstarter
  • alaboure/firefighter-template
  • p21211679/firefighter-luis-parra-yanis-lounadi
  • v23014723/firefighter-project
  • k20014011/firefighter-template
  • m23022217/firefighter-template
  • p20006624/firefighter-template
  • l21221596/firefighter-template
  • s21232465/firefighter-template
  • y21224754/firefighter-template
  • w21225935/firefighter-template
  • h22023886/firefighter-template
  • b21221604/firefighter-template-boucenna-yacine-zeghar-mohamed-lamine
  • c23025119/firefighterstarter
  • b20031964/firefighterstarter
24 results
Select Git revision
  • main
  • variant
2 results
Show changes
Showing
with 1022 additions and 187 deletions
.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
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?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"
fx:controller="controller.Controller" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity">
<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>
File added
......@@ -17,8 +17,10 @@ public class SimulatorApplication extends javafx.application.Application {
private static final int COLUMN_COUNT = 20;
private static final int BOX_WIDTH = 50;
private static final int BOX_HEIGHT = 50;
public static final int INITIAL_FIRE_COUNT = 3;
public static final int INITIAL_FIREFIGHTER_COUNT = 6;
public static final int INITIAL_FIRE_COUNT = 4;
public static final int INITIAL_FIREFIGHTER_COUNT = 3;
public static final int INITIAL_CLOUD_COUNT = 3;
public static final int INITIAL_MOTORIZED_COUNT = 3;
private Stage primaryStage;
private Parent view;
......@@ -44,7 +46,7 @@ public class SimulatorApplication extends javafx.application.Application {
view = loader.load();
Controller controller = loader.getController();
controller.initialize(BOX_WIDTH, BOX_HEIGHT, COLUMN_COUNT, ROW_COUNT,
INITIAL_FIRE_COUNT, INITIAL_FIREFIGHTER_COUNT);
INITIAL_FIRE_COUNT, INITIAL_FIREFIGHTER_COUNT,INITIAL_CLOUD_COUNT,INITIAL_MOTORIZED_COUNT);
}
private void showScene() {
......
......@@ -4,4 +4,5 @@ public class SimulatorMain {
public static void main(String[] args){
SimulatorApplication.main(args);
}
}
......@@ -12,9 +12,7 @@ import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.util.Duration;
import javafx.util.Pair;
import model.Board;
import model.ModelElement;
import model.FirefighterBoard;
import model.*;
import util.Position;
import view.Grid;
import view.ViewElement;
......@@ -40,7 +38,7 @@ public class Controller {
@FXML
private Grid<ViewElement> grid;
private Timeline timeline;
private Board<List<ModelElement>> board;
private FirefighterBoard board;
@FXML
private void initialize() {
......@@ -59,7 +57,7 @@ public class Controller {
}
private void updateBoard(){
List<Position> updatedPositions = board.updateToNextGeneration();
List<Position> updatedPositions = board.getBehavior().updateToNextGeneration();
List<Pair<Position, ViewElement>> updatedSquares = new ArrayList<>();
for(Position updatedPosition : updatedPositions){
List<ModelElement> squareState = board.getState(updatedPosition);
......@@ -67,30 +65,48 @@ public class Controller {
updatedSquares.add(new Pair<>(updatedPosition, viewElement));
}
grid.repaint(updatedSquares);
updateGenerationLabel(board.stepNumber());
updateGenerationLabel(board.getBehavior().stepNumber());
}
private void repaintGrid(){
int columnCount = board.columnCount();
int rowCount = board.rowCount();
int columnCount = board.getProperties().columnCount();
int rowCount = board.getProperties().rowCount();
ViewElement[][] viewElements = new ViewElement[rowCount][columnCount];
for(int column = 0; column < columnCount; column++)
for(int row = 0; row < rowCount; row++)
viewElements[row][column] = getViewElement(board.getState(new Position(row, column)));
grid.repaint(viewElements);
updateGenerationLabel(board.stepNumber());
updateGenerationLabel(board.getBehavior().stepNumber());
}
private ViewElement getViewElement(List<ModelElement> squareState) {
if(squareState.contains(ModelElement.FIREFIGHTER)){
for (ModelElement element : squareState) {
if (element instanceof FireFighter) {
return ViewElement.FIREFIGHTER;
}
if (squareState.contains(ModelElement.FIRE)){
if (element instanceof Fire) {
return ViewElement.FIRE;
}
if (element instanceof Cloud) {
return ViewElement.CLOUD;
}
if (element instanceof MotorizedFireFighter)
{
return ViewElement.MOTORIZED;
}
if(element instanceof Mountain)
{
return ViewElement.MOUNTAIN;
}
if (element instanceof Road)
{
return ViewElement.ROAD;
}
}
return ViewElement.EMPTY;
}
private void initializeTimeline() {
Duration duration = new Duration(Controller.PERIOD_IN_MILLISECONDS);
EventHandler<ActionEvent> eventHandler =
......@@ -124,9 +140,9 @@ public class Controller {
}
public void initialize(int squareWidth, int squareHeight, int columnCount,
int rowCount, int initialFireCount, int initialFirefighterCount) {
int rowCount, int initialFireCount, int initialFirefighterCount,int initialCloud,int initialMotorized) {
grid.setDimensions(columnCount, rowCount, squareWidth, squareHeight);
this.setModel(new FirefighterBoard(columnCount, rowCount, initialFireCount, initialFirefighterCount));
this.setModel(new FirefighterBoard(columnCount, rowCount, initialFireCount, initialFirefighterCount,initialCloud,initialMotorized));
repaintGrid();
}
......
......@@ -4,62 +4,23 @@ import util.Position;
import java.util.List;
/**
* This interface represents a generic board for modeling various state-based systems.
*
* @param <S> The type of state represented on the board.
*/
public interface Board<S> {
public interface Board<S> {
/**
* Get the state of the board at a specific position.
* Retourne l'état des éléments situés à une position spécifique du tableau.
*
* @param position The position on the board for which to retrieve the state.
* @return The state at the specified position.
* @param position La position sur le tableau pour laquelle récupérer l'état.
* @return L'état des éléments à la position donnée.
*/
S getState(Position position);
S getState(Position position); // État des éléments sur une position donnée.
/**
* Set the state of a specific position on the board to the specified state.
* Définit l'état des éléments à une position spécifique du tableau.
*
* @param state The state to set for the given position.
* @param position The position on the board for which to set the state.
* @param state L'état à définir pour la position donnée.
* @param position La position sur le tableau pour laquelle définir l'état.
*/
void setState(S state, Position position);
/**
* Get the number of rows in the board.
*
* @return The number of rows in the board.
*/
int rowCount();
/**
* Get the number of columns in the board.
*
* @return The number of columns in the board.
*/
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.
*/
void reset();
/**
* Get the current step number or generation of the board.
*
* @return The current step number or generation.
*/
int stepNumber();
}
package model;
import util.Position;
import java.util.List;
public interface BoardBehavior<S> {
/**
* Get the current step number or generation of the board.
*
* @return The current step number or generation.
*/
int stepNumber();
/**
* 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.
*/
void reset();
}
package model;
import util.Position;
public abstract class BoardElement implements ModelElement{
protected Position position;
public BoardElement(Position position) {
this.position = position;
}
@Override
public Position getPosition() {
return position;
}
public void setPosition(Position position) {
this.position = position;
}
public abstract String getType(); // Ajout de la méthode abstraite
public abstract String toString();
}
package model;
import util.Position;
import util.TargetStrategy;
import java.util.*;
public class BoardFireFighterBehavior implements BoardBehavior{
private final TargetStrategy targetStrategy = new TargetStrategy();
private final Map<Position, List<Position>> neighbors;
private List<Position> firefighterPositions;
private List<Position> motorizedFighters;
private Set<Position> firePositions;
private final ElementFactory<FireFighter> firefighterFactory;
private final ElementFactory<Fire> fireFactory;
private final ElementFactory<Cloud> cloudFactory;
private final ElementFactory<MotorizedFireFighter> motorizedFactory;
private List<Position> cloudPositions;
private final Map<Position, Terrain> terrainMap = new HashMap<>();
private int step;
public BoardFireFighterBehavior(Map<Position, List<Position>> neighbors, ElementFactory<Fire> fireFactory ,ElementFactory<FireFighter> firefighterFactory,
ElementFactory<Cloud> cloudFactory,ElementFactory<MotorizedFireFighter> motorizedFactory) {
this.step=0;
this.neighbors = neighbors;
this.firefighterFactory = firefighterFactory;
this.fireFactory = fireFactory;
this.cloudFactory=cloudFactory;
this.motorizedFactory=motorizedFactory;
}
public void initializeElements(int rowCount, int columnCount) {
// Feux
firePositions = new HashSet<>();
List<Fire> fires = fireFactory.createElements(rowCount, columnCount);
for (Fire fire : fires) {
firePositions.add(fire.getPosition());
}
// Pompiers
firefighterPositions = new ArrayList<>();
List<FireFighter> firefighters = firefighterFactory.createElements(rowCount, columnCount);
for (FireFighter firefighter : firefighters) {
firefighterPositions.add(firefighter.getPosition());
}
// Nuages
cloudPositions = new ArrayList<>();
List<Cloud> clouds = cloudFactory.createElements(rowCount, columnCount);
for (Cloud cloud : clouds) {
cloudPositions.add(cloud.getPosition());
}
// Pompiers motorisés
motorizedFighters = new ArrayList<>();
List<MotorizedFireFighter> motorizedFirefighters = motorizedFactory.createElements(rowCount, columnCount);
for (MotorizedFireFighter motorizedFirefighter : motorizedFirefighters) {
motorizedFighters.add(motorizedFirefighter.getPosition());
}
generateMountainBlocks(rowCount, columnCount);
generateRoads(rowCount,columnCount);
}
public List<Position> updateFires() {
List<Position> modifiedPositions = new ArrayList<>();
if (step % 2 == 0) {
List<Position> newFirePositions = new ArrayList<>();
// Pour chaque feu existant, vérifier ses voisins
for (Position fire : firePositions) {
// Si la position voisine est libre (non occupée par un feu ou un pompier), le feu peut se propager
for (Position neighbor : neighbors.get(fire)) {
// Vérifier si le feu peut se propager à cette position (pas de feu déjà là et pas un terrain bloqué)
if (canMoveTo(neighbor, firePositions, firefighterPositions) && !firePositions.contains(neighbor)) {
newFirePositions.add(neighbor);
}
}
}
// Ajouter les nouvelles positions de feu à la liste des feux existants
firePositions.addAll(newFirePositions);
modifiedPositions.addAll(newFirePositions);
}
return modifiedPositions;
}
public List<Position> updateFirefighters() {
List<Position> modifiedPositions = new ArrayList<>();
List<Position> newFirefighterPositions = new ArrayList<>();
for (Position firefighterPosition : firefighterPositions) {
// Calcul de la position vers laquelle le pompier devrait se déplacer
Position newFirefighterPosition = targetStrategy.neighborClosestToTarget(firefighterPosition, firePositions, neighbors);
// Vérification si la position cible est valide pour le mouvement
if (canMoveTo(newFirefighterPosition, firePositions, firefighterPositions)) {
// Si le déplacement est valide, on met à jour la position du pompier
newFirefighterPositions.add(newFirefighterPosition);
// Éteindre le feu à la nouvelle position
extinguish(newFirefighterPosition);
modifiedPositions.add(firefighterPosition);
modifiedPositions.add(newFirefighterPosition);
// Vérification des voisins et extinction des feux voisins
List<Position> neighborFirePositions = neighbors.get(newFirefighterPosition).stream()
.filter(firePositions::contains).toList();
// Log pour débogage
System.out.println("Pompiers se déplacent de " + firefighterPosition + " vers " + newFirefighterPosition);
// Éteindre les feux voisins
for (Position firePosition : neighborFirePositions) {
extinguish(firePosition);
modifiedPositions.add(firePosition); // Ajout des feux éteints dans la liste des positions modifiées
}
} else {
// Si la position n'est pas valide, le pompier reste sur place
newFirefighterPositions.add(firefighterPosition);
System.out.println("Pompier ne peut pas se déplacer à " + newFirefighterPosition + ", il reste à " + firefighterPosition);
}
}
// Mettre à jour la liste des positions des pompiers
firefighterPositions = newFirefighterPositions;
return modifiedPositions;
}
public List<Position> updateMotorized() {
List<Position> modifiedPositions = new ArrayList<>();
List<Position> newPositions = new ArrayList<>();
for (Position currentPosition : motorizedFighters) {
// Vérification de validité de la position actuelle
if (!neighbors.containsKey(currentPosition)) {
System.err.println("Position actuelle invalide : " + currentPosition);
newPositions.add(currentPosition);
continue;
}
// Étape 1 : Calcul du premier déplacement
Position firstStep = targetStrategy.neighborClosestToTarget(currentPosition, firePositions, neighbors);
if (firstStep == null || !neighbors.containsKey(firstStep)) {
// Aucun déplacement possible, rester sur place
System.out.println("Pas de première étape possible pour : " + currentPosition);
newPositions.add(currentPosition);
continue;
}
// Étape 2 : Calcul du deuxième déplacement
Position secondStep = targetStrategy.neighborClosestToTarget(firstStep, firePositions, neighbors);
Position finalPosition = (secondStep != null && neighbors.containsKey(secondStep)) ? secondStep : firstStep;
// Ajout de la position finale aux nouvelles positions
newPositions.add(finalPosition);
// Mise à jour des positions modifiées
modifiedPositions.add(currentPosition); // Ancienne position
modifiedPositions.add(finalPosition); // Nouvelle position
// Étape 3 : Éteindre les feux à la position finale
extinguish(finalPosition);
extinguishNearbyFires(finalPosition, modifiedPositions);
}
// Mettre à jour les positions globales
motorizedFighters = newPositions;
return modifiedPositions;
}
/**
* Éteint les feux à proximité d'une position donnée.
*
* @param firefighterPosition La position actuelle du pompier.
* @param modifiedPositions Les positions modifiées pendant ce tour.
*/
private void extinguishNearbyFires(Position firefighterPosition, List<Position> modifiedPositions) {
List<Position> nearbyFires = neighbors.getOrDefault(firefighterPosition, Collections.emptyList())
.stream()
.filter(firePositions::contains)
.toList();
for (Position fire : nearbyFires) {
firePositions.remove(fire);
modifiedPositions.add(fire);
System.out.println("Feu éteint à : " + fire);
}
}
private void extinguish(Position position) {
firePositions.remove(position);
}
public Set<Position> getFirePositions() {
return firePositions;
}
public List<Position> getFirefighterPositions() {
return firefighterPositions;
}
public void incrementStep() {
step++;
}
@Override
public int stepNumber() {
return step;
}
@Override
public List<Position> updateToNextGeneration() {
List<Position> modifiedPositions = updateFirefighters();
modifiedPositions.addAll(updateFires());
modifiedPositions.addAll(updateClouds());
modifiedPositions.addAll(updateMotorized());
incrementStep();
return modifiedPositions;
}
@Override
public void reset() {
this.step=0;
}
public List<Position> updateClouds() {
List<Position> modifiedPositions = new ArrayList<>();
List<Position> newCloudPositions = new ArrayList<>();
for (Position cloudPosition : cloudPositions) {
// Déplacement aléatoire
List<Position> possibleMoves = neighbors.get(cloudPosition);
Position newCloudPosition = possibleMoves.get(new Random().nextInt(possibleMoves.size()));
// Vérification que le nuage ne se déplace pas vers une montagne
if (!canMoveTo(newCloudPosition, firePositions, firefighterPositions)) {
continue; // Si la position est invalide ou une montagne, le nuage reste sur place
}
newCloudPositions.add(newCloudPosition);
// Éteindre le feu à la position du nuage (le nuage mange le feu)
if (firePositions.contains(newCloudPosition)) {
extinguish(newCloudPosition); // Supprimer le feu
modifiedPositions.add(newCloudPosition); // Ajouter la position du feu éteint aux positions modifiées
System.out.println("Feu éteint par nuage à : " + newCloudPosition);
}
modifiedPositions.add(cloudPosition); // Ajouter l'ancienne position du nuage
modifiedPositions.add(newCloudPosition); // Ajouter la nouvelle position du nuage
}
cloudPositions = newCloudPositions;
return modifiedPositions;
}
public List<Position> getCloudPositions() {
return cloudPositions;
}
public List<Position> getMotorizedFighters() {
return motorizedFighters;
}
private void generateMountainBlocks(int rowCount, int columnCount) {
Random random = new Random();
int maxMountains = 5; // Par exemple, générer 5 blocs de montagnes
int blockSize = 4; // Taille du bloc de montagnes (4 cases)
for (int i = 0; i < maxMountains; i++) {
// Générer un coin aléatoire pour chaque bloc de montagne (en s'assurant que les blocs ne dépassent pas la grille)
int startRow = random.nextInt(rowCount - 1); // -1 pour éviter le débordement
int startCol = random.nextInt(columnCount - 1);
// Vérifier si les cases sont libres avant d'y placer une montagne
if (canPlaceMountainBlock(startRow, startCol)) {
// Placer les montagnes sur la grille
placeMountainBlock(startRow, startCol);
}
}
}
private boolean canPlaceMountainBlock(int startRow, int startCol) {
// Vérifier si les 4 cases sont libres
for (int row = startRow; row < startRow + 2; row++) {
for (int col = startCol; col < startCol + 2; col++) {
Position pos = new Position(row, col);
if (terrainMap.containsKey(pos)) {
return false; // Une case est déjà occupée
}
}
}
return true; // Toutes les cases sont libres
}
private void placeMountainBlock(int startRow, int startCol) {
// Placer les 4 cases de montagne
for (int row = startRow; row < startRow + 2; row++) {
for (int col = startCol; col < startCol + 2; col++) {
Position pos = new Position(row, col);
terrainMap.put(pos, new Mountain(pos));
}
}
}
public Map<Position, Terrain> getTerrainMap() {
return terrainMap;
}
public boolean canMoveTo(Position position, Set<Position> firePositions, List<Position> firefighterPositions) {
// Vérifie si la position est hors des limites (par exemple, en dehors de la grille ou inaccessible)
if (!neighbors.containsKey(position)) {
return false;
}
// Si la position est occupée par un feu et que le terrain n'est pas traversable par le feu
if (firePositions.contains(position)) {
return false; // Impossible de traverser une case contenant un feu
}
// Si la position est occupée par un pompier et que le pompier ne peut pas franchir
if (firefighterPositions.contains(position)) {
return false; // Impossible de se déplacer sur la position d'un autre pompier
}
// Si la position est une montagne, aucun élément ne peut la franchir sauf les nuages
if (terrainMap.get(position) != null && !cloudPositions.contains(position)) {
return false; // Impossible de franchir une montagne, sauf pour un nuage
}
return true; // La position est traversable
}
private void generateRoads(int rowCount, int columnCount) {
Random random = new Random();
int maxRoads = 3; // Par exemple, générer 3 routes
int roadLength = 5; // Longueur de chaque route (5 cases)
for (int i = 0; i < maxRoads; i++) {
int startRow = random.nextInt(rowCount); // L'index de départ de la route
int startCol = random.nextInt(columnCount);
// Créer une route uniquement si la position est valide
if (canPlaceRoad(startRow, startCol, roadLength,columnCount)) {
placeRoad(startRow, startCol, roadLength);
}
}
}
private boolean canPlaceRoad(int startRow, int startCol, int roadLength,int columnCount) {
// Vérifier si la ligne droite de la route peut être placée sans dépasser les bords
if (startCol + roadLength > columnCount) { // Vérifie si la route dépasse la largeur de la grille
return false;
}
// Vérifier que toutes les cases sont libres avant de placer la route
for (int i = 0; i < roadLength; i++) {
Position pos = new Position(startRow, startCol + i);
if (terrainMap.containsKey(pos)) {
return false; // Une case est déjà occupée
}
}
return true;
}
private void placeRoad(int startRow, int startCol, int roadLength) {
// Placer une route (ligne droite) sur la grille
for (int i = 0; i < roadLength; i++) {
Position pos = new Position(startRow, startCol + i);
terrainMap.put(pos, new Road(pos)); // Placer une route à chaque case
}
}
}
package model;
import util.Position;
import java.util.List;
import java.util.Map;
public class BoardFirefighterProperties implements BoardProperties{
private final int rowCount;
private final int columnCount;
private final Position[][] positions;
public BoardFirefighterProperties(int rowCount, int columnCount) {
this.rowCount = rowCount;
this.columnCount = columnCount;
this.positions = new Position[rowCount][columnCount];
initializePositions();
}
private void initializePositions() {
for (int row = 0; row < rowCount; row++) {
for (int column = 0; column < columnCount; column++) {
positions[row][column] = new Position(row, column);
}
}
}
public Position getPosition(int row, int column) {
return positions[row][column];
}
@Override
public int rowCount() {
return rowCount;
}
@Override
public int columnCount() {
return columnCount;
}
}
package model;
import util.Position;
import java.util.List;
/**
* Interface représentant les propriétés d'un tableau générique pour la gestion de l'état.
*
* @param <S> Le type d'état utilisé pour les éléments du tableau.
*/
public interface BoardProperties<S> {
/**
* Retourne le nombre de lignes du tableau.
*
* @return Le nombre de lignes.
*/
int rowCount(); // Nombre de lignes.
/**
* Retourne le nombre de colonnes du tableau.
*
* @return Le nombre de colonnes.
*/
int columnCount(); // Nombre de colonnes.
}
package model;
import model.BoardElement;
import util.Position;
public class Cloud extends BoardElement {
public Cloud(Position position) {
super(position);
}
@Override
public String getType() {
return "CLOUD";
}
@Override
public String toString() {
return "Cloud at " + position;
}
}
package model;
import util.Position;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class CloudFactory implements ElementFactory<Cloud>, PositionGenerator {
private final Random random;
private final int count;
public CloudFactory(Random random, int count) {
this.random = random;
this.count = count;
}
@Override
public List<Cloud> createElements(int rowCount, int columnCount) {
List<Cloud> clouds = new ArrayList<>();
for (int i = 0; i < count; i++) {
Position position = generateRandomPosition(rowCount, columnCount);
clouds.add(new Cloud(position));
}
return clouds;
}
@Override
public int getCount() {
return 0;
}
@Override
public Position generateRandomPosition(int rowCount, int columnCount) {
int row = random.nextInt(rowCount);
int col = random.nextInt(columnCount);
return new Position(row, col);
}
}
package model;
import java.util.List;
public interface ElementFactory<T extends ModelElement> {
List<T> createElements(int rowCount, int columnCount);
int getCount();
}
package model;
import util.Position;
public class Fire extends BoardElement{
public Fire(Position position) {
super(position);
}
@Override
public String getType() {
return "FIRE";
}
@Override
public String toString() {
return "Fire{" +
"position=" + position +
'}';
}
}
package model;
import util.Position;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class FireFactory implements ElementFactory<Fire>,PositionGenerator{
private final Random random;
private int count;
public FireFactory(Random random, int count) {
this.random = random; // Injecte un générateur aléatoire pour une flexibilité.
this.count=count;
}
/**
* Crée une liste de feux avec des positions et intensités aléatoires.
*
* @param rowCount Nombre de lignes du plateau.
* @param columnCount Nombre de colonnes du plateau.
* @return Une liste d'objets `Fire`.
*/
public List<Fire> createElements(int rowCount, int columnCount) {
List<Fire> fires = new ArrayList<>();
for (int i = 0; i < count; i++) {
Position randomPosition = generateRandomPosition(rowCount, columnCount);
boolean add = fires.add(new Fire(randomPosition));
}
return fires;
}
/**
* Génère une position aléatoire sur le plateau.
*
* @param rowCount Nombre de lignes.
* @param columnCount Nombre de colonnes.
* @return Une position aléatoire.
*/
@Override
public Position generateRandomPosition(int rowCount, int columnCount) {
int row = random.nextInt(rowCount);
int column = random.nextInt(columnCount);
return new Position(row, column);
}
public int getCount() {
return count;
}
}
package model;
import util.Position;
public class FireFighter extends BoardElement{
public FireFighter(Position position) {
super(position);
}
@Override
public String getType() {
return "FIREFIGHTER";
}
@Override
public String toString() {
return "Firefighter at " + position;
}
}
......@@ -4,29 +4,35 @@ 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 BoardFireFighterBehavior behavior;
private final BoardFirefighterProperties properties;
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++)
public FirefighterBoard(int columnCount, int rowCount, int initialFireCount, int initialFirefighterCount,int initialCloud,int initialMotorized) {
Map<Position, List<Position>> neighbors = initializeNeighbors(rowCount, columnCount);
this.properties = new BoardFirefighterProperties(rowCount, columnCount);
this.behavior = new BoardFireFighterBehavior(neighbors,new FireFactory(randomGenerator,initialFireCount),new FirefighterFactory(randomGenerator,initialFirefighterCount),
new CloudFactory(randomGenerator,initialCloud),new MotorizedFactory(randomGenerator,initialMotorized));
behavior.initializeElements( properties.rowCount(), properties.columnCount());
}
private Map<Position, List<Position>> initializeNeighbors(int rowCount, int columnCount) {
Map<Position, List<Position>> neighbors = new HashMap<>();
Position[][] positions = new Position[rowCount][columnCount];
for (int row = 0; row < rowCount; row++) {
for (int column = 0; column < columnCount; column++) {
positions[row][column] = new Position(row, column);
for (int column = 0; column < columnCount; column++)
}
}
for (int row = 0; row < rowCount; row++) {
for (int column = 0; column < columnCount; column++) {
List<Position> list = new ArrayList<>();
if (row > 0) list.add(positions[row - 1][column]);
if (column > 0) list.add(positions[row][column - 1]);
......@@ -34,114 +40,72 @@ public class FirefighterBoard implements Board<List<ModelElement>> {
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));
return neighbors;
}
@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;
}
// Filtrage des éléments Fire (en transformant les positions en objets Fire)
behavior.getFirePositions().stream()
.filter(pos -> pos.isAtPosition(position)) // Vérifier si la position correspond
.forEach(pos -> result.add(new Fire(pos))); // Créer un objet Fire à partir de Position
// Filtrage des éléments Firefighter (en transformant les positions en objets FireFighter)
behavior.getFirefighterPositions().stream()
.filter(pos -> pos.isAtPosition(position)) // Vérifier si la position correspond
.forEach(pos -> result.add(new FireFighter(pos))); // Créer un objet Firefighter à partir de Position
// Filtrage des éléments Cloud
behavior.getCloudPositions().stream()
.filter(pos -> pos.isAtPosition(position))
.forEach(pos -> result.add(new Cloud(pos)));
// Filtrage des éléments Motorized
behavior.getMotorizedFighters().stream()
.filter(pos -> pos.isAtPosition(position))
.forEach(pos -> result.add(new MotorizedFireFighter(pos)));
behavior.getTerrainMap().forEach((pos, value) -> {
if (pos.isAtPosition(position) && value instanceof Mountain) {
result.add((Mountain) value); // Ajouter uniquement un objet Mountain
}
});
behavior.getTerrainMap().forEach((pos, value) -> {
if (pos.isAtPosition(position) && value instanceof Road) {
result.add((Road) value); // Ajouter uniquement un objet Mountain
}
});
@Override
public int columnCount() {
return columnCount;
return result;
}
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);
public void reset() {
behavior.reset();
behavior.initializeElements(properties.rowCount(), properties.columnCount());
}
return modifiedPositions;
public void setState(List<ModelElement> state, Position position) {
// Pour chaque élément dans l'état, on l'ajoute sur le plateau
state.forEach(element -> addElementToBoard(element, position));
}
@Override
public int stepNumber() {
return step;
}
private void addElementToBoard(ModelElement element, Position position) {
if (element instanceof Fire) {
behavior.getFirePositions().add(position); // Ajouter un Fire
} else if (element instanceof FireFighter) {
behavior.getFirefighterPositions().add(position); // Ajouter un Firefighter
} else if (element instanceof Cloud) {
behavior.getCloudPositions().add(position);
} else if (element instanceof MotorizedFireFighter) {
behavior.getMotorizedFighters().add(position);
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);
public BoardFireFighterBehavior getBehavior() {
return behavior;
}
@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);
}
}
public BoardFirefighterProperties getProperties() {
return properties;
}
}
package model;
import util.Position;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class FirefighterFactory implements ElementFactory<FireFighter>, PositionGenerator{
private final Random random;
private int count;
public FirefighterFactory(Random random,int count) {
this.random = random;
this.count=count;
}
@Override
public List<FireFighter> createElements(int rowCount, int columnCount) {
List<FireFighter> firefighters = new ArrayList<>();
for (int i = 0; i < count; i++) {
Position randomPosition = generateRandomPosition(rowCount, columnCount);
firefighters.add(new FireFighter(randomPosition));
}
return firefighters;
}
@Override
public Position generateRandomPosition(int rowCount, int columnCount) {
int row = random.nextInt(rowCount);
int column = random.nextInt(columnCount);
return new Position(row, column);
}
public int getCount() {
return count;
}
}