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/Ghost.java | 243 ++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 src/ch/epfl/maze/physical/pacman/Ghost.java (limited to 'src/ch/epfl/maze/physical/pacman/Ghost.java') 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(); + } + +} -- cgit v1.2.3