package ch.epfl.maze.physical; import ch.epfl.maze.util.Direction; import ch.epfl.maze.util.Vector2D; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.Set; import java.util.stream.Collectors; /** * A probabilistic animal that uses a random component in its decision making process. * * @author Pacien TRAN-GIRARD */ abstract public class ProbabilisticAnimal extends Animal { public static final Random RANDOM_SOURCE = new Random(); /** * Constructs a probabilistic animal with a starting position * * @param position Starting position of the probabilistic animal in the labyrinth */ public ProbabilisticAnimal(Vector2D position) { super(position); // no pun intended } /** * Excludes the given direction from possible choices. * * @param choices A set of choices * @param toExclude The Direction to exclude * @return A set of smart choices */ protected Set excludeDirection(Set choices, Direction toExclude) { return choices .stream() .filter(dir -> dir != toExclude) .collect(Collectors.toSet()); } /** * Excludes the origin direction from possible choices. * * @param choices A set of choices * @return A set of smart choices */ protected Set excludeOrigin(Set choices) { return this.excludeDirection(choices, this.getDirection().reverse()); } /** * Returns a random Direction from the given choices. * * @param choices A set of Direction * @return A random Direction taken from the given choices */ protected Direction getRandomDirection(Set choices) { List choiceList = new ArrayList<>(choices); return choiceList.get(RANDOM_SOURCE.nextInt(choices.size())); } /** * Moves according to an improved version of a random walk : the * probabilistic animal does not directly retrace its steps if not forced. */ @Override public Direction move(Set choices) { if (choices.isEmpty()) return Direction.NONE; Set smartChoices = choices.size() > 1 ? this.excludeOrigin(choices) : choices; return this.getRandomDirection(smartChoices); } }