summaryrefslogtreecommitdiff
path: root/src/ch/epfl/maze/simulation/MazeSimulation.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/ch/epfl/maze/simulation/MazeSimulation.java')
-rw-r--r--src/ch/epfl/maze/simulation/MazeSimulation.java211
1 files changed, 211 insertions, 0 deletions
diff --git a/src/ch/epfl/maze/simulation/MazeSimulation.java b/src/ch/epfl/maze/simulation/MazeSimulation.java
new file mode 100644
index 0000000..d70f735
--- /dev/null
+++ b/src/ch/epfl/maze/simulation/MazeSimulation.java
@@ -0,0 +1,211 @@
1package ch.epfl.maze.simulation;
2
3import java.util.LinkedList;
4import java.util.List;
5import java.util.Map;
6import java.util.TreeMap;
7
8import ch.epfl.maze.graphics.Animation;
9import ch.epfl.maze.physical.Animal;
10import ch.epfl.maze.physical.Maze;
11import ch.epfl.maze.physical.World;
12import ch.epfl.maze.util.Action;
13import ch.epfl.maze.util.Direction;
14import ch.epfl.maze.util.Vector2D;
15
16/**
17 * Simulation of a maze solver. Handles the next move of each animal, as well as
18 * the animation by notifying the changes to it. The simulation finishes when
19 * every animal has found the exit.
20 *
21 */
22
23public final class MazeSimulation implements Simulation {
24
25 /* limit to the step counter, over which the animals are considered lost */
26 public static final int COUNTER_LIMIT = 10000;
27
28 /* simulation components */
29 private Maze mMaze;
30 private Map<Integer, List<Animal>> mArrivalTimes;
31 private int mStepCounter;
32
33 /**
34 * Constructs a simulation with a {@code Maze} to simulate.
35 *
36 * @param maze
37 * The maze to simulate
38 */
39
40 public MazeSimulation(Maze maze) {
41 mMaze = maze;
42 mArrivalTimes = new TreeMap<Integer, List<Animal>>();
43 mStepCounter = 0;
44 }
45
46 @Override
47 public void move(Animation listener) {
48 if (isOver()) {
49 return;
50 }
51
52 // increments counter
53 mStepCounter++;
54
55 // if counter exceeded limit, it considers animals lost
56 if (mStepCounter > COUNTER_LIMIT) {
57 List<Animal> animals = mMaze.getAnimals();
58 List<Animal> lostAnimals = new LinkedList<Animal>();
59 for (Animal animal : animals) {
60 mMaze.removeAnimal(animal);
61 lostAnimals.add(animal);
62 }
63
64 mArrivalTimes.put(Integer.MAX_VALUE, lostAnimals); // infinite
65 return;
66 }
67
68 // asks animals to move
69 moveAnimals(listener);
70
71 // notifies animation that all the changes are done
72 if (listener != null) {
73 listener.doneUpdating();
74 }
75 }
76
77 @Override
78 public boolean isOver() {
79 return mMaze.isSolved();
80 }
81
82 @Override
83 public World getWorld() {
84 return mMaze;
85 }
86
87 @Override
88 public int getSteps() {
89 return mStepCounter;
90 }
91
92 public Map<Integer, List<Animal>> getArrivalTimes() {
93 return new TreeMap<Integer, List<Animal>>(mArrivalTimes);
94 }
95
96 public String getRecordTable() {
97 String recordTable = "";
98 int position = 1;
99 for (Map.Entry<Integer, List<Animal>> entry : mArrivalTimes.entrySet()) {
100 // only returns the 10 first
101 if (position > 10) {
102 return recordTable;
103 }
104
105 for (Animal animal : entry.getValue()) {
106 if (entry.getKey() == Integer.MAX_VALUE) {
107 recordTable += "-- ";
108 recordTable += animal.getClass().getSimpleName();
109 recordTable += " - never finished\n";
110 } else {
111 recordTable += position + ". ";
112 recordTable += animal.getClass().getSimpleName();
113 recordTable += " - " + entry.getKey() + " steps\n";
114 }
115 }
116 position += entry.getValue().size();
117 }
118
119 return recordTable;
120 }
121
122 @Override
123 public void restart() {
124 mMaze.reset();
125 mArrivalTimes.clear();
126 mStepCounter = 0;
127 }
128
129 @Override
130 public void stop() {
131 List<Animal> forgottenAnimals = new LinkedList<Animal>();
132 for (Animal animal : mMaze.getAnimals()) {
133 forgottenAnimals.add(animal);
134 mMaze.removeAnimal(animal);
135 }
136 mArrivalTimes.put(Integer.MAX_VALUE, forgottenAnimals);
137 }
138
139 /**
140 * Moves the animals in the maze.
141 *
142 * @param listener
143 * The listener to which the function will notify the changes
144 * (can be null)
145 */
146
147 private void moveAnimals(Animation listener) {
148 List<Animal> animals = mMaze.getAnimals();
149 for (int i = 0; i < animals.size(); i++) {
150 Animal animal = animals.get(i);
151 Vector2D position = animal.getPosition();
152 Direction[] choices = mMaze.getChoices(position);
153
154 // tries to make animal move
155 Direction choice;
156 try {
157 choice = animal.move(choices);
158 if (!animal.getPosition().equals(position)) {
159 System.err.println("Error : Animal position changed while choosing direction.");
160 System.err.println("\tDid you call setPosition(Vector2D) or update(Direction) ?\n");
161 animal.setPosition(position);
162 choice = null;
163 }
164 } catch (Exception E) {
165 System.err.print("Exception occurred while moving animals: ");
166 E.printStackTrace();
167 choice = null;
168 }
169
170 // if animal could move
171 if (choice != null) {
172 Vector2D futurePosition = animal.getPosition();
173 futurePosition = futurePosition.addDirectionTo(choice);
174
175 int x = futurePosition.getX();
176 int y = futurePosition.getY();
177
178
179 if (mMaze.isFree(x, y)) {
180 // asks animation to draw the action of the animal
181 if (listener != null) {
182 Action action = new Action(choice, true);
183 listener.update(animal, i, action);
184 }
185
186 // if at the end of the maze
187 if (mMaze.getTile(x, y) == World.EXIT) {
188 mMaze.removeAnimal(animal);
189
190 // records arrival time
191 if (mArrivalTimes.get(mStepCounter) == null) {
192 mArrivalTimes.put(mStepCounter, new LinkedList<Animal>());
193 }
194 mArrivalTimes.get(mStepCounter).add(animal);
195 } else {
196 animal.update(choice);
197 }
198 } else if (listener != null) {
199 // asks animation to draw an interrupted movement
200 Action action = new Action(choice, false);
201 listener.update(animal, i, action);
202 }
203
204 } else if (listener != null) {
205 // asks animation to draw a confused animal
206 Action action = new Action(Direction.NONE, false);
207 listener.update(animal, i, action);
208 }
209 }
210 }
211}