Select Git revision
WizardTest.java
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
PathGenerator.java 6.90 KiB
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 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();
}
public void setBoard(Board<?> board){
this.board = board;
}
/** Initialise le chemin avec l'ancre et choisit la première direction. */
private void initializePath() {
path.clear();
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;
}
}