summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ch/epfl/maze/physical/GhostPredator.java196
1 files changed, 193 insertions, 3 deletions
diff --git a/src/ch/epfl/maze/physical/GhostPredator.java b/src/ch/epfl/maze/physical/GhostPredator.java
index 34b8c4f..44bb1f6 100644
--- a/src/ch/epfl/maze/physical/GhostPredator.java
+++ b/src/ch/epfl/maze/physical/GhostPredator.java
@@ -1,7 +1,11 @@
1package ch.epfl.maze.physical; 1package ch.epfl.maze.physical;
2 2
3import ch.epfl.maze.util.Direction;
3import ch.epfl.maze.util.Vector2D; 4import ch.epfl.maze.util.Vector2D;
4 5
6import java.util.ArrayList;
7import java.util.List;
8
5/** 9/**
6 * Predator ghost that have two different modes and a home position in the labyrinth. 10 * Predator ghost that have two different modes and a home position in the labyrinth.
7 * 11 *
@@ -9,9 +13,45 @@ import ch.epfl.maze.util.Vector2D;
9 */ 13 */
10abstract public class GhostPredator extends Predator { 14abstract public class GhostPredator extends Predator {
11 15
12 /* constants relative to the Pac-Man game */ 16 public enum Mode {
13 public static final int SCATTER_DURATION = 14; 17 CHASE(40),
14 public static final int CHASE_DURATION = 40; 18 SCATTER(14);
19
20 public static final Mode DEFAULT = CHASE;
21 public final int duration;
22
23 /**
24 * Constructs a new Mode with the given duration.
25 *
26 * @param duration The duration in cycles
27 */
28 Mode(int duration) {
29 this.duration = duration;
30 }
31
32 /**
33 * Returns the next Mode.
34 *
35 * @return The next Mode
36 */
37 public Mode getNext() {
38 switch (this) {
39 case CHASE:
40 return SCATTER;
41 case SCATTER:
42 return CHASE;
43 default:
44 return DEFAULT;
45 }
46 }
47 }
48
49 private static Prey commonPrey;
50
51 private final Vector2D homePosition;
52
53 private Mode mode;
54 private int modeCycle;
15 55
16 /** 56 /**
17 * Constructs a predator with a specified position. 57 * Constructs a predator with a specified position.
@@ -20,6 +60,156 @@ abstract public class GhostPredator extends Predator {
20 */ 60 */
21 public GhostPredator(Vector2D position) { 61 public GhostPredator(Vector2D position) {
22 super(position); 62 super(position);
63
64 this.homePosition = position;
65
66 this.mode = Mode.DEFAULT;
67 this.modeCycle = 0;
23 } 68 }
24 69
70 /**
71 * Selects a new random Prey to chase in the Daedalus.
72 *
73 * @param daedalus The Daedalus
74 * @return The Chosen One
75 */
76 private static Prey selectRandomPrey(Daedalus daedalus) {
77 if (daedalus.getPreys().isEmpty()) return null;
78
79 int randomPreyIndex = GhostPredator.RANDOM_SOURCE.nextInt(daedalus.getPreys().size());
80 return daedalus.getPreys().get(randomPreyIndex);
81 }
82
83 /**
84 * Returns the commonly targeted Prey.
85 *
86 * @param daedalus The Daedalus
87 * @return The common Prey
88 */
89 private static Prey getPrey(Daedalus daedalus) {
90 if (GhostPredator.commonPrey == null || !daedalus.hasPrey(GhostPredator.commonPrey))
91 GhostPredator.commonPrey = GhostPredator.selectRandomPrey(daedalus);
92
93 return GhostPredator.commonPrey;
94 }
95
96 /**
97 * Returns the commonly targeted Prey's position.
98 *
99 * @param daedalus The Daedalus
100 * @return The position of the Prey
101 */
102 protected final Vector2D getPreyPosition(Daedalus daedalus) {
103 Prey prey = GhostPredator.getPrey(daedalus);
104
105 if (prey == null) return this.homePosition;
106 return prey.getPosition();
107 }
108
109 /**
110 * Returns the commonly targeted Prey's Direction.
111 *
112 * @param daedalus The Daedalus
113 * @return The Direction the Prey is facing
114 */
115 protected final Direction getPreyDirection(Daedalus daedalus) {
116 Prey prey = GhostPredator.getPrey(daedalus);
117
118 if (prey == null) return Direction.NONE;
119 return prey.getCurrentDirection();
120 }
121
122 /**
123 * Calculates the Euclidean distance from the adjacent position at the given Direction to the target position.
124 *
125 * @param dir The adjacent Direction
126 * @param targetPosition The targeted position
127 * @return The Euclidean distance between the two positions
128 */
129 private double calcDistanceFromAdjacentDirectionTo(Direction dir, Vector2D targetPosition) {
130 return this
131 .getPosition()
132 .addDirectionTo(dir)
133 .sub(targetPosition)
134 .dist();
135 }
136
137 /**
138 * Selects the best Direction in the given choices by minimizing the Euclidean distance to the targeted position.
139 *
140 * @param targetPosition The targeted position
141 * @param choices An array of Direction choices
142 * @return An array of optimal Direction choices
143 */
144 private Direction[] selectBestPaths(Vector2D targetPosition, Direction[] choices) {
145 List<Direction> bestPaths = new ArrayList<>();
146 double minDist = Double.MAX_VALUE;
147
148 for (Direction dir : choices) {
149 double dist = this.calcDistanceFromAdjacentDirectionTo(dir, targetPosition);
150
151 if (dist < minDist) {
152 minDist = dist;
153 bestPaths.clear();
154 }
155
156 if (dist <= minDist)
157 bestPaths.add(dir);
158 }
159
160 return bestPaths.toArray(new Direction[bestPaths.size()]);
161 }
162
163 /**
164 * Rotates to the next Mode.
165 */
166 protected void rotateMode() {
167 this.mode = this.mode.getNext();
168 this.modeCycle = 0;
169 }
170
171 /**
172 * Increments the cycle counter and rotates to the next Mode if the Mode's duration has been reached.
173 */
174 private void countCycle() {
175 this.modeCycle += 1;
176
177 if (this.modeCycle >= this.mode.duration)
178 this.rotateMode();
179 }
180
181 @Override
182 public Direction move(Direction[] choices, Daedalus daedalus) {
183 this.countCycle();
184
185 Direction[] smartChoices = choices.length > 1 ? this.excludeOrigin(choices) : choices;
186 Direction[] bestPaths = this.selectBestPaths(this.getTargetPosition(daedalus), smartChoices);
187 return this.move(bestPaths);
188 }
189
190 /**
191 * Returns the position to target according to the current Mode.
192 *
193 * @param daedalus The Daedalus
194 * @return The position to target
195 */
196 protected Vector2D getTargetPosition(Daedalus daedalus) {
197 switch (this.mode) {
198 case CHASE:
199 return this.getPreyTargetPosition(daedalus);
200 case SCATTER:
201 return this.homePosition;
202 default:
203 return this.homePosition;
204 }
205 }
206
207 /**
208 * Returns the Prey's projected targeted position.
209 *
210 * @param daedalus The Daedalus
211 * @return The projected position
212 */
213 protected abstract Vector2D getPreyTargetPosition(Daedalus daedalus);
214
25} 215}