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 use a random component in its decision making process. * * @author Pacien TRAN-GIRARD */ abstract public class ProbabilisticAnimal extends Animal { private final Random randomSource; private Direction currentDirection; /** * 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 this.randomSource = new Random(); this.currentDirection = Direction.NONE; } /** * Excludes the origin direction for choices. * * @param choices An array of choices * @return An array of smart choices */ protected Direction[] excludeOrigin(Direction[] choices) { return (new ArrayList<>(Arrays.asList(choices))) .stream() .filter(dir -> !dir.isOpposite(this.currentDirection)) .collect(Collectors.toList()) .toArray(new Direction[0]); } /** * 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[randomSource.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; this.currentDirection = this.getRandomDirection(smartChoices); return this.currentDirection; } }