From 4da9bdc4fa2f44eedba3dff29af7b0ce9180e442 Mon Sep 17 00:00:00 2001 From: Pacien TRAN-GIRARD Date: Tue, 24 Nov 2015 23:43:00 +0100 Subject: Refactor Ghosts --- src/ch/epfl/maze/physical/pacman/Blinky.java | 3 +- src/ch/epfl/maze/physical/pacman/Clyde.java | 3 +- src/ch/epfl/maze/physical/pacman/Ghost.java | 243 +++++++++++++++++++++++++++ src/ch/epfl/maze/physical/pacman/Inky.java | 15 +- src/ch/epfl/maze/physical/pacman/Pinky.java | 3 +- 5 files changed, 253 insertions(+), 14 deletions(-) create mode 100644 src/ch/epfl/maze/physical/pacman/Ghost.java (limited to 'src/ch/epfl/maze/physical/pacman') diff --git a/src/ch/epfl/maze/physical/pacman/Blinky.java b/src/ch/epfl/maze/physical/pacman/Blinky.java index 4e8c4a0..5f81d13 100644 --- a/src/ch/epfl/maze/physical/pacman/Blinky.java +++ b/src/ch/epfl/maze/physical/pacman/Blinky.java @@ -2,7 +2,6 @@ package ch.epfl.maze.physical.pacman; import ch.epfl.maze.physical.Animal; import ch.epfl.maze.physical.Daedalus; -import ch.epfl.maze.physical.GhostPredator; import ch.epfl.maze.util.Vector2D; /** @@ -11,7 +10,7 @@ import ch.epfl.maze.util.Vector2D; * @author EPFL * @author Pacien TRAN-GIRARD */ -public class Blinky extends GhostPredator { +public class Blinky extends Ghost { /** * Constructs a Blinky with a starting position. diff --git a/src/ch/epfl/maze/physical/pacman/Clyde.java b/src/ch/epfl/maze/physical/pacman/Clyde.java index 40089db..2d7e47a 100644 --- a/src/ch/epfl/maze/physical/pacman/Clyde.java +++ b/src/ch/epfl/maze/physical/pacman/Clyde.java @@ -2,7 +2,6 @@ package ch.epfl.maze.physical.pacman; import ch.epfl.maze.physical.Animal; import ch.epfl.maze.physical.Daedalus; -import ch.epfl.maze.physical.GhostPredator; import ch.epfl.maze.util.Vector2D; /** @@ -12,7 +11,7 @@ import ch.epfl.maze.util.Vector2D; * @author EPFL * @author Pacien TRAN-GIRARD */ -public class Clyde extends GhostPredator { +public class Clyde extends Ghost { private static double PROXIMITY_THRESHOLD = 4.0d; diff --git a/src/ch/epfl/maze/physical/pacman/Ghost.java b/src/ch/epfl/maze/physical/pacman/Ghost.java new file mode 100644 index 0000000..f8f511e --- /dev/null +++ b/src/ch/epfl/maze/physical/pacman/Ghost.java @@ -0,0 +1,243 @@ +package ch.epfl.maze.physical.pacman; + +import ch.epfl.maze.physical.Daedalus; +import ch.epfl.maze.physical.Predator; +import ch.epfl.maze.physical.Prey; +import ch.epfl.maze.physical.stragegies.picker.RandomPicker; +import ch.epfl.maze.physical.stragegies.reducer.BackwardReducer; +import ch.epfl.maze.physical.stragegies.reducer.CostReducer; +import ch.epfl.maze.util.Direction; +import ch.epfl.maze.util.Vector2D; + +import java.util.EnumSet; +import java.util.Set; + +/** + * Predator ghost that have two different modes and a home position in the labyrinth. + * + * @author Pacien TRAN-GIRARD + */ +abstract public class Ghost extends Predator implements BackwardReducer, CostReducer, RandomPicker { + + public enum Mode { + CHASE(40), + SCATTER(14); + + public static final Mode DEFAULT = CHASE; + public final int duration; + + /** + * Constructs a new Mode with the given duration. + * + * @param duration The duration in cycles + */ + Mode(int duration) { + this.duration = duration; + } + + /** + * Returns the next Mode. + * + * @return The next Mode + */ + public Mode getNext() { + switch (this) { + case CHASE: + return SCATTER; + case SCATTER: + return CHASE; + default: + return DEFAULT; + } + } + } + + private static Prey commonPrey; + + private final Vector2D homePosition; + + private Mode mode; + private int modeCycle; + + /** + * Constructs a predator with a specified position. + * + * @param position Position of the predator in the labyrinth + */ + public Ghost(Vector2D position) { + super(position); + + this.homePosition = position; + + this.mode = Mode.DEFAULT; + this.modeCycle = 0; + } + + /** + * Returns the cost to reach the target by choosing the given Direction by calculating the Euclidean distance. + * + * @param choice The Direction choice + * @param daedalus The Daedalus + * @return The Euclidean distance cost + */ + @Override + public int getChoiceCost(Direction choice, Daedalus daedalus) { + Vector2D target = this.getTargetPosition(daedalus); + return (int) (this.getDistanceTo(choice, target) * 100); + } + + @Override + public Set reduce(Set choices) { + return EnumSet.noneOf(Direction.class); + } + + /** + * Selects the best Direction in the given choices by minimizing the Euclidean distance to the targeted position + * after excluding the provenance if possible. + * + * @param choices A set of Direction choices + * @param daedalus The Daedalus + * @return A set of optimal Direction choices + */ + @Override + public Set reduce(Set choices, Daedalus daedalus) { + Set forwardChoices = choices.size() > 1 ? BackwardReducer.super.reduce(choices) : choices; + return CostReducer.super.reduce(forwardChoices, daedalus); + } + + @Override + public Direction move(Set choices, Daedalus daedalus) { + this.countCycle(); + + Set bestChoices = this.reduce(choices, daedalus); + return this.pick(bestChoices); + } + + /** + * Returns the Prey's projected targeted position. + * + * @param daedalus The Daedalus + * @return The projected position + */ + abstract protected Vector2D getPreyTargetPosition(Daedalus daedalus); + + /** + * Returns the current Mode. + * + * @param daedalus The Daedalus + * @return The current Mode + */ + protected Mode getMode(Daedalus daedalus) { + return this.mode; + } + + /** + * Returns the position to target according to the current Mode. + * + * @param daedalus The Daedalus + * @return The position to target + */ + protected Vector2D getTargetPosition(Daedalus daedalus) { + switch (this.getMode(daedalus)) { + case CHASE: + return this.getPreyTargetPosition(daedalus); + case SCATTER: + return this.homePosition; + default: + return this.homePosition; + } + } + + /** + * Selects a new random Prey to chase in the Daedalus. + * + * @param daedalus The Daedalus + * @return The Chosen One + */ + private static Prey selectAnyPrey(Daedalus daedalus) { + if (daedalus.getPreySet().isEmpty()) return null; + return daedalus.getPreySet().stream().findAny().get(); + } + + /** + * Sets a random Prey as the common Pre. + * + * @param daedalus The Daedalus + */ + private static synchronized void setAnyPrey(Daedalus daedalus) { + Ghost.commonPrey = Ghost.selectAnyPrey(daedalus); + } + + /** + * Returns the commonly targeted Prey. + * + * @param daedalus The Daedalus + * @return The common Prey + */ + private static Prey getPrey(Daedalus daedalus) { + if (Ghost.commonPrey == null || !daedalus.hasPrey(Ghost.commonPrey)) + Ghost.setAnyPrey(daedalus); + + return Ghost.commonPrey; + } + + /** + * Returns the commonly targeted Prey's position. + * + * @param daedalus The Daedalus + * @return The position of the Prey + */ + protected final Vector2D getPreyPosition(Daedalus daedalus) { + Prey prey = Ghost.getPrey(daedalus); + + if (prey == null) return this.homePosition; + return prey.getPosition(); + } + + /** + * Returns the commonly targeted Prey's Direction. + * + * @param daedalus The Daedalus + * @return The Direction the Prey is facing + */ + protected final Direction getPreyDirection(Daedalus daedalus) { + Prey prey = Ghost.getPrey(daedalus); + + if (prey == null) return Direction.NONE; + return prey.getDirection(); + } + + /** + * Calculates the Euclidean distance from the adjacent position at the given Direction to the target position. + * + * @param dir The adjacent Direction + * @param targetPosition The targeted position + * @return The Euclidean distance between the two positions + */ + private double getDistanceTo(Direction dir, Vector2D targetPosition) { + return this + .getPosition() + .addDirectionTo(dir) + .sub(targetPosition) + .dist(); + } + + /** + * Rotates to the next Mode. + */ + protected void rotateMode() { + this.mode = this.mode.getNext(); + this.modeCycle = 0; + } + + /** + * Increments the cycle counter and rotates to the next Mode if the Mode's duration has been reached. + */ + private void countCycle() { + this.modeCycle += 1; + + if (this.modeCycle >= this.mode.duration) + this.rotateMode(); + } + +} diff --git a/src/ch/epfl/maze/physical/pacman/Inky.java b/src/ch/epfl/maze/physical/pacman/Inky.java index 05c712c..c716058 100644 --- a/src/ch/epfl/maze/physical/pacman/Inky.java +++ b/src/ch/epfl/maze/physical/pacman/Inky.java @@ -2,7 +2,6 @@ package ch.epfl.maze.physical.pacman; import ch.epfl.maze.physical.Animal; import ch.epfl.maze.physical.Daedalus; -import ch.epfl.maze.physical.GhostPredator; import ch.epfl.maze.util.Vector2D; import java.util.NoSuchElementException; @@ -14,9 +13,9 @@ import java.util.NoSuchElementException; * @author EPFL * @author Pacien TRAN-GIRARD */ -public class Inky extends GhostPredator { +public class Inky extends Ghost { - private GhostPredator companion; + private Ghost companion; /** * Finds Inky's best friend (Blinky) in the Daedalus. @@ -24,10 +23,10 @@ public class Inky extends GhostPredator { * @param daedalus The Daedalus * @return The companion if found, null otherwise */ - private static GhostPredator findCompanion(Daedalus daedalus) { + private static Ghost findCompanion(Daedalus daedalus) { try { return (Blinky) daedalus - .getPredators() + .getPredatorSet() .stream() .filter(pred -> pred instanceof Blinky) .findFirst() @@ -43,7 +42,7 @@ public class Inky extends GhostPredator { * @param position Starting position of Inky in the labyrinth * @param companion Inky's accomplice */ - public Inky(Vector2D position, GhostPredator companion) { + public Inky(Vector2D position, Ghost companion) { super(position); this.companion = companion; } @@ -63,7 +62,7 @@ public class Inky extends GhostPredator { * @param daedalus The Daedalus * @return Inky's companion if present, null otherwise */ - private GhostPredator getCompanion(Daedalus daedalus) { + private Ghost getCompanion(Daedalus daedalus) { if (this.companion == null) this.companion = Inky.findCompanion(daedalus); @@ -77,7 +76,7 @@ public class Inky extends GhostPredator { * @return Inky's companion's position if present, null otherwise */ private Vector2D getCompanionPosition(Daedalus daedalus) { - GhostPredator companion = this.getCompanion(daedalus); + Ghost companion = this.getCompanion(daedalus); if (companion == null) return new Vector2D(); return companion.getPosition(); } diff --git a/src/ch/epfl/maze/physical/pacman/Pinky.java b/src/ch/epfl/maze/physical/pacman/Pinky.java index f3e145d..344f55a 100644 --- a/src/ch/epfl/maze/physical/pacman/Pinky.java +++ b/src/ch/epfl/maze/physical/pacman/Pinky.java @@ -2,7 +2,6 @@ package ch.epfl.maze.physical.pacman; import ch.epfl.maze.physical.Animal; import ch.epfl.maze.physical.Daedalus; -import ch.epfl.maze.physical.GhostPredator; import ch.epfl.maze.util.Direction; import ch.epfl.maze.util.Vector2D; @@ -12,7 +11,7 @@ import ch.epfl.maze.util.Vector2D; * @author EPFL * @author Pacien TRAN-GIRARD */ -public class Pinky extends GhostPredator { +public class Pinky extends Ghost { private static final int TARGET_OFFSET = 4; -- cgit v1.2.3