-
Notifications
You must be signed in to change notification settings - Fork 4
Submission A #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Submission A #6
Conversation
|
|
||
| ElevatorSnapshot currentElevatorSnapshot = | ||
| currentSnapshot.getElevatorSnapshot(maybeElevatorId.orElseThrow()); | ||
| assertEquals(human.getStartingFloor(), currentElevatorSnapshot.currentFloor(), | ||
| ERROR_MESSAGE_PRE | ||
| + "When a human enters an elevator, the elevator must be at the humans starting floor. But '%s' entered elevator with ID '%d' at a different floor.".formatted( | ||
| human, maybeElevatorId.orElseThrow())); | ||
| } | ||
|
|
||
| boolean exitedElevator = | ||
| previousState != Human.State.ARRIVED && currentState == Human.State.ARRIVED; | ||
| if (exitedElevator) { | ||
| assertTrue(currentHumanSnapshot.currentElevatorId().isEmpty(), ERROR_MESSAGE_PRE | ||
| + "When a human exits an elevator, they must not have a current elevator id anymore. But '%s' has.".formatted( | ||
| human)); | ||
|
|
||
| // Only if the human actually travelled around | ||
| if (human.getStartingFloor() != human.getDestinationFloor()) { | ||
| OptionalInt maybeElevatorId = previousHumanSnapshot.currentElevatorId(); | ||
| assertTrue(maybeElevatorId.isPresent(), ERROR_MESSAGE_PRE | ||
| + "When a human exits an elevator, they must have had a current elevator id previously. But '%s' does not.".formatted( | ||
| human)); | ||
|
|
||
| assertEquals(Human.State.TRAVELING_WITH_ELEVATOR, previousState, | ||
| "When a human exits an elevator, their previous state must be traveling. But '%s' was in state %s.".formatted( | ||
| human, previousState)); | ||
|
|
||
| ElevatorSnapshot currentElevatorSnapshot = | ||
| currentSnapshot.getElevatorSnapshot(maybeElevatorId.orElseThrow()); | ||
| assertEquals(human.getDestinationFloor(), | ||
| currentElevatorSnapshot.currentFloor(), ERROR_MESSAGE_PRE | ||
| + "When a human exits an elevator, the elevator must be at the humans destination floor. But '%s' exited elevator with ID '%d' at a different floor.".formatted( | ||
| human, maybeElevatorId.orElseThrow())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed important sanity checks
| return humans.stream() | ||
| .map(Human::getCurrentState) | ||
| .allMatch(Human.State.ARRIVED::equals); | ||
| return humanTravelingCount == 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(prob an optimization to avoid big iterations)
|
|
||
| public void addHuman(Human human) { | ||
| if (isDone()) { | ||
| throw new SimulationFinishedException("Can't add new human after simulation is finished!"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, but a IllegalStateException might have been more appropriate. but shows they can use exceptions, neat
| if (human.getCurrentState() != Human.State.ARRIVED) { | ||
| humanTravelingCount++; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isnt the initial state always not-arrived by definition? smells a bit
| @Override | ||
| public synchronized void onHumanArrived(Human human) { | ||
| if (humanTravelingCount > 0) { | ||
| humanTravelingCount--; //We trust that the human hasnt notified us twice. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kek. but okay
|
|
||
| @Override | ||
| public synchronized void onHumanArrived(Human human) { | ||
| if (humanTravelingCount > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defensive behavior smells, why not an exception? does this actually happen?
| */ | ||
| private Integer currentEnteredElevatorId; | ||
|
|
||
| private final List<HumanArrivedListener> listeners = new ArrayList<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
design-wise this is a bit weird. like, why would humans contact anyone when they arrived. more reasonable might be something like an elevator notifying the elevator system when a human leaves the elevator.
but even that is technically IRL not a thing - anyways, fair solution to the performance problem.
| if (currentState == State.ARRIVED) { | ||
| return; //dont want to notify listeners again for our arrival | ||
| } | ||
| this.currentState = State.ARRIVED; | ||
| for (var listener : listeners) { | ||
| listener.onHumanArrived(this); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this logic is easy to accidentally miss by directly setting the state. if such a logic is used, all state-changes should flow through a setter, not just for ARRIVED
| bestElevator = floorPanelSystem.bestElevator(destinationFloor, destinationFloor > startingFloor ? TravelDirection.UP : TravelDirection.DOWN); | ||
| if(bestElevator.getCurrentFloor() == startingFloor) { | ||
| this.currentEnteredElevatorId = bestElevator.getId(); | ||
| this.currentState = State.TRAVELING_WITH_ELEVATOR; | ||
| return; | ||
| } | ||
| floorPanelSystem.requestElevator(bestElevator,startingFloor); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this works but with respect to real life thats not a thing. humans dont get told which elevator to use and wait for, they press a button and when the door opens they enter, regardless of elevator ID
| if (destinationFloor == startingFloor) { | ||
| return; | ||
| } | ||
| bestElevator = floorPanelSystem.bestElevator(destinationFloor, destinationFloor > startingFloor ? TravelDirection.UP : TravelDirection.DOWN); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
method naming could be improved. its also unclear that this is essentially a getter/compute method as its missing any verb
| void requestElevator(Elevator bestElevator, int atFloor); | ||
| Elevator bestElevator(int atFloor, TravelDirection desiredTravelDirection); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing javadoc
| private final int floorsServed; | ||
| private int currentFloor; | ||
|
|
||
| private final List<Integer> floorRequests = new ArrayList<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a queue would prob be more appropriate
| public void incrementFloorByOne() { | ||
| if (currentFloor+1 > this.getTopFloor()) { | ||
| return; | ||
| } | ||
| currentFloor++; | ||
| } | ||
|
|
||
| public void decrementFloorByOne() { | ||
| if (currentFloor-1 < minFloor) { | ||
| return; | ||
| } | ||
| currentFloor--; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use of math.min/max would be more idiomatic but ok
|
|
||
| //if we have arrived at our floor, or we already are there, we remove the request | ||
| if (currentFloor == floorRequests.getFirst()) { | ||
| synchronized (this) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(the sync placement looks correct, neat)
| elevatorListeners.parallelStream().forEach(listener -> listener.onElevatorSystemReady(this)); | ||
| } | ||
|
|
||
| public static int floorAndElevatorDistance(int floor, Elevator elevator) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
method naming is confusing
| return Math.abs(elevator.getCurrentFloor()-floor); | ||
| } | ||
| @Override | ||
| public Elevator bestElevator(int atFloor, TravelDirection desiredTravelDirection) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
method naming is confusing
| for (var elevator : elevators) { | ||
| if (floorAndElevatorDistance(atFloor, elevator) < floorAndElevatorDistance(atFloor, candidates.stream().findAny().get())) { | ||
| candidates.clear(); | ||
| candidates.add(elevator); | ||
| } else if (floorAndElevatorDistance(atFloor, elevator) == floorAndElevatorDistance(atFloor, candidates.stream().findAny().get())) { | ||
| candidates.add(elevator); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this could benefit from some smaller improvements. for example saving the method call results in vars, using orElseThrow() instead of get() and some other smaller things maybe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
quite sophisticated implementation:
- elevators serve humans with a request-queue (FIFO)
- the elevator system picks the "best elevator" for each humans request based on which one is closest and then breaks ties by least amount of work per elevator (nice)
- humans wait for their assigned elevator id (kinda unrealistic, but works)
- extra mile: added multithreading/syncing, perf improvement by using "human arrived counter based on listener" instead of iterating every human every step
- the code quality is ok. not very clean, method names, missing javadoc, ... but readable :)
Submission by user A