package ch.epfl.maze.physical.zoo; import ch.epfl.maze.physical.Animal; import ch.epfl.maze.physical.stragegies.picker.RandomPicker; import ch.epfl.maze.physical.stragegies.reducer.BackwardReducer; import ch.epfl.maze.physical.stragegies.reducer.BlindCaseReducer; import ch.epfl.maze.util.Direction; import ch.epfl.maze.util.Vector2D; import java.util.HashSet; import java.util.Set; /** * Hamster A.I. that remembers the previous choice it has made and the dead ends * it has already met. * * @author EPFL * @author Pacien TRAN-GIRARD */ public class Hamster extends Animal implements BlindCaseReducer, BackwardReducer, RandomPicker { private final Set positionBlacklist; /** * Constructs a hamster with a starting position. * * @param position Starting position of the hamster in the labyrinth */ public Hamster(Vector2D position) { super(position); this.positionBlacklist = new HashSet<>(); } /** * Checks is the choice leads to a known dead end. * * @param choice A Direction * @return T(The given choice does not lead to a blacklisted path) */ @Override public boolean keepChoice(Direction choice) { Vector2D choicePosition = this.getPosition().addDirectionTo(choice); return !this.isPositionBlacklisted(choicePosition); } /** * Filters the Direction choices using the blacklist. * * @param choices A set of Direction choices * @return A subset of choices */ @Override public Set reduce(Set choices) { Set knownChoices = BlindCaseReducer.super.reduce(choices); this.updateBlacklist(knownChoices); return knownChoices.size() > 1 ? BackwardReducer.super.reduce(knownChoices) : knownChoices; } /** * Moves without retracing directly its steps and by avoiding the dead-ends * it learns during its journey. */ @Override public Direction move(Set choices) { Set smartChoices = this.reduce(choices); return this.pick(smartChoices); } @Override public Animal copy() { return new Hamster(this.getPosition()); } /** * Updates the position blacklist if needed. * * @param choices The choices currently available */ private void updateBlacklist(Set choices) { if (this.inDeadEnd(choices)) this.blacklistPosition(this.getPosition()); } /** * Checks if the given choices set correspond to a dead end. * * @param choices The choices currently available * @return T(The given choices set correspond to a dead end) */ private boolean inDeadEnd(Set choices) { return choices.size() < 2; } /** * Checks if the given position is known to lead to a dead end. * * @param position The position to check * @return T(The given position is blacklisted) */ private boolean isPositionBlacklisted(Vector2D position) { return this.positionBlacklist.contains(position); } /** * Regiters the given position in the blacklist. * * @param position The position to blacklist */ private void blacklistPosition(Vector2D position) { this.positionBlacklist.add(position); } }