diff --git a/build/resources/main/view/view.fxml b/build/resources/main/view/view.fxml index 336ffa315645baacbe25bf59171d2ff6d867b9c5..6c1059bd037e38236e9085cf992dd07189f5e9b2 100644 --- a/build/resources/main/view/view.fxml +++ b/build/resources/main/view/view.fxml @@ -1,37 +1,43 @@ <?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" - text="Generation number"/> - <Label fx:id="generationNumberLabel" alignment="CENTER" contentDisplay="TEXT_ONLY" - maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="24.0" prefWidth="200.0"/> + 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"/> + 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" diff --git a/src/main/java/app/SimulatorApplication.java b/src/main/java/app/SimulatorApplication.java index e1778df888e9ea205aeb4139413058be8dccaf5f..86abb8525b4a41c5a54cea60981c01025d5ae3f8 100644 --- a/src/main/java/app/SimulatorApplication.java +++ b/src/main/java/app/SimulatorApplication.java @@ -15,8 +15,8 @@ public class SimulatorApplication extends javafx.application.Application { 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; diff --git a/src/main/java/model/Board.java b/src/main/java/model/Board.java index 30baf946331f02d670790920433df68759e21a07..b25b421b024f35472a35835a972ed5c7dc8b7a26 100644 --- a/src/main/java/model/Board.java +++ b/src/main/java/model/Board.java @@ -64,5 +64,7 @@ public interface Board<S> { // 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); } diff --git a/src/main/java/model/Fire.java b/src/main/java/model/Fire.java index c35008271a0b0c94137ac0a13bef39ff01fcc3ee..7e54fc2b23057479b1f38f1a782d66e9b1b49501 100644 --- a/src/main/java/model/Fire.java +++ b/src/main/java/model/Fire.java @@ -1,4 +1,8 @@ package model; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import javafx.scene.paint.Color; import util.Position; @@ -12,8 +16,27 @@ public class Fire implements Entity{ @Override public void nextTurn(Board<Entity> board) { - + List<Position> positions = generateAdjacentPosition(); + for(Position p : positions){ + board.setState(new Fire(p, board), p); + } } + + 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; diff --git a/src/main/java/model/FireFighter.java b/src/main/java/model/FireFighter.java index aea07f0d517b5183eb7f06da7a7de5bd610d0f59..8a78412d32444566960bf3223c3e832ea5baa3fa 100644 --- a/src/main/java/model/FireFighter.java +++ b/src/main/java/model/FireFighter.java @@ -5,9 +5,11 @@ import util.Position; public class FireFighter implements Entity{ private Position position; private final Color viewColor = Color.BLUE; + private Board<Entity> board; - public FireFighter(Position position){ + public FireFighter(Position position, Board<Entity> b){ this.position = position; + this.board = b; } public void nextTurn(Board<Entity> b){ diff --git a/src/main/java/model/FireFighterScenario.java b/src/main/java/model/FireFighterScenario.java index a01a9dd2e87ec26da6cb4d2fdecb6879dfb16b3d..553307771917db0af9782065e429f4f44abe68de 100644 --- a/src/main/java/model/FireFighterScenario.java +++ b/src/main/java/model/FireFighterScenario.java @@ -1,77 +1,126 @@ 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; +public class FireFighterScenario extends EntityScenario implements Board<Entity> { -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); + 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; } - 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."); + +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), pos); + fireCount++; + if (fireCount == initialFireCount && fireFighterCount == initialFireFightersCount) { + return; + } + continue; + } + + if (fireFighterCount < initialFireFightersCount && random.nextInt(100) < chance) { + setState(new FireFighter(pos, this), 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)){ + public void setState(Entity state, Position position) { + if (!(getState(position) instanceof EmptySquare)) { return; } matrix.set(position.x(), position.y(), state); } - // Le booléen replaceState permet de forcer le remplacement des cases vides - public void setState(Entity state, Position position, boolean replaceStates){ - if(!(getState(position) instanceof EmptySquare) && !replaceStates){ + 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(){ + public int rowCount() { return matrix.getRows(); } - public int columnCount(){ + public int columnCount() { return matrix.getColumns(); } public List<Position> updateToNextGeneration() { ArrayList<Position> changedPositions = new ArrayList<>(); - Iterator<Entity> iterator = matrix.iterator(); + Iterator<Entity> iterator = matrix.iterator(); while (iterator.hasNext()) { - Entity e = iterator.next(); - Position p = new Position(e.getPosition().x(), e.getPosition().y()); - e.nextTurn(this); + Entity e = iterator.next(); + Position p = new Position(e.getPosition().x(), e.getPosition().y()); + e.nextTurn(this); - if (!e.getPosition().equals(p)) { - changedPositions.add(p); - } + if (!e.getPosition().equals(p)) { + changedPositions.add(p); + } } return changedPositions; -} - - + } - public void reset(){ + public void reset() { matrix.clear(); } - - public int stepNumber(){ + public int stepNumber() { this.step++; return this.step; } + + @Override + public boolean doesPositionExist(Position position) { + return matrix.validateIndexes(position); + } } diff --git a/src/main/java/util/Matrix.java b/src/main/java/util/Matrix.java index 38c61097e6aa2fffa56695edf2c0f62b6da1fde5..7d8f97f0c76bfe32264f89cde79a5a3bac5f7346 100644 --- a/src/main/java/util/Matrix.java +++ b/src/main/java/util/Matrix.java @@ -56,6 +56,8 @@ public class Matrix<E> implements Iterable<E> { public int getRows(){ return this.rows; } + /* + public void displayMatrix() { System.out.print(" "); for (int j = 0; j < columns; j++) { @@ -80,12 +82,17 @@ public class Matrix<E> implements Iterable<E> { System.out.println(); } } + */ private void validateIndexes(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 validateIndexes(Position position){ + return position.x() < 0 || position.x() >= rows || position.y() < 0 || position.y() >= columns; + } diff --git a/src/main/resources/view/view.fxml b/src/main/resources/view/view.fxml index 336ffa315645baacbe25bf59171d2ff6d867b9c5..6c1059bd037e38236e9085cf992dd07189f5e9b2 100644 --- a/src/main/resources/view/view.fxml +++ b/src/main/resources/view/view.fxml @@ -1,37 +1,43 @@ <?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" - text="Generation number"/> - <Label fx:id="generationNumberLabel" alignment="CENTER" contentDisplay="TEXT_ONLY" - maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="24.0" prefWidth="200.0"/> + 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"/> + 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" diff --git a/src/test/java/view/FirefighterGridTest.java b/src/test/java/view/FirefighterGridTest.java index 4b45ebdca3b936b42c2b322b1294488341d180bb..dfcdf5d95c5e8c84d974339040ce5e5a836237b7 100644 --- a/src/test/java/view/FirefighterGridTest.java +++ b/src/test/java/view/FirefighterGridTest.java @@ -1,20 +1,20 @@ 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); } }