Skip to content
Snippets Groups Projects
Select Git revision
  • f996b97f3c75ed73409b15f142f45a746ddc6eeb
  • main default protected
  • melissa
  • yanis
  • variant
5 results

DirectionUtils.java

Blame
  • Forked from COUETOUX Basile / FirefighterStarter
    Source project has a limited visibility.
    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;
        }
    }