From 15c612d56c98849daafeebea79d3f8f9b3a887b2 Mon Sep 17 00:00:00 2001 From: Pacien TRAN-GIRARD Date: Sun, 22 Nov 2015 16:03:51 +0100 Subject: Implement Panda A.I. and its Trail --- src/ch/epfl/maze/physical/zoo/Panda.java | 125 +++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 8 deletions(-) (limited to 'src/ch/epfl/maze/physical/zoo') diff --git a/src/ch/epfl/maze/physical/zoo/Panda.java b/src/ch/epfl/maze/physical/zoo/Panda.java index c168d97..fecec84 100644 --- a/src/ch/epfl/maze/physical/zoo/Panda.java +++ b/src/ch/epfl/maze/physical/zoo/Panda.java @@ -1,23 +1,128 @@ package ch.epfl.maze.physical.zoo; import ch.epfl.maze.physical.Animal; +import ch.epfl.maze.physical.ProbabilisticAnimal; import ch.epfl.maze.util.Direction; +import ch.epfl.maze.util.Trail; import ch.epfl.maze.util.Vector2D; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.stream.Collectors; + /** * Panda A.I. that implements Trémeaux's Algorithm. + * + * @author Pacien TRAN-GIRARD */ -public class Panda extends Animal { +public class Panda extends ProbabilisticAnimal { + + private final Trail trail; /** * Constructs a panda with a starting position. * * @param position Starting position of the panda in the labyrinth */ - public Panda(Vector2D position) { super(position); - // TODO + this.trail = new Trail(); + } + + /** + * Checks if the current position is an intersection given the possible choices. + * + * @param choices An array of possible Directions + * @return T(the current position is an intersection) + */ + private boolean isIntersection(Direction[] choices) { + return choices.length > 2; + } + + /** + * Get the Marking at the adjacent position given the Direction. + * + * @param dir The Direction from the current position + * @return The Marking + */ + private Trail.Marking getMarkingAtDirection(Direction dir) { + Vector2D pos = this.getPosition().addDirectionTo(dir); + return this.trail.getMarking(pos); + } + + /** + * Checks if all Direction choices are leading to the given Marking. + * + * @param choices An array of possible Directions + * @param marking The Marking + * @return T(all choices are leading to positions with the given Marking) + */ + private boolean allChoicesLeadingTo(Direction[] choices, Trail.Marking marking) { + return (new ArrayList<>(Arrays.asList(choices))) + .stream() + .allMatch(dir -> this.getMarkingAtDirection(dir) == marking); + } + + /** + * Selects the Direction choices leading to the given Marking. + * + * @param choices An array of possible Directions + * @param marking The Marking + * @return An array of choices leading to the given Marking + */ + private Direction[] selectDirectionsWithMarking(Direction[] choices, Trail.Marking marking) { + return (new ArrayList<>(Arrays.asList(choices))) + .stream() + .filter(dir -> this.getMarkingAtDirection(dir) == marking) + .collect(Collectors.toList()) + .toArray(new Direction[0]); + } + + /** + * Selects the best choices according to the neighbours Markings. + * + * @param choices An array of possible Directions + * @return An array of smart choices + */ + private Direction[] selectBestDirections(Direction[] choices) { + // special case + if (this.isIntersection(choices) && this.allChoicesLeadingTo(choices, Trail.Marking.AVOID_MARKING)) + return new Direction[]{this.currentDirection.reverse()}; + + // general case + for (Trail.Marking mark : Trail.Marking.ALL) { + Direction[] smartChoices = this.selectDirectionsWithMarking(choices, mark); + if (smartChoices.length > 0) return smartChoices; + } + + // panda is trapped :( + return new Direction[]{}; + } + + /** + * Determines if the current position should be marked according to the rules of the Trémeaux's Algorithm, + * avoiding intersections over-marking. + * + * @param choices An array of possible Directions + * @param choice The selected Direction + * @return T(the current position should be marked) + */ + private boolean shouldMarkCurrentPosition(Direction[] choices, Direction choice) { + return !(this.isIntersection(choices) + && this.trail.getMarking(this.getPosition()) == Trail.Marking.AVOID_MARKING + && this.getMarkingAtDirection(choice) == Trail.Marking.NO_MARKING); + } + + /** + * Marks the current position according to the rules of the Trémeaux's Algorithm. + * + * @param choices An array of possible Direction to take + */ + private void markCurrentPosition(Direction[] choices) { + if (choices.length == 1 && this.allChoicesLeadingTo(choices, Trail.Marking.AVOID_MARKING)) // dead end + this.trail.markPosition(this.getPosition(), Trail.Marking.NO_GO_MARKING); + else + this.trail.markPosition(this.getPosition()); } /** @@ -26,16 +131,20 @@ public class Panda extends Animal { * colors). It will prefer taking the least marked paths. Special cases * have to be handled, especially when the panda is at an intersection. */ - @Override public Direction move(Direction[] choices) { - // TODO - return Direction.NONE; + Direction[] smartChoices = this.selectBestDirections(choices); + Direction choice = super.move(smartChoices); + + if (this.shouldMarkCurrentPosition(choices, choice)) + this.markCurrentPosition(choices); + + return choice; } @Override public Animal copy() { - // TODO - return null; + return new Panda(this.getPosition()); } + } -- cgit v1.2.3