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 +++++++++++++++++++++++++++++--
src/ch/epfl/maze/util/Trail.java | 79 +++++++++++++++++++
2 files changed, 196 insertions(+), 8 deletions(-)
create mode 100644 src/ch/epfl/maze/util/Trail.java
(limited to 'src/ch/epfl')
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());
}
+
}
diff --git a/src/ch/epfl/maze/util/Trail.java b/src/ch/epfl/maze/util/Trail.java
new file mode 100644
index 0000000..351db8f
--- /dev/null
+++ b/src/ch/epfl/maze/util/Trail.java
@@ -0,0 +1,79 @@
+package ch.epfl.maze.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A trail keeping track on positional markings.
+ *
+ * @author Pacien TRAN-GIRARD
+ */
+public class Trail {
+
+ public enum Marking {
+ NO_MARKING,
+ AVOID_MARKING,
+ NO_GO_MARKING;
+
+ public static Marking DEFAULT = NO_MARKING;
+ public static Marking[] ALL = new Marking[]{NO_MARKING, AVOID_MARKING, NO_GO_MARKING};
+
+ /**
+ * Returns the next Marking.
+ *
+ * @return The next Marking
+ */
+ public Marking getNext() {
+ switch (this) {
+ case NO_MARKING:
+ return AVOID_MARKING;
+ case AVOID_MARKING:
+ return NO_GO_MARKING;
+ case NO_GO_MARKING:
+ return NO_GO_MARKING;
+ default:
+ return AVOID_MARKING;
+ }
+ }
+ }
+
+ private final Map trail;
+
+ /**
+ * Constructs a new blank Trail.
+ */
+ public Trail() {
+ this.trail = new HashMap<>();
+ }
+
+ /**
+ * Get the marking at the given position.
+ *
+ * @param position The positional Vector
+ * @return The Marking
+ */
+ public Marking getMarking(Vector2D position) {
+ Marking marking = this.trail.get(position);
+ return marking != null ? marking : Marking.DEFAULT;
+ }
+
+ /**
+ * Marks the given position with the given Marking.
+ *
+ * @param position The positional vector
+ * @param marking The Marking
+ */
+ public void markPosition(Vector2D position, Marking marking) {
+ this.trail.put(position, marking);
+ }
+
+ /**
+ * Marks the given position with the following Marking.
+ *
+ * @param position The positional vector
+ */
+ public void markPosition(Vector2D position) {
+ this.markPosition(position, this.getMarking(position).getNext());
+ }
+
+}
--
cgit v1.2.3