diff --git a/Contest/Assignment/src/org/togetherjava/event/elevator/Main.java b/Contest/Assignment/src/org/togetherjava/event/elevator/Main.java
index e9e4159..18cb393 100644
--- a/Contest/Assignment/src/org/togetherjava/event/elevator/Main.java
+++ b/Contest/Assignment/src/org/togetherjava/event/elevator/Main.java
@@ -19,11 +19,11 @@ public static void main(final String[] args) {
// Eventually try out the randomly generated systems. If you want to debug a problem you encountered
// with one of them, note down the seed that it prints at the beginning and then use the variant that takes this seed.
// That way, it will generate the same system again, and you can repeat the test.
- Simulation simulation = Simulation.createSingleElevatorSingleHumanSimulation();
- // Simulation simulation = Simulation.createSimpleSimulation();
- // Simulation simulation = Simulation.createRandomSimulation(5, 50, 10);
- // Simulation simulation = Simulation.createRandomSimulation(putDesiredSeedHere, 5, 50, 10);
-
+// Simulation simulation = Simulation.createSingleElevatorSingleHumanSimulation();
+// Simulation simulation = Simulation.createSimpleSimulation();
+ Simulation simulation = Simulation.createRandomSimulation(5, 100, 10);
+// Simulation simulation = Simulation.createRandomSimulation(3, 100, 100000, 100);
+// Simulation simulation = Simulation.createCustomSimulation();
simulation.printSummary();
System.out.println("Starting simulation...");
@@ -35,7 +35,7 @@ public static void main(final String[] args) {
simulation.step();
simulation.prettyPrint();
- if (simulation.getStepCount() >= 100_000) {
+ if (simulation.getStepCount() >= 100_00) {
throw new IllegalStateException("Simulation aborted. All humans should have arrived"
+ " by now, but they did not. There is likely a bug in your code.");
}
diff --git a/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/Elevator.java b/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/Elevator.java
index 51333b2..b8e0fd8 100644
--- a/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/Elevator.java
+++ b/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/Elevator.java
@@ -1,8 +1,10 @@
package org.togetherjava.event.elevator.elevators;
-import java.util.StringJoiner;
+import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
+import static org.togetherjava.event.elevator.elevators.ElevatorSystem.mod;
+
/**
* A single elevator that can serve a given amount of floors.
*
@@ -16,6 +18,10 @@ public final class Elevator implements ElevatorPanel {
private final int minFloor;
private final int floorsServed;
private int currentFloor;
+ private int numberOfHumansAboard;
+ private int humanExited;
+ private List requestedDestinationFloors;
+ private TravelDirection travellingDirection;
/**
* Creates a new elevator.
@@ -37,6 +43,7 @@ public Elevator(int minFloor, int floorsServed, int currentFloor) {
this.minFloor = minFloor;
this.currentFloor = currentFloor;
this.floorsServed = floorsServed;
+ this.requestedDestinationFloors = new ArrayList<>();
}
@Override
@@ -57,12 +64,20 @@ public int getCurrentFloor() {
return currentFloor;
}
+ public TravelDirection getTravellingDirection() {
+ return travellingDirection;
+ }
+
@Override
public void requestDestinationFloor(int destinationFloor) {
// TODO Implement. This represents a human or the elevator system
// itself requesting this elevator to eventually move to the given floor.
// The elevator is supposed to memorize the destination in a way that
// it can ensure to eventually reach it.
+ requestedDestinationFloors.add(destinationFloor);
+ if(destinationFloor > currentFloor) travellingDirection = TravelDirection.UP;
+ else if(destinationFloor < currentFloor) travellingDirection = TravelDirection.DOWN;
+ else travellingDirection = null;
System.out.println("Request for destination floor received");
}
@@ -76,15 +91,91 @@ public void moveOneFloor() {
// meaning that the average time waiting (either in corridor or inside the elevator)
// is minimized across all humans.
// It is essential that this method updates the currentFloor field accordingly.
+ if(requestedDestinationFloors.isEmpty()) {
+ lastResort();
+ return;
+ }
+ sortingList();
+ int currentRequest = requestedDestinationFloors.getLast();
+ if(currentRequest > currentFloor) {
+ currentFloor++;
+ travellingDirection = TravelDirection.UP;
+ }
+ else if(currentRequest < currentFloor) {
+ currentFloor--;
+ travellingDirection = TravelDirection.DOWN;
+ }
+ else {
+ requestedDestinationFloors.removeLast();
+ removeRequests();
+ }
System.out.println("Request to move a floor received");
}
+ /**
+ * It is possible that the requests ends for the current elevator but there are still humans onboard.
+ * In that case the paternoster is the last resort to make sure the humans onboard reach the destination floor.
+ */
+ private void lastResort() {
+ if(currentFloor == minFloor) travellingDirection = TravelDirection.UP;
+ else if(currentFloor == (minFloor + floorsServed -1)) travellingDirection = TravelDirection.DOWN;
+ else if(numberOfHumansAboard != 0) {
+ if(travellingDirection == TravelDirection.UP) currentFloor++;
+ else if(travellingDirection == TravelDirection.DOWN) currentFloor--;
+ }
+ }
+
+ /**
+ * For instance, a number of humans can exit to the current floor.
+ * But the request for the current floor can make the elevator come to the current floor again or stay at it for consecutive steps.
+ * To prevent such loss of steps, this method removes the number of request according to the number of humans exited.
+ */
+ private void removeRequests() {
+ for(int i = 0; i < humanExited; i++) {
+ for(int j = 0; j < requestedDestinationFloors.size(); j++) {
+ if(requestedDestinationFloors.get(j) == currentFloor) {
+ requestedDestinationFloors.remove(j);
+ humanExited--;
+ j--;
+ }
+ }
+ }
+ }
+
+ /**
+ * To sort the list based on how far the requested floor is from the current floor
+ * The idea is to make the elevator go to the nearest or farthest request based on strategy.
+ */
+
+ private void sortingList() {
+ for(int i = 0; i < requestedDestinationFloors.size() - 1; i++) {
+ if(mod(requestedDestinationFloors.get(i) - currentFloor) < mod(requestedDestinationFloors.get(i+1)) - currentFloor) {
+ int temp = requestedDestinationFloors.get(i + 1);
+ requestedDestinationFloors.remove(i + 1);
+ requestedDestinationFloors.add(i + 1,requestedDestinationFloors.get(i));
+ requestedDestinationFloors.remove(i);
+ requestedDestinationFloors.add(i,temp);
+ }
+ }
+ }
+
+ @Override
+ public void enteredElevator() {
+ numberOfHumansAboard++;
+ }
+
+ @Override
+ public void exitedElevator() {
+ numberOfHumansAboard--;
+ humanExited++;
+ }
+
@Override
public synchronized String toString() {
return new StringJoiner(", ", Elevator.class.getSimpleName() + "[", "]").add("id=" + id)
.add("minFloor=" + minFloor)
.add("floorsServed=" + floorsServed)
- .add("currentFloor=" + currentFloor)
+ .add("currentFloor=" + this.currentFloor)
.toString();
}
}
diff --git a/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/ElevatorPanel.java b/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/ElevatorPanel.java
index 386ec77..669869e 100644
--- a/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/ElevatorPanel.java
+++ b/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/ElevatorPanel.java
@@ -25,4 +25,15 @@ public interface ElevatorPanel {
* @param destinationFloor the desired destination, must be within the range served by this elevator
*/
void requestDestinationFloor(int destinationFloor);
+
+
+ /**
+ * Counts the number of humans exited the elevator and updates the number of humans aboard counter.
+ */
+ void exitedElevator();
+
+ /**
+ * Counts the number of humans entered the elevator.
+ */
+ void enteredElevator();
}
diff --git a/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/ElevatorSystem.java b/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/ElevatorSystem.java
index fadfe56..49f3b1c 100644
--- a/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/ElevatorSystem.java
+++ b/Contest/Assignment/src/org/togetherjava/event/elevator/elevators/ElevatorSystem.java
@@ -2,8 +2,7 @@
import org.togetherjava.event.elevator.humans.ElevatorListener;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
/**
* System controlling all elevators of a building.
@@ -16,6 +15,7 @@ public final class ElevatorSystem implements FloorPanelSystem {
private final List elevators = new ArrayList<>();
private final List elevatorListeners = new ArrayList<>();
+
public void registerElevator(Elevator elevator) {
elevators.add(elevator);
}
@@ -39,9 +39,48 @@ public void requestElevator(int atFloor, TravelDirection desiredTravelDirection)
// The human can then enter the elevator and request their actual destination within the elevator.
// Ideally this has to select the best elevator among all which can reduce the time
// for the human spending waiting (either in corridor or in the elevator itself).
+
+ final Elevator bestElevator = getBestElevator(atFloor, desiredTravelDirection);
+ bestElevator.requestDestinationFloor(atFloor);
+
System.out.println("Request for elevator received");
}
+ /**
+ * Cases covered :-
+ * 1. Lift has no requests, that means travelling direction is null. This makes sure each and every elevator moves to
+ * take requests from humans.
+ * 2. Lift has requests, and it'll go in the direction of the said human currently requesting.
+ * This prioritises that the human requesting hops in the elevator moving in their direction.
+ * 3.Lift has requests, and it'll go against the direction of the said human currently requesting.
+ * This ensures that humans will get a lift coming in there direction even if they may have to wait longer.
+ *
+ * @param atFloor the floor from which the human is requesting from.
+ * @param desiredTravelDirection the direction said human wants to go, this will help to provide them the best lift.
+ * @return
+ */
+ private Elevator getBestElevator(int atFloor, TravelDirection desiredTravelDirection) {
+ Elevator bestElevator = elevators.getFirst();
+ for(Elevator elevator : elevators) {
+ if(elevator.getTravellingDirection() == null && mod((bestElevator.getCurrentFloor() - atFloor)) > mod((elevator.getCurrentFloor() - atFloor))) {
+ bestElevator = elevator;
+ }
+ else if(elevator.getTravellingDirection() == desiredTravelDirection && mod((bestElevator.getCurrentFloor() - atFloor)) > mod((elevator.getCurrentFloor() - atFloor))) {
+ bestElevator = elevator;
+ }
+ else if(mod((bestElevator.getCurrentFloor() - atFloor)) > mod((elevator.getCurrentFloor() - atFloor))) {
+ bestElevator = elevator;
+ }
+ }
+ return bestElevator;
+ }
+
+ static int mod(int num) {
+ int modValue = num;
+ if(modValue < 0) modValue *= -1;
+ return modValue;
+ }
+
public void moveOneFloor() {
elevators.forEach(Elevator::moveOneFloor);
elevators.forEach(elevator -> elevatorListeners.forEach(listener -> listener.onElevatorArrivedAtFloor(elevator)));
diff --git a/Contest/Assignment/src/org/togetherjava/event/elevator/humans/ElevatorListener.java b/Contest/Assignment/src/org/togetherjava/event/elevator/humans/ElevatorListener.java
index a124b1b..67e348a 100644
--- a/Contest/Assignment/src/org/togetherjava/event/elevator/humans/ElevatorListener.java
+++ b/Contest/Assignment/src/org/togetherjava/event/elevator/humans/ElevatorListener.java
@@ -25,4 +25,5 @@ public interface ElevatorListener {
* relevant (i.e. humans that can enter the elevator).
*/
void onElevatorArrivedAtFloor(ElevatorPanel elevatorPanel);
+
}
diff --git a/Contest/Assignment/src/org/togetherjava/event/elevator/humans/Human.java b/Contest/Assignment/src/org/togetherjava/event/elevator/humans/Human.java
index 0af2511..2265078 100644
--- a/Contest/Assignment/src/org/togetherjava/event/elevator/humans/Human.java
+++ b/Contest/Assignment/src/org/togetherjava/event/elevator/humans/Human.java
@@ -2,9 +2,11 @@
import org.togetherjava.event.elevator.elevators.ElevatorPanel;
import org.togetherjava.event.elevator.elevators.FloorPanelSystem;
+import org.togetherjava.event.elevator.elevators.TravelDirection;
import java.util.OptionalInt;
import java.util.StringJoiner;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* A single human that starts at a given floor and wants to
@@ -14,9 +16,12 @@
* for example requesting an elevator, eventually entering and exiting them.
*/
public final class Human implements ElevatorListener {
+ private static final AtomicInteger NEXT_ID = new AtomicInteger(0);
+ private final int id;
private State currentState;
private final int startingFloor;
private final int destinationFloor;
+ private boolean requestedDestinationFloor;
/**
* If the human is currently inside an elevator, this is its unique ID.
* Otherwise, this is {@code null} to indicate that the human is currently on the corridor.
@@ -36,13 +41,16 @@ public Human(int startingFloor, int destinationFloor) {
if (startingFloor <= 0 || destinationFloor <= 0) {
throw new IllegalArgumentException("Floors must be at least 1");
}
-
+ this.id = NEXT_ID.getAndIncrement();
this.startingFloor = startingFloor;
this.destinationFloor = destinationFloor;
-
- currentState = State.IDLE;
+ this.requestedDestinationFloor = false;
+ this.currentState = State.IDLE;
}
+ public int getId() {
+ return id;
+ }
public State getCurrentState() {
return currentState;
}
@@ -60,6 +68,15 @@ public void onElevatorSystemReady(FloorPanelSystem floorPanelSystem) {
// TODO Implement. The system is now ready and the human should leave
// their initial IDLE state, requesting an elevator by clicking on the buttons of
// the floor panel system. The human will now enter the WAITING_FOR_ELEVATOR state.
+ if(startingFloor == destinationFloor) {
+ currentState = State.ARRIVED;
+ return;
+ }
+ TravelDirection travelDirection;
+ if(startingFloor - destinationFloor > 0) travelDirection = TravelDirection.UP;
+ else travelDirection = TravelDirection.DOWN;
+ floorPanelSystem.requestElevator(startingFloor, travelDirection);
+ currentState = State.WAITING_FOR_ELEVATOR;
System.out.println("Ready-event received");
}
@@ -70,7 +87,25 @@ public void onElevatorArrivedAtFloor(ElevatorPanel elevatorPanel) {
// elevator and request their actual destination floor. The state has to change to TRAVELING_WITH_ELEVATOR.
// If the human is currently traveling with this elevator and the event represents
// arrival at the human's destination floor, the human can now exit the elevator.
- System.out.println("Arrived-event received");
+ if(currentEnteredElevatorId == null) {
+ if (currentState.equals(State.WAITING_FOR_ELEVATOR) && elevatorPanel.getCurrentFloor() == this.getStartingFloor()) {
+ currentEnteredElevatorId = elevatorPanel.getId();
+ if(!requestedDestinationFloor) {
+ elevatorPanel.requestDestinationFloor(this.destinationFloor);
+ elevatorPanel.enteredElevator();
+ requestedDestinationFloor = true;
+ }
+ this.currentState = State.TRAVELING_WITH_ELEVATOR;
+ }
+ }
+ else {
+ if (currentState.equals(State.TRAVELING_WITH_ELEVATOR) && elevatorPanel.getId() == this.currentEnteredElevatorId && elevatorPanel.getCurrentFloor() == this.getDestinationFloor()) {
+ this.currentState = State.ARRIVED;
+ this.currentEnteredElevatorId = null;
+ elevatorPanel.exitedElevator();
+ System.out.println("Arrived-event received");
+ }
+ }
}
public OptionalInt getCurrentEnteredElevatorId() {
diff --git a/Contest/Assignment/src/org/togetherjava/event/elevator/simulation/Simulation.java b/Contest/Assignment/src/org/togetherjava/event/elevator/simulation/Simulation.java
index 6f462c6..a10936e 100644
--- a/Contest/Assignment/src/org/togetherjava/event/elevator/simulation/Simulation.java
+++ b/Contest/Assignment/src/org/togetherjava/event/elevator/simulation/Simulation.java
@@ -64,6 +64,10 @@ public static Simulation createRandomSimulation(long seed, int amountOfElevators
return new Simulation(elevators, humans);
}
+ public static Simulation createCustomSimulation() {
+ return new Simulation(List.of(new Elevator(1, 10, 10)),
+ List.of(new Human(2, 2),new Human(1, 2)));
+ }
public Simulation(List elevators, List humans) {
this.elevators = new ArrayList<>(elevators);
@@ -96,7 +100,6 @@ public void start() {
public void step() {
elevatorSystem.moveOneFloor();
-
humanStatistics.forEach(HumanStatistics::step);
stepCount++;
}
diff --git a/Contest/Assignment/test/SimulationTest.java b/Contest/Assignment/test/SimulationTest.java
index 440f444..e22076a 100644
--- a/Contest/Assignment/test/SimulationTest.java
+++ b/Contest/Assignment/test/SimulationTest.java
@@ -41,7 +41,6 @@ void testSimpleSimulation() {
assertDoesNotThrow(() -> simulation.startAndExecuteUntilDone(stepLimit),
"Simulation obtained by 'Simulation.createSimpleSimulation()' was aborted because it could not finish in time.");
-
simulationFailed = false;
}
@@ -52,7 +51,6 @@ void testRandomSimulationSmall() {
assertDoesNotThrow(() -> simulation.startAndExecuteUntilDone(stepLimit),
"Simulation obtained by 'Simulation.createRandomSimulation(1, 5, 50, 10)' was aborted because it could not finish in time.");
-
simulationFailed = false;
}
@@ -61,17 +59,17 @@ void testRandomSimulationMedium() {
Simulation simulation = Simulation.createRandomSimulation(2, 20, 1_000, 50);
int stepLimit = 10_000;
+
assertDoesNotThrow(() -> simulation.startAndExecuteUntilDone(stepLimit),
"Simulation obtained by 'Simulation.createRandomSimulation(2, 20, 1_000, 50)' was aborted because it could not finish in time.");
-
simulationFailed = false;
+
}
@Test
void testRandomSimulationBig() {
Simulation simulation = Simulation.createRandomSimulation(3, 100, 100_000, 100);
int stepLimit = 100_000;
-
assertDoesNotThrow(() -> simulation.startAndExecuteUntilDone(stepLimit),
"Simulation obtained by 'Simulation.createRandomSimulation(3, 100, 100_000, 100)' was aborted because it could not finish in time.");