diff options
Diffstat (limited to 'src/ch')
-rw-r--r-- | src/ch/epfl/maze/physical/GhostPredator.java | 196 |
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 @@ | |||
1 | package ch.epfl.maze.physical; | 1 | package ch.epfl.maze.physical; |
2 | 2 | ||
3 | import ch.epfl.maze.util.Direction; | ||
3 | import ch.epfl.maze.util.Vector2D; | 4 | import ch.epfl.maze.util.Vector2D; |
4 | 5 | ||
6 | import java.util.ArrayList; | ||
7 | import 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 | */ |
10 | abstract public class GhostPredator extends Predator { | 14 | abstract 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 | } |