package ch.epfl.maze.physical; import ch.epfl.maze.util.Direction; import ch.epfl.maze.util.Vector2D; import java.util.ArrayList; import java.util.Arrays; import java.util.Random; 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 An array of choices * @param toExclude The Direction to exclude * @return An array of smart choices */ protected Direction[] excludeDirection(Direction[] choices, Direction toExclude) { return (new ArrayList<>(Arrays.asList(choices))) .stream() .filter(dir -> dir != toExclude) .collect(Collectors.toList()) .toArray(new Direction[0]); } /** * Excludes the origin direction from possible choices. * * @param choices An array of choices * @return An array of smart choices */ protected Direction[] excludeOrigin(Direction[] choices) { return this.excludeDirection(choices, this.getDirection().reverse()); } /** * Returns a random Direction from the given choices. * * @param choices An array of Direction * @return A random Direction taken from the given choices */ protected Direction getRandomDirection(Direction[] choices) { return choices[RANDOM_SOURCE.nextInt(choices.length)]; } /** * 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(Direction[] choices) { if (choices.length == 0) return Direction.NONE; Direction[] smartChoices = choices.length > 1 ? this.excludeOrigin(choices) : choices; return this.getRandomDirection(smartChoices); } }