Lab2-lift

This commit is contained in:
Imbus 2024-09-26 00:07:55 +02:00
parent 974547157c
commit 09cd85f364
7 changed files with 327 additions and 35 deletions

38
lift/src/LiftMain.java Normal file
View file

@ -0,0 +1,38 @@
import lift.LiftMonitor;
import lift.LiftThread;
import lift.LiftView;
import lift.PassengerThread;
public class LiftMain {
public static void main(String[] args) {
// Could be read from args
final int NBR_FLOORS = 12, MAX_PASSENGERS = 4;
LiftView view = new LiftView(NBR_FLOORS, MAX_PASSENGERS);
// LiftMonitor passed to all threads
LiftMonitor monitor = new LiftMonitor(view, NBR_FLOORS);
// Static array since the number of passengers is fixed
PassengerThread[] pass_threads = new PassengerThread[20];
for (PassengerThread p : pass_threads) {
p = new PassengerThread(view, monitor);
p.start();
}
LiftThread lift = new LiftThread(view, monitor);
lift.start();
// Rejoin all threads, in practice this is redundant
try {
// Passenger threads first
for (PassengerThread p : pass_threads) {
p.join();
}
lift.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

View file

@ -1,30 +1,27 @@
import lift.LiftView; import lift.LiftView;
import lift.Passenger; import lift.Passenger;
public class OnePersonRidesLift { public class OnePersonRidesLift {
public static void main(String[] args) {
final int NBR_FLOORS = 7, MAX_PASSENGERS = 4;
public static void main(String[] args) { LiftView view = new LiftView(NBR_FLOORS, MAX_PASSENGERS);
Passenger pass = view.createPassenger();
int fromFloor = pass.getStartFloor();
int toFloor = pass.getDestinationFloor();
final int NBR_FLOORS = 7, MAX_PASSENGERS = 4; pass.begin(); // walk in (from left)
if (fromFloor != 0) {
LiftView view = new LiftView(NBR_FLOORS, MAX_PASSENGERS); view.moveLift(0, fromFloor);
Passenger pass = view.createPassenger();
int fromFloor = pass.getStartFloor();
int toFloor = pass.getDestinationFloor();
pass.begin(); // walk in (from left)
if (fromFloor != 0) {
view.moveLift(0, fromFloor);
}
view.openDoors(fromFloor);
pass.enterLift(); // step inside
view.closeDoors();
view.moveLift(fromFloor, toFloor); // ride lift
view.openDoors(toFloor);
pass.exitLift(); // leave lift
pass.end(); // walk out (to the right)
} }
} view.openDoors(fromFloor);
pass.enterLift(); // step inside
view.closeDoors();
view.moveLift(fromFloor, toFloor); // ride lift
view.openDoors(toFloor);
pass.exitLift(); // leave lift
pass.end(); // walk out (to the right)
}
}

25
lift/src/lift/Door.java Normal file
View file

@ -0,0 +1,25 @@
package lift;
class Door {
private boolean open;
/** Create a new closed door */
public Door() {
open = false;
}
/** Returns true if door is open */
public boolean isOpen() {
return open;
}
/** Open the door */
public void open() {
open = true;
}
/** Close the door */
public void close() {
open = false;
}
}

View file

@ -0,0 +1,175 @@
package lift;
import java.util.Arrays;
enum Direction {
UP,
DOWN,
}
/** Lift monitor. Handles lift motion and various state. */
public class LiftMonitor {
/** the floor the lift is currently on */
private int floor;
/** Number of floors */
private int nfloors;
/** true if the lift is moving, false if standing still with doors open */
private boolean moving;
/** Current direction of the lift */
private Direction direction;
/** number of passengers waiting to enter the lift at the various floors */
private int[] waitEntry;
/** number of passengers (in lift) waiting to leave at the various floors */
private int[] waitExit;
/** number of passengers currently in the lift */
private int load;
/** view object passed from main */
private LiftView view;
/** State (open/closed) of door on current floor */
private Door door;
/** Counter of number of passengers currently entering the elevator */
private int passengersEntering;
/** Counter of number of passengers currently exiting the elevator */
private int passengersExiting;
/** Create new LiftMonitor */
public LiftMonitor(LiftView v, int floors) {
floor = 0;
nfloors = floors;
moving = true;
direction = Direction.UP;
door = new Door();
waitEntry = new int[nfloors];
waitExit = new int[nfloors];
load = 0;
view = v;
passengersEntering = 0;
passengersExiting = 0;
}
/** Increases the number of waiting passengers on given floor */
public synchronized void increaseWaitEntry(int passengerFloor) {
waitEntry[passengerFloor]++;
notifyAll();
}
/** Handles passengers waiting to enter arriving lift */
public synchronized void enterLift(int passengerFloor,
int passengerDestination) {
while (floor != passengerFloor || load == 4 || moving ||
passengersEntering == 4) {
try {
wait();
} catch (InterruptedException e) {
throw new Error("Monitor.enterLift interrupted " + e);
}
}
waitEntry[floor]--;
waitExit[passengerDestination]++;
load++;
passengersEntering++;
notifyAll();
}
/** Called after passengers has completed entry animation */
public synchronized void enterCompleted() {
passengersEntering--;
notifyAll();
}
/** Handles passengers waiting to exit lift */
public synchronized void exitLift(int passengerDestination) {
while (floor != passengerDestination) {
try {
wait();
} catch (InterruptedException e) {
throw new Error("Monitor.exitLift interrupted " + e);
}
}
waitExit[passengerDestination]--;
load--;
passengersExiting++;
notifyAll();
}
/** Called after passengers has completed exit animation */
public synchronized void exitCompleted() {
passengersExiting--;
notifyAll();
}
/**
* Handles the conditions when the elevator is to wait for passengers
* entering/exiting the lift and waiting when there are no passengers waiting
* on any floor.
*/
public synchronized int[] liftContinue() {
while (Arrays.stream(waitEntry).sum() == 0 &&
Arrays.stream(waitExit).sum() == 0) {
try {
wait();
} catch (InterruptedException e) {
throw new Error("LiftContinue no passengers interrupted " + e);
}
}
/** Stops the elevator to allow passengers to enter or exit */
while (waitEntry[floor] > 0 && load != 4 || waitExit[floor] > 0 ||
passengersEntering > 0 || passengersExiting > 0) {
if (!door.isOpen()) {
view.openDoors(floor);
door.open();
}
moving = false;
notifyAll();
try {
wait();
} catch (InterruptedException e) {
throw new Error("Monitor.liftContinue interrupted " + e);
}
}
if (!moving)
view.closeDoors();
if (door.isOpen())
door.close();
moving = true;
calculateDirection();
/**
* Sends the elevators current position and next position to the LiftThread
*/
int[] movingPositions = new int[2];
movingPositions[0] = floor;
movingPositions[1] = floor + (direction == Direction.UP ? 1 : -1);
return movingPositions;
}
/** Moves the elevator in the given direction */
public synchronized void incrementFloor() {
floor = floor + (direction == Direction.UP ? 1 : -1);
}
/**
* Handles calculation of elevator direction
* Changes the direction of the elevator if there are no passengers that wants
* to enter or exit on floors either above or below the elevator
*/
private void calculateDirection() {
if (Arrays.stream(waitEntry, floor, nfloors).sum() == 0 &&
Arrays.stream(waitExit, floor, nfloors).sum() == 0 && floor != 0) {
direction = Direction.DOWN;
} else if (Arrays.stream(waitEntry, 0, floor + 1).sum() == 0 &&
Arrays.stream(waitExit, 0, floor + 1).sum() == 0 && floor != 6) {
direction = Direction.UP;
} else if (floor == nfloors - 1) {
direction = Direction.DOWN;
} else if (floor == 0) {
direction = Direction.UP;
}
}
}

View file

@ -0,0 +1,20 @@
package lift;
/** Thread responsible for lift movement and rendering */
public class LiftThread extends Thread {
private LiftView view;
private LiftMonitor monitor;
public LiftThread(LiftView v, LiftMonitor m) {
view = v;
monitor = m;
}
public void run() {
while (true) {
int[] elevatorPositions = monitor.liftContinue();
view.moveLift(elevatorPositions[0], elevatorPositions[1]);
monitor.incrementFloor();
}
}
}

View file

@ -1,21 +1,24 @@
package lift; package lift;
public interface Passenger { public interface Passenger {
/** @return the floor the passenger starts at */ /** @return the floor the passenger starts at */
int getStartFloor(); int getStartFloor();
/** @return the floor the passenger is going to */ /** @return the floor the passenger is going to */
int getDestinationFloor(); int getDestinationFloor();
/** First, delay for 0..45 seconds. Then animate the passenger's walk, on the entry floor, to the lift. */ /**
void begin(); * First, delay for 0..45 seconds. Then animate the passenger's walk, on the
* entry floor, to the lift.
*/
void begin();
/** Animate the passenger's walk from the entry floor into the lift. */ /** Animate the passenger's walk from the entry floor into the lift. */
void enterLift(); void enterLift();
/** Animate the passenger's walk out of the lift, to the exit floor. */ /** Animate the passenger's walk out of the lift, to the exit floor. */
void exitLift(); void exitLift();
/** Animate the passenger's walk, on the exit floor, out of view. */ /** Animate the passenger's walk, on the exit floor, out of view. */
void end(); void end();
} }

View file

@ -0,0 +1,34 @@
package lift;
/** Responsible for a single passenger. */
public class PassengerThread extends Thread {
private LiftView view;
private LiftMonitor monitor;
public PassengerThread(LiftView v, LiftMonitor m) {
view = v;
monitor = m;
}
/** Drives a passenger through the lift phases */
public void run() {
while (true) {
Passenger p = view.createPassenger();
p.begin();
// Walk towards the lift
monitor.increaseWaitEntry(p.getStartFloor());
monitor.enterLift(p.getStartFloor(), p.getDestinationFloor());
p.enterLift();
// Passenger is now inside the lift, now exit
monitor.enterCompleted();
monitor.exitLift(p.getDestinationFloor());
p.exitLift();
// Despawn
monitor.exitCompleted();
p.end();
}
}
}