Skip to content

Conversation

@Zabuzard
Copy link
Member

@Zabuzard Zabuzard commented Dec 1, 2025

Submission by user A

Comment on lines 95 to 127

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()));
Copy link
Member Author

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;
Copy link
Member Author

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!");
Copy link
Member Author

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

Comment on lines +123 to +125
if (human.getCurrentState() != Human.State.ARRIVED) {
humanTravelingCount++;
}
Copy link
Member Author

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.
Copy link
Member Author

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) {
Copy link
Member Author

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<>();
Copy link
Member Author

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.

Comment on lines +56 to +62
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);
}
Copy link
Member Author

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

Comment on lines +89 to +95
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);
Copy link
Member Author

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);
Copy link
Member Author

@Zabuzard Zabuzard Dec 1, 2025

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

Comment on lines +18 to +19
void requestElevator(Elevator bestElevator, int atFloor);
Elevator bestElevator(int atFloor, TravelDirection desiredTravelDirection);
Copy link
Member Author

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<>();
Copy link
Member Author

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

Comment on lines +82 to +93
public void incrementFloorByOne() {
if (currentFloor+1 > this.getTopFloor()) {
return;
}
currentFloor++;
}

public void decrementFloorByOne() {
if (currentFloor-1 < minFloor) {
return;
}
currentFloor--;
Copy link
Member Author

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) {
Copy link
Member Author

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) {
Copy link
Member Author

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) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

method naming is confusing

Comment on lines +48 to +53
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);
Copy link
Member Author

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

Copy link
Member Author

@Zabuzard Zabuzard left a 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 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants