diff --git a/src/main/java/app/SimulatorApplication.java b/src/main/java/app/SimulatorApplication.java index 076797034356054523760c0b7cca79e2446b762a..e599a547f731aa93c242499313608944adfc7883 100644 --- a/src/main/java/app/SimulatorApplication.java +++ b/src/main/java/app/SimulatorApplication.java @@ -13,16 +13,16 @@ import javafx.stage.Stage; public class SimulatorApplication extends javafx.application.Application { private static final String VIEW_RESOURCE_PATH = "/view/view.fxml"; private static final String APP_NAME = "Firefighter simulator"; - private static final int ROW_COUNT = 40; - private static final int COLUMN_COUNT = 40; - private static final int BOX_WIDTH = 15; - private static final int BOX_HEIGHT = 15; - public static final int INITIAL_FIRE_COUNT = 4; - public static final int INITIAL_FIREFIGHTER_COUNT = 18; - public static final int INITIAL_MOTORIZED_FIREFIGHTER_COUNT = 5; - public static final int INITIAL_CLOUD_COUNT = 9; - public static final int INITIAL_MOUNTAIN_COUNT= 18; - public static final int TURNS_FOR_SPAWNING_AIRTANKER = 8; + private static final int ROW_COUNT = 80; + private static final int COLUMN_COUNT = 80; + private static final int BOX_WIDTH = 8; + private static final int BOX_HEIGHT = 8; + public static final int INITIAL_FIRE_COUNT = 6; + public static final int INITIAL_FIREFIGHTER_COUNT = 32; + public static final int INITIAL_MOTORIZED_FIREFIGHTER_COUNT = 10; + public static final int INITIAL_CLOUD_COUNT = 15; + public static final int INITIAL_MOUNTAIN_COUNT= 28; + public static final int TURNS_FOR_SPAWNING_AIRTANKER = 4; private Stage primaryStage; private Parent view; diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java index ae28563066b8de289df950dac99fb61a437c3379..f77e3487811237db97b10afc8d9fa3fd221a28c9 100644 --- a/src/main/java/controller/Controller.java +++ b/src/main/java/controller/Controller.java @@ -128,7 +128,7 @@ public class Controller { int rowCount, int initialFireCount, int initialFirefighterCount, int initialMotorizedFirefightersCount, int initialcloudCount, int initialmountaincount, int turnsForSpawningAirTanker) { grid.setDimensions(columnCount, rowCount, squareWidth, squareHeight); Board<Square> model = new FireFighterScenario(columnCount, rowCount); - Map<EntityFactory, Integer> entityCounts = new HashMap<>(); + Map<EntityFactory, Integer> entityCounts = new HashMap<EntityFactory, Integer>(); entityCounts.put((pos, b) -> new Fire(pos), initialFireCount); entityCounts.put((pos, b) -> new FireFighter(pos, b), initialFirefighterCount); diff --git a/src/main/java/model/EntitySpawner.java b/src/main/java/model/EntitySpawner.java index 475625f36ee2ac40cb629dfc0906adb01371aca7..c8f0de6aaa1e51b620125129ff323268c92f6d96 100644 --- a/src/main/java/model/EntitySpawner.java +++ b/src/main/java/model/EntitySpawner.java @@ -1,12 +1,16 @@ package model; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.Set; +import util.Direction; import util.Position; public class EntitySpawner { @@ -68,4 +72,198 @@ public class EntitySpawner { } return positions; } + + public static void generateEntitiesInLine(Board<Square> board, Position anchor, EntityFactory entityFactory) { + int xIncrement = 0; + int yIncrement = 0; + + // Determine increments based on which coordinate is zero + if (anchor.x() == 0 && anchor.y() >= 0) { + // Starting from the left edge (x == 0), increment x to move right + xIncrement = 1; + } else if (anchor.y() == 0 && anchor.x() >= 0) { + // Starting from the top edge (y == 0), increment y to move down + yIncrement = 1; + } else { + // If neither x nor y is 0, cannot determine direction + throw new IllegalArgumentException("Anchor position must have x or y equal to 0"); + } + + int x = anchor.x(); + int y = anchor.y(); + + // Continue until we reach the edge of the board + while (board.doesPositionExist(new Position(x, y))) { + Position pos = new Position(x, y); + // Create a new entity for each position + Entity entity = entityFactory.create(pos, board); + entity.setPosition(pos); // Set the position if not already set in the factory + board.addEntityAtSquare(entity, pos); + + x += xIncrement; + y += yIncrement; + } + } + + public static List<Position> generateEntitiesInRandomLine(Board<Square> board, Position anchor, int maxStepsInDirection, int minimumRoadLength) { + Random random = new Random(); + List<Position> path = new ArrayList<>(); + int x = anchor.x(); + int y = anchor.y(); + + // Toutes les directions possibles + List<Direction> allDirections = Arrays.asList(Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST); + + // Choisir une direction initiale aléatoire + Direction initialDirection = allDirections.get(random.nextInt(allDirections.size())); + path.add(new Position(x, y)); // Ajouter la position de l'ancre au chemin + int roadLength = 1; + + // Déterminer la direction interdite (opposée à la direction initiale) + Direction forbiddenDirection = getOppositeDirection(initialDirection); + + // Initialiser la direction courante + Direction currentDirection = initialDirection; + int stepsInCurrentDirection = 0; + + // Ensemble des directions définitivement exclues (direction initiale) + Set<Direction> permanentlyExcludedDirections = new HashSet<>(); + permanentlyExcludedDirections.add(initialDirection); + + // Ensemble des directions temporairement exclues (initialement vide) + Set<Direction> temporarilyExcludedDirections = new HashSet<>(); + + while (true) { + // Calculer la prochaine position dans la direction courante + int nextX = x + getXIncrement(currentDirection); + int nextY = y + getYIncrement(currentDirection); + Position nextPos = new Position(nextX, nextY); + + if (board.doesPositionExist(nextPos)) { + // Ajouter la position au chemin + path.add(nextPos); + x = nextX; + y = nextY; + roadLength++; + stepsInCurrentDirection++; + } else { + // La position dans la direction courante est invalide + if (roadLength < minimumRoadLength) { + // Exclure temporairement la direction courante + temporarilyExcludedDirections.add(currentDirection); + + // Choisir une nouvelle direction valide + Direction newDirection = chooseNewDirection(allDirections, currentDirection, forbiddenDirection, + permanentlyExcludedDirections, temporarilyExcludedDirections, board, x, y, random); + + if (newDirection == null) { + // Aucune direction valide disponible pour atteindre la longueur minimale + break; + } + + // Mettre à jour la direction courante + currentDirection = newDirection; + forbiddenDirection = getOppositeDirection(currentDirection); + stepsInCurrentDirection = 0; + continue; // Recommencer avec la nouvelle direction + } else { + // La longueur minimale est atteinte, arrêter la génération + break; + } + } + + // Vérifier s'il est temps de changer de direction + if (stepsInCurrentDirection >= maxStepsInDirection) { + // Choisir une nouvelle direction + Direction newDirection = chooseNewDirection(allDirections, currentDirection, forbiddenDirection, + permanentlyExcludedDirections, temporarilyExcludedDirections, board, x, y, random); + + if (newDirection == null) { + // Aucune direction valide disponible + break; + } + + // Mettre à jour la direction courante + currentDirection = newDirection; + forbiddenDirection = getOppositeDirection(currentDirection); + stepsInCurrentDirection = 0; + } + } + + return path; // Retourner la liste des positions formant le serpent + } + + /** + * Choisit une nouvelle direction valide en tenant compte des exclusions permanentes et temporaires. + * + * @param allDirections Toutes les directions possibles. + * @param currentDirection La direction actuelle. + * @param forbiddenDirection La direction opposée à la direction actuelle (interdite). + * @param permanentlyExcludedDirections Les directions définitivement exclues. + * @param temporarilyExcludedDirections Les directions temporairement exclues. + * @param board Le plateau de jeu. + * @param x La coordonnée X actuelle. + * @param y La coordonnée Y actuelle. + * @param random Une instance de Random pour le choix aléatoire. + * @return La nouvelle direction choisie ou null si aucune direction valide n'est disponible. + */ + private static Direction chooseNewDirection(List<Direction> allDirections, Direction currentDirection, Direction forbiddenDirection, + Set<Direction> permanentlyExcludedDirections, Set<Direction> temporarilyExcludedDirections, + Board<Square> board, int x, int y, Random random) { + // Créer une liste de directions valides en excluant : + // - La direction actuelle + // - La direction interdite (opposée à la direction actuelle) + // - Les directions définitivement exclues + // - Les directions temporairement exclues + List<Direction> validDirections = new ArrayList<>(allDirections); + validDirections.remove(currentDirection); + validDirections.remove(forbiddenDirection); + validDirections.removeAll(permanentlyExcludedDirections); + validDirections.removeAll(temporarilyExcludedDirections); + + // Filtrer les directions qui permettent de continuer le chemin + validDirections.removeIf(dir -> !board.doesPositionExist(new Position(x + getXIncrement(dir), y + getYIncrement(dir)))); + + if (validDirections.isEmpty()) { + // Aucune direction valide disponible + return null; + } + + // Choisir une nouvelle direction aléatoirement + return validDirections.get(random.nextInt(validDirections.size())); + } + + private static int getXIncrement(Direction direction) { + switch (direction) { + case NORTH: return -1; + case SOUTH: return 1; + default: return 0; + } + } + + private static int getYIncrement(Direction direction) { + switch (direction) { + case EAST: return 1; + case WEST: return -1; + default: return 0; + } + } + + private static Direction getOppositeDirection(Direction direction) { + switch (direction) { + case NORTH: return Direction.SOUTH; + case SOUTH: return Direction.NORTH; + case EAST: return Direction.WEST; + case WEST: return Direction.EAST; + default: throw new IllegalArgumentException("Direction non supportée : " + direction); + } + } + + + + + + + + } diff --git a/src/main/java/model/Fire.java b/src/main/java/model/Fire.java index 8ad742e43ce3525c074b75b49b218e56cdbf49fd..0ff0b1883e56388eb72e8347ec20115990552f7b 100644 --- a/src/main/java/model/Fire.java +++ b/src/main/java/model/Fire.java @@ -56,7 +56,7 @@ public class Fire implements Entity { } // Skip if the position contains a Cloud (if clouds prevent fire spread) - if (board.doesSquareContainEntity(p, Cloud.class)) { + if (board.doesSquareContainEntity(p, Road.class)) { continue; } diff --git a/src/main/java/model/FireFighterScenario.java b/src/main/java/model/FireFighterScenario.java index f48e74465b29f6110b07ab257f54772f1ae299d6..8be76438beec260d42b7ad1a5a59feb74b4d61f6 100644 --- a/src/main/java/model/FireFighterScenario.java +++ b/src/main/java/model/FireFighterScenario.java @@ -7,6 +7,7 @@ import java.util.Map; import java.util.Random; import util.Matrix; +import util.PathGenerator; import util.Position; import util.PositionUtil; @@ -23,12 +24,12 @@ public class FireFighterScenario extends EntityScenario implements Board<Square> this.step = 0; } -public void placeInitialEntities(Map<EntityFactory, Integer> entityCounts) { + public void placeInitialEntities(Map<EntityFactory, Integer> entityCounts) { EntitySpawner spawner = new EntitySpawner(this); spawner.spawnEntities(entityCounts); + generateRoads(); this.initialMap = entityCounts; -} - + } public Square getStates(Position position) { if (position.x() > matrix.size() || position.y() > matrix.size()) { @@ -62,7 +63,6 @@ public void placeInitialEntities(Map<EntityFactory, Integer> entityCounts) { } } - public int rowCount() { return matrix.getRows(); } @@ -81,24 +81,24 @@ public void placeInitialEntities(Map<EntityFactory, Integer> entityCounts) { Iterator<Square> iterator = matrix.iterator(); while (iterator.hasNext()) { - Square s = iterator.next(); - if (s.isEmpty()) - continue; - if (s.getMaxAge() == 0) { - s.incrementAllAges(); - continue; - } - if (s.getMaxAge() == step + 1) { - continue; - } - List<Entity> entities = new ArrayList<>(s.getEntities()); - for (Entity e : entities) { - if(e.getAge() >= stepNumber()-1){ - continue; - } - e.incrementAge(); - changedPositions.addAll(e.nextTurn(this)); + Square s = iterator.next(); + if (s.isEmpty()) + continue; + if (s.getMaxAge() == 0) { + s.incrementAllAges(); + continue; + } + if (s.getMaxAge() == step + 1) { + continue; + } + List<Entity> entities = new ArrayList<>(s.getEntities()); + for (Entity e : entities) { + if (e.getAge() >= stepNumber() - 1) { + continue; } + e.incrementAge(); + changedPositions.addAll(e.nextTurn(this)); + } } // Increment the step counter @@ -106,49 +106,45 @@ public void placeInitialEntities(Map<EntityFactory, Integer> entityCounts) { // Check if it's time to spawn an AirTanker if (this.step % 8 == 0) { - // Spawn an AirTanker at a random edge position - spawnAirTanker(changedPositions); + // Spawn an AirTanker at a random edge position + spawnAirTanker(changedPositions); } return changedPositions; -} + } -// Helper method to spawn an AirTanker -private void spawnAirTanker(List<Position> changedPositions) { - System.out.println("Spawning AirTanker"); - Random rand = new Random(); - int edge = rand.nextInt(4); // 0: top, 1: bottom, 2: left, 3: right - Position position = null; + // Helper method to spawn an AirTanker + private void spawnAirTanker(List<Position> changedPositions) { + Random rand = new Random(); + int edge = rand.nextInt(4); // 0: top, 1: bottom, 2: left, 3: right + Position position = null; - if (edge == 0) { // Top edge (x == 0) - int y = rand.nextInt(columnCount()-1); + if (edge == 0) { // Top edge (x == 0) + int y = rand.nextInt(columnCount() - 1); position = new Position(0, y); - } else if (edge == 1) { // Bottom edge (x == rowCount() - 1) + } else if (edge == 1) { // Bottom edge (x == rowCount() - 1) int y = rand.nextInt(columnCount()); position = new Position(rowCount() - 1, y); - } else if (edge == 2) { // Left edge (y == 0) - int x = rand.nextInt(rowCount()-1); + } else if (edge == 2) { // Left edge (y == 0) + int x = rand.nextInt(rowCount() - 1); position = new Position(x, 0); - } else if (edge == 3) { // Right edge (y == columnCount() - 1) - int x = rand.nextInt(rowCount()-1); - position = new Position(x, columnCount() -1); - } else { - // This else block is technically not necessary because edge will always be between 0 and 3 + } else if (edge == 3) { // Right edge (y == columnCount() - 1) + int x = rand.nextInt(rowCount() - 1); + position = new Position(x, columnCount() - 1); + } else { + // This else block is technically not necessary because edge will always be + // between 0 and 3 throw new IllegalStateException("Unexpected edge value: " + edge); - } - - System.out.println("Position: " + position.toString()); - // Create a new AirTanker - AirTanker airTanker = new AirTanker(position, this, getStepNumber()); - System.out.println(" direction : " + airTanker.getDirection()); - // Add the AirTanker to the board - addEntityAtSquare(airTanker, position); - - // Record the changed position - changedPositions.add(position); -} + } + // Create a new AirTanker + AirTanker airTanker = new AirTanker(position, this, getStepNumber()); + // Add the AirTanker to the board + addEntityAtSquare(airTanker, position); + // Record the changed position + changedPositions.add(position); + } public Position getNearestEntity(Position fromPos, Class<?> entityType) { int rows = matrix.getRows(); @@ -210,11 +206,53 @@ private void spawnAirTanker(List<Position> changedPositions) { @Override public boolean isPositionFree(Position position, int priority) { List<Entity> entities = matrix.get(position.x(), position.y()).getEntities(); - for(Entity e : entities){ - if(e.getPriority() == priority){ + for (Entity e : entities) { + if (e.getPriority() == priority) { return false; } } return true; } + + private void generateRoads() { + if(columnCount() < 10 || rowCount() < 10){ + return; + } + Random random = new Random(); + + // Get board dimensions + int rowCount = rowCount(); // Number of rows (vertical axis) + int columnCount = columnCount(); // Number of columns (horizontal axis) + + // Decide randomly whether to set x or y to 0 + boolean setXToZero = random.nextBoolean(); + + int x = 0; + int y = 0; + + if (setXToZero) { + // x is set to 0, y is random within column bounds + x = 0; + y = random.nextInt(columnCount); + } else { + // y is set to 0, x is random within row bounds + x = random.nextInt(rowCount); + y = 0; + } + + Position startPosition = new Position(x, y); + PathGenerator pathGenerator = new PathGenerator(this, startPosition, 4, columnCount()); + // Call generateEntitiesInLine to place the roads + List<Position> snake = pathGenerator.generate(); + for(Position p : snake){ + List<Entity> entitiesAtSquare = List.copyOf(getStates(p).getEntities()); + for(Entity e: entitiesAtSquare){ + if(e instanceof Mountain){ + clearCaseFrom(e, e.getPosition()); + } + } + addEntityAtSquare(new Road(p), p); + } +} + } diff --git a/src/main/java/model/Road.java b/src/main/java/model/Road.java new file mode 100644 index 0000000000000000000000000000000000000000..aacbd8e7a3d4f9408c550a73e57f25093f3df0dd --- /dev/null +++ b/src/main/java/model/Road.java @@ -0,0 +1,57 @@ +package model; + +import java.util.List; + +import javafx.scene.paint.Color; +import util.Position; + +public class Road implements Entity{ + private int age; + private final int PRIORITY = 0; + private final Color VIEW_COLOR = Color.BLACK; + private Position position; + + public Road(Position position){ + this.position = position; + } + @Override + public List<Position> nextTurn(Board<Square> board) { + return List.of(); + } + + @Override + public Position getPosition() { + return this.position; + } + + @Override + public void setPosition(Position p) { + this.position = p; + } + + @Override + public int getAge() { + return age; + } + + @Override + public void setAge(int age) { + this.age = age; + } + + @Override + public void incrementAge() { + this.age = age + 1; + } + + @Override + public Color getViewColor() { + return this.VIEW_COLOR; + } + + @Override + public int getPriority() { + return this.PRIORITY; + } + +} diff --git a/src/main/java/util/DirectionUtils.java b/src/main/java/util/DirectionUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..f1daaeac1941f5fc6437868f42fa709ba2bc2bf0 --- /dev/null +++ b/src/main/java/util/DirectionUtils.java @@ -0,0 +1,109 @@ +package util; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; + +import model.Board; +import model.Square; + +public class DirectionUtils { + + /** + * Obtient l'incrément sur l'axe X pour une direction donnée. + * + * @param direction La direction. + * @return L'incrément sur l'axe X. + */ + public static int getXIncrement(Direction direction) { + switch (direction) { + case NORTH: + return -1; + case SOUTH: + return 1; + default: + return 0; + } + } + + /** + * Obtient l'incrément sur l'axe Y pour une direction donnée. + * + * @param direction La direction. + * @return L'incrément sur l'axe Y. + */ + public static int getYIncrement(Direction direction) { + switch (direction) { + case EAST: + return 1; + case WEST: + return -1; + default: + return 0; + } + } + + /** + * Obtient la direction opposée. + * + * @param direction La direction actuelle. + * @return La direction opposée. + */ + public static Direction getOpposite(Direction direction) { + switch (direction) { + case NORTH: + return Direction.SOUTH; + case SOUTH: + return Direction.NORTH; + case EAST: + return Direction.WEST; + case WEST: + return Direction.EAST; + default: + throw new IllegalArgumentException("Direction non supportée : " + direction); + } + } + + /** + * Choisit une direction aléatoire parmi toutes les directions disponibles. + * + * @param random Instance de Random. + * @return Une direction aléatoire. + */ + public static Direction getRandomDirection() { + Random r = new Random(); + Direction[] directions = Direction.values(); + return directions[r.nextInt(directions.length)]; + } + + /** + * Obtient les directions valides en fonction des exclusions et de la position actuelle. + * + * @param currentDirection La direction actuelle. + * @param permanentlyExcludedDirections Les directions définitivement exclues. + * @param temporarilyExcludedDirections Les directions temporairement exclues. + * @param board Le plateau de jeu. + * @param currentPosition La position actuelle. + * @return Une liste de directions valides. + */ + public static List<Direction> getValidDirections( + Direction currentDirection, + Set<Direction> permanentlyExcludedDirections, + Set<Direction> temporarilyExcludedDirections, + Board<Square> board, + Position currentPosition + ) { + return Arrays.stream(Direction.values()) + .filter(dir -> dir != currentDirection) + .filter(dir -> dir != getOpposite(currentDirection)) + .filter(dir -> !permanentlyExcludedDirections.contains(dir)) + .filter(dir -> !temporarilyExcludedDirections.contains(dir)) + .filter(dir -> { + Position nextPos = currentPosition.move(dir); + return board.doesPositionExist(nextPos); + }) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/util/PathGenerator.java b/src/main/java/util/PathGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..149c4ca1633a286e84915cf3c75c7405607470da --- /dev/null +++ b/src/main/java/util/PathGenerator.java @@ -0,0 +1,189 @@ +package util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +import model.Board; + +public class PathGenerator { + private final Board<?> board; + private final Random random = new Random(); + private final int maxStepsInDirection; + private final int minimumRoadLength; + private final Set<Direction> initialExcludedDirections = new HashSet<>(); + private final Position anchor; + + private Position currentPosition; + private Direction currentDirection; + private Direction excludedDirection = null; + private Direction lastDirection = null; + private int stepsInCurrentDirection = 0; + private int roadLength = 1; + private final List<Position> path = new ArrayList<>(); + + /** + * Constructeur de PathGenerator. + * + * @param board Le plateau de jeu. + * @param anchor La position de départ. + * @param maxStepsInDirection Nombre maximal de pas dans une direction avant de changer. + * @param minimumRoadLength Longueur minimale du chemin. + */ + public PathGenerator(Board<?> board, Position anchor, int maxStepsInDirection, int minimumRoadLength) { + this.board = board; + this.anchor = anchor; + this.maxStepsInDirection = maxStepsInDirection; + this.minimumRoadLength = minimumRoadLength; + initializePath(); + } + + /** + * Génère le chemin en respectant les contraintes. + * + * @return Liste des positions formant le chemin. + */ + public List<Position> generate() { + while (true) { + if (canMoveInCurrentDirection()) { + moveInCurrentDirection(); + if (shouldChangeDirection()) { + if (!changeDirection(false)) break; + } + } else { + if (!handleObstacle()) break; + } + } + return roadLength >= minimumRoadLength ? path : regeneratePath(); + } + + /** Initialise le chemin avec l'ancre et choisit la première direction. */ + private void initializePath() { + path.clear(); + roadLength = 1; + stepsInCurrentDirection = 0; + currentPosition = anchor; + path.add(anchor); + currentDirection = DirectionUtils.getRandomDirection(); + initialExcludedDirections.clear(); + initialExcludedDirections.add(currentDirection); + lastDirection = currentDirection; + excludedDirection = null; + } + + /** Vérifie si le mouvement dans la direction actuelle est possible. */ + private boolean canMoveInCurrentDirection() { + Position nextPosition = currentPosition.move(currentDirection); + return board.doesPositionExist(nextPosition); + } + + /** Effectue le mouvement dans la direction actuelle. */ + private void moveInCurrentDirection() { + currentPosition = currentPosition.move(currentDirection); + path.add(currentPosition); + roadLength++; + stepsInCurrentDirection++; + excludedDirection = DirectionUtils.getOpposite(currentDirection); + } + + /** Détermine si un changement de direction est nécessaire. */ + private boolean shouldChangeDirection() { + return stepsInCurrentDirection >= maxStepsInDirection; + } + + /** + * Change la direction actuelle. + * + * @param mustContinue Si true, la nouvelle direction doit permettre de continuer le chemin. + * @return true si la direction a été changée avec succès, sinon false. + */ + private boolean changeDirection(boolean mustContinue) { + Direction newDirection = chooseNewDirection(mustContinue); + if (newDirection == null) return false; + updateDirection(newDirection); + return true; + } + + /** Gère le cas où le mouvement n'est pas possible (obstacle ou bord du plateau). */ + private boolean handleObstacle() { + if (roadLength < minimumRoadLength) { + return changeDirection(true); + } + return false; + } + + /** Réinitialise et génère à nouveau le chemin. */ + private List<Position> regeneratePath() { + initializePath(); + return generate(); + } + + /** Met à jour la direction actuelle et les compteurs associés. */ + private void updateDirection(Direction newDirection) { + currentDirection = newDirection; + stepsInCurrentDirection = 0; + lastDirection = newDirection; + excludedDirection = DirectionUtils.getOpposite(newDirection); + } + + /** + * Choisit une nouvelle direction valide en tenant compte des exclusions. + * + * @param mustContinue Si true, la direction doit permettre de continuer le chemin. + * @return La nouvelle direction choisie ou null si aucune n'est valide. + */ + private Direction chooseNewDirection(boolean mustContinue) { + Set<Direction> exclusions = new HashSet<>(initialExcludedDirections); + Collections.addAll(exclusions, excludedDirection, lastDirection); + List<Direction> validDirections = getValidDirections(exclusions, currentPosition); + + if (mustContinue) { + validDirections = filterDirectionsToContinue(validDirections, currentPosition); + } + + return validDirections.isEmpty() ? null : validDirections.get(random.nextInt(validDirections.size())); + } + + /** + * Obtient les directions valides à partir de la position actuelle. + * + * @param exclusions Les directions à exclure. + * @param currentPosition La position actuelle. + * @return Liste des directions valides. + */ + private List<Direction> getValidDirections(Set<Direction> exclusions, Position currentPosition) { + List<Direction> validDirections = new ArrayList<>(); + for (Direction dir : Direction.values()) { + if (!exclusions.contains(dir)) { + Position nextPos = currentPosition.move(dir); + if (board.doesPositionExist(nextPos)) { + validDirections.add(dir); + } + } + } + return validDirections; + } + + /** + * Filtre les directions pour s'assurer qu'elles permettent de continuer le chemin. + * + * @param directions Liste des directions valides. + * @param currentPosition La position actuelle. + * @return Liste des directions permettant de continuer. + */ + private List<Direction> filterDirectionsToContinue(List<Direction> directions, Position currentPosition) { + List<Direction> filtered = new ArrayList<>(); + for (Direction dir : directions) { + Position nextPos = currentPosition.move(dir); + Set<Direction> futureExclusions = new HashSet<>(initialExcludedDirections); + futureExclusions.add(DirectionUtils.getOpposite(dir)); + if (!getValidDirections(futureExclusions, nextPos).isEmpty()) { + filtered.add(dir); + } + } + return filtered; + } +} diff --git a/src/main/java/util/Position.java b/src/main/java/util/Position.java index 389b8214dbc56af0914084e8fa7e68cd3c1b2e72..d6407fadb846754bdfb63ef8b4a5966dd78f25e1 100644 --- a/src/main/java/util/Position.java +++ b/src/main/java/util/Position.java @@ -1,5 +1,10 @@ package util; public record Position(int x, int y) { - + // Méthode pour déplacer la position dans une direction donnée + public Position move(Direction direction) { + int newX = this.x + DirectionUtils.getXIncrement(direction); + int newY = this.y + DirectionUtils.getYIncrement(direction); + return new Position(newX, newY); + } } diff --git a/src/main/java/util/PositionUtil.java b/src/main/java/util/PositionUtil.java index 278bf9f0aab3b76154f1d442ba7b001e60c60278..0a3f9011468dbeb11e6b8b2f4fb3549f0f083328 100644 --- a/src/main/java/util/PositionUtil.java +++ b/src/main/java/util/PositionUtil.java @@ -75,8 +75,6 @@ public class PositionUtil { } public static List<Position> generateAdjacentPositions(Position position, Board<Square> board, int distance) { - int x = position.x(); - int y = position.y(); List<Position> positions = new ArrayList<Position>(); for(int i = 0; i < 4; i++){