From 655ac88f4e73b2df532a451aedf5a561ea1b0d2c Mon Sep 17 00:00:00 2001 From: Pacien TRAN-GIRARD Date: Sat, 21 Nov 2015 10:36:18 +0100 Subject: Import project structure --- .../epfl/maze/simulation/DaedalusSimulation.java | 364 +++++++++++++++++++++ 1 file changed, 364 insertions(+) create mode 100644 src/ch/epfl/maze/simulation/DaedalusSimulation.java (limited to 'src/ch/epfl/maze/simulation/DaedalusSimulation.java') diff --git a/src/ch/epfl/maze/simulation/DaedalusSimulation.java b/src/ch/epfl/maze/simulation/DaedalusSimulation.java new file mode 100644 index 0000000..2082772 --- /dev/null +++ b/src/ch/epfl/maze/simulation/DaedalusSimulation.java @@ -0,0 +1,364 @@ +package ch.epfl.maze.simulation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import ch.epfl.maze.graphics.Animation; +import ch.epfl.maze.physical.Animal; +import ch.epfl.maze.physical.Daedalus; +import ch.epfl.maze.physical.Predator; +import ch.epfl.maze.physical.Prey; +import ch.epfl.maze.physical.World; +import ch.epfl.maze.util.Action; +import ch.epfl.maze.util.Direction; +import ch.epfl.maze.util.Vector2D; + +/** + * Simulation of a predation environment. Handles the next moves of every + * predator and prey in a Daedalus, as well as the animation by notifying + * changes to it. The simulation finishes when every prey has been caught. + * + */ + +public final class DaedalusSimulation implements Simulation { + + /* limit to the step counter, over which the animals are considered lost */ + public static final int COUNTER_LIMIT = 10000; + + /* simulation components */ + private Daedalus mDaedalus; + private Map> mArrivalTimes; + private int mStepCounter; + + /* collision check variables */ + private Map> mPreyMoves; + private Map> mPredatorMoves; + + /** + * Constructs a simulation with a {@code Daedalus} to simulate. + * + * @param daedalus + * The daedalus to simulate + */ + + public DaedalusSimulation(Daedalus daedalus) { + mDaedalus = daedalus; + mArrivalTimes = new TreeMap>(Collections.reverseOrder()); + mStepCounter = 0; + mPreyMoves = new HashMap>(); + mPredatorMoves = new HashMap>(); + } + + @Override + public void move(Animation listener) { + if (isOver()) { + return; + } + + // clears moves maps + mPreyMoves.clear(); + mPredatorMoves.clear(); + + // increments counter + mStepCounter++; + + // if counter exceeded the limit, it considers preys safe + if (mStepCounter > COUNTER_LIMIT) { + List preys = mDaedalus.getPreys(); + List safePreys = new LinkedList(); + for (Prey prey : preys) { + mDaedalus.removePrey(prey); + safePreys.add(prey); + } + + mArrivalTimes.put(Integer.MAX_VALUE, safePreys); // infinite + return; + } + + // asks predators and preys to move + movePredators(listener); + movePreys(listener); + + // checks collisions + checkCollisions(listener); + + // notifies animation that all the changes are done + if (listener != null) { + listener.doneUpdating(); + } + } + + @Override + public boolean isOver() { + return mDaedalus.isSolved(); + } + + @Override + public World getWorld() { + return mDaedalus; + } + + @Override + public int getSteps() { + return mStepCounter; + } + + @Override + public Map> getArrivalTimes() { + TreeMap> arrivalTimes = new TreeMap>(); + for (Map.Entry> entry : mArrivalTimes.entrySet()) { + int time = entry.getKey(); + List animals = new ArrayList(entry.getValue()); + arrivalTimes.put(time, animals); + } + + return arrivalTimes; + } + + @Override + public String getRecordTable() { + String recordTable = ""; + int position = 1; + for (Map.Entry> entry : mArrivalTimes.entrySet()) { + // only returns the 10 first + if (position > 10) { + return recordTable; + } + + for (Prey prey : entry.getValue()) { + if (entry.getKey() == Integer.MIN_VALUE) { + recordTable += "-- "; + recordTable += prey.getClass().getSimpleName(); + recordTable += " - never finished\n"; + } else { + recordTable += position + ". "; + recordTable += prey.getClass().getSimpleName(); + if (entry.getKey() == Integer.MAX_VALUE) { + recordTable += " - has survived\n"; + } else { + recordTable += " - " + entry.getKey() + " steps\n"; + } + } + } + position += entry.getValue().size(); + } + + return recordTable; + } + + @Override + public void restart() { + mDaedalus.reset(); + mArrivalTimes.clear(); + mStepCounter = 0; + } + + @Override + public void stop() { + List forgottenPreys = new LinkedList(); + for (Prey prey : mDaedalus.getPreys()) { + forgottenPreys.add(prey); + mDaedalus.removePrey(prey); + } + mArrivalTimes.put(Integer.MIN_VALUE, forgottenPreys); + } + + /** + * Moves the predators in the daedalus. + * + * @param listener + * The listener to which the function will notify the changes + * (can be null) + */ + + private void movePredators(Animation listener) { + List predators = mDaedalus.getPredators(); + for (int i = 0; i < predators.size(); i++) { + Predator predator = predators.get(i); + Vector2D position = predator.getPosition(); + Vector2D newPosition = position; + Direction[] choices = mDaedalus.getChoices(position); + + // tries to make predator move + Direction choice; + try { + choice = predator.move(choices, mDaedalus); + if (!predator.getPosition().equals(position)) { + System.err.println("Error : Predator position changed while choosing direction."); + System.err.println("\tDid you call setPosition(Vector2D) or update(Direction) ?\n"); + predator.setPosition(position); + choice = null; + } + } catch (Exception E) { + System.err.print("Exception occurred while moving animals: "); + E.printStackTrace(); + choice = null; + } + + // if predator could move + Action action; + if (choice != null) { + newPosition = position.addDirectionTo(choice); + + int x = newPosition.getX(); + int y = newPosition.getY(); + + if (mDaedalus.isFree(x, y)) { + action = new Action(choice, true); + } else { + newPosition = position; + action = new Action(choice, false); + choice = Direction.NONE; + } + + if (listener != null) { + // asks animation to draw corresponding action + listener.update(predator, i, action); + } + + predator.update(choice); + } else { + if (listener != null) { + // asks animation to draw a confused animal + action = new Action(Direction.NONE, false); + listener.update(predator, i, action); + } + } + + // records position changes to handle collisions + List moves = new ArrayList(); + moves.add(position); + moves.add(newPosition); + mPredatorMoves.put(predator, moves); + } + } + + /** + * Moves the preys in the daedalus. + * + * @param listener + * The listener to which the function will notify the changes + * (can be null) + */ + + private void movePreys(Animation listener) { + List preys = mDaedalus.getPreys(); + Action action; + Direction choice; + for (int i = 0; i < preys.size(); i++) { + Prey prey = preys.get(i); + Vector2D position = prey.getPosition(); + Vector2D newPosition = position; + Direction[] choices = mDaedalus.getChoices(position); + + // tries to make prey move + try { + choice = prey.move(choices, mDaedalus); + if (!prey.getPosition().equals(position)) { + System.err.println("Error : Prey position changed while choosing direction."); + System.err.println("\tDid you call setPosition(Vector2D) or update(Direction) ?\n"); + prey.setPosition(position); + choice = null; + } + } catch (Exception E) { + System.err.print("Exception occurred while moving animals: "); + E.printStackTrace(); + choice = null; + } + + // if prey could move + if (choice != null) { + newPosition = position.addDirectionTo(choice); + + int x = newPosition.getX(); + int y = newPosition.getY(); + + if (mDaedalus.isFree(x, y)) { + action = new Action(choice, true); + } else { + newPosition = position; + action = new Action(choice, false); + choice = Direction.NONE; + } + + if (listener != null) { + // draws animation + listener.update(prey, i + mDaedalus.getPredators().size(), action); + } + prey.update(choice); + } else { + if (listener != null) { + action = new Action(Direction.NONE, false); + listener.update(prey, i + mDaedalus.getPredators().size(), action); + } + } + + // records position changes to handle collisions + List moves = new ArrayList(); + moves.add(position); + moves.add(newPosition); + mPreyMoves.put(prey, moves); + } + } + + /** + * Checks collisions between predators and preys in {@codeO(n*m)}. A collision + * occurs if two animals land on the same tile, or when they run into each + * other. + *

+ * A special case is handled when animals run into each other. The animation + * is notified that an animal dies between two squares. + * + * @param listener + * The listener to which the function will notify the changes + * (can be null) + */ + + private void checkCollisions(Animation listener) { + List predators = mDaedalus.getPredators(); + List preys = mDaedalus.getPreys(); + + for (int i = 0; i < predators.size(); ++i) { + Predator a = predators.get(i); + List aChanges = mPredatorMoves.get(a); + for (int j = 0; j < preys.size(); ++j) { + Prey b = preys.get(j); + List bChanges = mPreyMoves.get(b); + + // position changes for animal a + Vector2D aOld = aChanges.get(0); + Vector2D aNew = aChanges.get(1); + // position changes for animal b + Vector2D bOld = bChanges.get(0); + Vector2D bNew = bChanges.get(1); + + // if (a.new == b.new) or (a.old == b.new and b.old == a.new) + boolean diesInBetween = aOld.equals(bNew) && bOld.equals(aNew); + boolean diesInPlace = aNew.equals(bNew); + + if (diesInPlace || diesInBetween) { + if (mDaedalus.hasPrey(b)) { + mDaedalus.removePrey(b); + + // records survival time + if (mArrivalTimes.get(mStepCounter) == null) { + mArrivalTimes.put(mStepCounter, new LinkedList()); + } + mArrivalTimes.get(mStepCounter).add(b); + + // asks animation to interrupt movement if it dies + // moving + if (listener != null && diesInBetween) { + listener.updateDying(j + predators.size()); + } + } + } + } + } + } +} -- cgit v1.2.3