diff options
Diffstat (limited to 'src/ch/epfl/maze/physical/pacman/Ghost.java')
-rw-r--r-- | src/ch/epfl/maze/physical/pacman/Ghost.java | 243 |
1 files changed, 243 insertions, 0 deletions
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 @@ | |||
1 | package ch.epfl.maze.physical.pacman; | ||
2 | |||
3 | import ch.epfl.maze.physical.Daedalus; | ||
4 | import ch.epfl.maze.physical.Predator; | ||
5 | import ch.epfl.maze.physical.Prey; | ||
6 | import ch.epfl.maze.physical.stragegies.picker.RandomPicker; | ||
7 | import ch.epfl.maze.physical.stragegies.reducer.BackwardReducer; | ||
8 | import ch.epfl.maze.physical.stragegies.reducer.CostReducer; | ||
9 | import ch.epfl.maze.util.Direction; | ||
10 | import ch.epfl.maze.util.Vector2D; | ||
11 | |||
12 | import java.util.EnumSet; | ||
13 | import java.util.Set; | ||
14 | |||
15 | /** | ||
16 | * Predator ghost that have two different modes and a home position in the labyrinth. | ||
17 | * | ||
18 | * @author Pacien TRAN-GIRARD | ||
19 | */ | ||
20 | abstract public class Ghost extends Predator implements BackwardReducer, CostReducer, RandomPicker { | ||
21 | |||
22 | public enum Mode { | ||
23 | CHASE(40), | ||
24 | SCATTER(14); | ||
25 | |||
26 | public static final Mode DEFAULT = CHASE; | ||
27 | public final int duration; | ||
28 | |||
29 | /** | ||
30 | * Constructs a new Mode with the given duration. | ||
31 | * | ||
32 | * @param duration The duration in cycles | ||
33 | */ | ||
34 | Mode(int duration) { | ||
35 | this.duration = duration; | ||
36 | } | ||
37 | |||
38 | /** | ||
39 | * Returns the next Mode. | ||
40 | * | ||
41 | * @return The next Mode | ||
42 | */ | ||
43 | public Mode getNext() { | ||
44 | switch (this) { | ||
45 | case CHASE: | ||
46 | return SCATTER; | ||
47 | case SCATTER: | ||
48 | return CHASE; | ||
49 | default: | ||
50 | return DEFAULT; | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | |||
55 | private static Prey commonPrey; | ||
56 | |||
57 | private final Vector2D homePosition; | ||
58 | |||
59 | private Mode mode; | ||
60 | private int modeCycle; | ||
61 | |||
62 | /** | ||
63 | * Constructs a predator with a specified position. | ||
64 | * | ||
65 | * @param position Position of the predator in the labyrinth | ||
66 | */ | ||
67 | public Ghost(Vector2D position) { | ||
68 | super(position); | ||
69 | |||
70 | this.homePosition = position; | ||
71 | |||
72 | this.mode = Mode.DEFAULT; | ||
73 | this.modeCycle = 0; | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * Returns the cost to reach the target by choosing the given Direction by calculating the Euclidean distance. | ||
78 | * | ||
79 | * @param choice The Direction choice | ||
80 | * @param daedalus The Daedalus | ||
81 | * @return The Euclidean distance cost | ||
82 | */ | ||
83 | @Override | ||
84 | public int getChoiceCost(Direction choice, Daedalus daedalus) { | ||
85 | Vector2D target = this.getTargetPosition(daedalus); | ||
86 | return (int) (this.getDistanceTo(choice, target) * 100); | ||
87 | } | ||
88 | |||
89 | @Override | ||
90 | public Set<Direction> reduce(Set<Direction> choices) { | ||
91 | return EnumSet.noneOf(Direction.class); | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * Selects the best Direction in the given choices by minimizing the Euclidean distance to the targeted position | ||
96 | * after excluding the provenance if possible. | ||
97 | * | ||
98 | * @param choices A set of Direction choices | ||
99 | * @param daedalus The Daedalus | ||
100 | * @return A set of optimal Direction choices | ||
101 | */ | ||
102 | @Override | ||
103 | public Set<Direction> reduce(Set<Direction> choices, Daedalus daedalus) { | ||
104 | Set<Direction> forwardChoices = choices.size() > 1 ? BackwardReducer.super.reduce(choices) : choices; | ||
105 | return CostReducer.super.reduce(forwardChoices, daedalus); | ||
106 | } | ||
107 | |||
108 | @Override | ||
109 | public Direction move(Set<Direction> choices, Daedalus daedalus) { | ||
110 | this.countCycle(); | ||
111 | |||
112 | Set<Direction> bestChoices = this.reduce(choices, daedalus); | ||
113 | return this.pick(bestChoices); | ||
114 | } | ||
115 | |||
116 | /** | ||
117 | * Returns the Prey's projected targeted position. | ||
118 | * | ||
119 | * @param daedalus The Daedalus | ||
120 | * @return The projected position | ||
121 | */ | ||
122 | abstract protected Vector2D getPreyTargetPosition(Daedalus daedalus); | ||
123 | |||
124 | /** | ||
125 | * Returns the current Mode. | ||
126 | * | ||
127 | * @param daedalus The Daedalus | ||
128 | * @return The current Mode | ||
129 | */ | ||
130 | protected Mode getMode(Daedalus daedalus) { | ||
131 | return this.mode; | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * Returns the position to target according to the current Mode. | ||
136 | * | ||
137 | * @param daedalus The Daedalus | ||
138 | * @return The position to target | ||
139 | */ | ||
140 | protected Vector2D getTargetPosition(Daedalus daedalus) { | ||
141 | switch (this.getMode(daedalus)) { | ||
142 | case CHASE: | ||
143 | return this.getPreyTargetPosition(daedalus); | ||
144 | case SCATTER: | ||
145 | return this.homePosition; | ||
146 | default: | ||
147 | return this.homePosition; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * Selects a new random Prey to chase in the Daedalus. | ||
153 | * | ||
154 | * @param daedalus The Daedalus | ||
155 | * @return The Chosen One | ||
156 | */ | ||
157 | private static Prey selectAnyPrey(Daedalus daedalus) { | ||
158 | if (daedalus.getPreySet().isEmpty()) return null; | ||
159 | return daedalus.getPreySet().stream().findAny().get(); | ||
160 | } | ||
161 | |||
162 | /** | ||
163 | * Sets a random Prey as the common Pre. | ||
164 | * | ||
165 | * @param daedalus The Daedalus | ||
166 | */ | ||
167 | private static synchronized void setAnyPrey(Daedalus daedalus) { | ||
168 | Ghost.commonPrey = Ghost.selectAnyPrey(daedalus); | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * Returns the commonly targeted Prey. | ||
173 | * | ||
174 | * @param daedalus The Daedalus | ||
175 | * @return The common Prey | ||
176 | */ | ||
177 | private static Prey getPrey(Daedalus daedalus) { | ||
178 | if (Ghost.commonPrey == null || !daedalus.hasPrey(Ghost.commonPrey)) | ||
179 | Ghost.setAnyPrey(daedalus); | ||
180 | |||
181 | return Ghost.commonPrey; | ||
182 | } | ||
183 | |||
184 | /** | ||
185 | * Returns the commonly targeted Prey's position. | ||
186 | * | ||
187 | * @param daedalus The Daedalus | ||
188 | * @return The position of the Prey | ||
189 | */ | ||
190 | protected final Vector2D getPreyPosition(Daedalus daedalus) { | ||
191 | Prey prey = Ghost.getPrey(daedalus); | ||
192 | |||
193 | if (prey == null) return this.homePosition; | ||
194 | return prey.getPosition(); | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * Returns the commonly targeted Prey's Direction. | ||
199 | * | ||
200 | * @param daedalus The Daedalus | ||
201 | * @return The Direction the Prey is facing | ||
202 | */ | ||
203 | protected final Direction getPreyDirection(Daedalus daedalus) { | ||
204 | Prey prey = Ghost.getPrey(daedalus); | ||
205 | |||
206 | if (prey == null) return Direction.NONE; | ||
207 | return prey.getDirection(); | ||
208 | } | ||
209 | |||
210 | /** | ||
211 | * Calculates the Euclidean distance from the adjacent position at the given Direction to the target position. | ||
212 | * | ||
213 | * @param dir The adjacent Direction | ||
214 | * @param targetPosition The targeted position | ||
215 | * @return The Euclidean distance between the two positions | ||
216 | */ | ||
217 | private double getDistanceTo(Direction dir, Vector2D targetPosition) { | ||
218 | return this | ||
219 | .getPosition() | ||
220 | .addDirectionTo(dir) | ||
221 | .sub(targetPosition) | ||
222 | .dist(); | ||
223 | } | ||
224 | |||
225 | /** | ||
226 | * Rotates to the next Mode. | ||
227 | */ | ||
228 | protected void rotateMode() { | ||