Amazon Interview Question
Software Engineer / Developersggg.. what if an emergency happens which has no an appropriate EmergencyRequest type ?
e.g., biohazard ?;))
and who's gonna instantiate this EmergencyRequest
when it happens ? personnel ? )) everyone dive into panic gg
furthermore: you are nto allowed to use elevator when fire alarm
public class Elevator {
private float location = 0;
private Direction direction = Direction.UP;
private State state = State.STOPPED;
private Door door = Door.CLOSED;
private Thread processingThread;
private Thread listeningThread;
public class Request {
public long time;
public Integer floor;
public Direction direction;
public Request(long time, Integer floor, Direction direction) {
this.time = time;
this.floor = floor;
this.direction = direction;
}
}
public enum Direction {
UP, DOWN
}
public enum State {
MOVING, STOPPED
}
public enum Door {
OPEN, CLOSED
}
public Comparator<Request> upComparator = new Comparator<Request>() {
public int compare(Request u1, Request u2) {
return u1.floor.compareTo(u2.floor);
}
};
public Comparator<Request> downComparator = upComparator.reversed();
private Queue<Request> upQueue = new PriorityQueue<>(upComparator);
private Queue<Request> currentQueue = upQueue;
private Queue<Request> downQueue = new PriorityQueue<>(downComparator);
public void call(int floor, Direction direction) {
if (direction == Direction.UP) {
if (floor >= location) {
currentQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
} else {
upQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
}
} else {
if (floor <= location) {
currentQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
} else {
downQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
}
}
}
public void go(int floor) {
call(floor, direction);
}
public void process() {
while (true) {
if (!upQueue.isEmpty() && !downQueue.isEmpty()) {
Request r = currentQueue.poll();
if (r != null) {
goToFloor(r.floor);
} else {
preProcessNextQueue();
}
}
}
}
public void goToFloor(int floor) {
state = State.MOVING;
for (float i = location; i <= floor; i = (float) (i + 0.1)) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
location = floor;
door = Door.OPEN;
state = State.STOPPED;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
door = Door.CLOSED;
}
private void preProcessNextQueue() {
if (getLowestTimeUpQueue() > getLowestTimeDownQueue()) {
this.direction = Direction.UP;
currentQueue = upQueue;
upQueue = new PriorityQueue<>(upComparator);
} else {
this.direction = Direction.DOWN;
currentQueue = downQueue;
downQueue = new PriorityQueue<>(downComparator);
}
}
private long getLowestTimeUpQueue() {
long lowest = Long.MAX_VALUE;
for (Request r : upQueue) {
if (r.time < lowest)
lowest = r.time;
}
return lowest;
}
private long getLowestTimeDownQueue() {
long lowest = Long.MAX_VALUE;
for (Request r : downQueue) {
if (r.time < lowest)
lowest = r.time;
}
return lowest;
}
public class Process implements Runnable {
@Override
public void run() {
process();
}
}
public class Listen implements Runnable {
@Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(90000);
while (true) {
Socket socket = serverSocket.accept();
Thread thread = new Thread(new Worker(socket));
thread.start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Worker implements Runnable {
private Socket s;
public Worker(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(s.getInputStream()));
String line;
while (true) {
if ((line = reader.readLine()) != null) {
String[] tokens = line.split(" ");
if(tokens.length == 3 && tokens[0].equals("call")){
call(Integer.parseInt(tokens[1]), tokens[2].equals("up")?Direction.UP:Direction.DOWN);
}else if(tokens.length == 2 && tokens[0].equals("go")){
go(Integer.parseInt(tokens[1]));
}else{
s.getOutputStream().write("Wrong input".getBytes());
}
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Elevator elevator = new Elevator();
elevator.listeningThread = new Thread(elevator.new Listen());
elevator.listeningThread.start();
elevator.processingThread = new Thread(elevator.new Process());
elevator.processingThread.start();
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
OMG...Floor is not an Object. You are using the Process Oriented way but not Object Oriented way to handle this question.
The answer is you just need an elevator class. The elevator will save the floor information and current floor number. Then judge the current floor number and the number which it will go (from the user operation), and choose to go up or go down. very simple
I think its a typical example of command pattern. Elevator system will have set of slots where each buttons (commands) can be executed.
This way we can extend the elevator system by adding new buttons very easily and each button can test individually.
it would be nice to add these two variables
numOfStopsAhead
numOfStopsBehind
according to the direction and requested floor you can increment either
every stop decrements the first one
if the first one becomes 0, it is time to change direction and swap these 2 variables as well.
stop if both is 0
a floor request would increment the ahead one and set the direction and call start
--You can't design everything during the system. You need to show all operation and implement one. For example
/*
------------------------
Elevator System
------------------------
Use Cases :
1. Passanger/User wants to go to the different floor.
2. He request the floor number in the elevator system
3. Elevator picks the person
4. Elevator delivers the person to the floor.
-----------------
What if elevator is running ?
-> If it is going to the same direction, it will pick the person on its way
-> If it is open state, it will wait to get it running state
-> If elevator is in halt/maintainance state, it will not respond
-> If it is waiting state, it will start moving.
------------------ Alternate usecases----
-> Elevator has a maximum number of floor.
-> A user can request for call, alarm, stop, keep door open/close such commands
-> Elevator has preferrences like door will keep open for 5 seconds for loading or unloading.
------------------
Let's find out the classes, attribute and datastructure by doing language analysis
---------------------------------------------------------------------------------
1. Passanger
-> srcFloor
-> destinationFloor
*issueRequest(int dest)
*issueAlarm()
*issueStop()
2. Elevator
-> state
-> direction
-> speed
-> targetted Floors
*openDoor()
*moveUp()
*moveDown()
*stop()
*startAlarm()
3. State (Enum)
-> Running, Open, Idle, Stopped, Alarmed
4. Floor
-> number
-> isServiced
--------------------------------------------------------------------------------------
Command Pattern ( How Elevator will listen to request )
--------------------------------------------------------------------------------------
/*
/
class Elevator{
State currState;
int directon;
int speed;
Floor[] targettedFloors;
void openDoor()
{
//Implementation of open door
}
void closeDoor()
{
//Implementation of closing door
}
}
interface Request
{
boolean execute(Elevator e);
}
class DoorOpenRequest implements Request{
public boolean execute(Elevator e)
{
e.openDoor();
}
}
class CloseDoorRequest implements Request{
public boolean execute(Elevator e)
{
e.closecloseDoor();
}
}
--- If passanger wants to issue request
Command odCommand = new OpenDoorCommand(Elevator.getInstance());
odCommand.execute();
public class Elevator {
private float location = 0;
private Direction direction = Direction.UP;
private State state = State.STOPPED;
private Door door = Door.CLOSED;
private Thread processingThread;
private Thread listeningThread;
public class Request {
public long time;
public Integer floor;
public Direction direction;
public Request(long time, Integer floor, Direction direction) {
this.time = time;
this.floor = floor;
this.direction = direction;
}
}
public enum Direction {
UP, DOWN
}
public enum State {
MOVING, STOPPED
}
public enum Door {
OPEN, CLOSED
}
public Comparator<Request> upComparator = new Comparator<Request>() {
public int compare(Request u1, Request u2) {
return u1.floor.compareTo(u2.floor);
}
};
public Comparator<Request> downComparator = upComparator.reversed();
private Queue<Request> upQueue = new PriorityQueue<>(upComparator);
private Queue<Request> currentQueue = upQueue;
private Queue<Request> downQueue = new PriorityQueue<>(downComparator);
public void call(int floor, Direction direction) {
if (direction == Direction.UP) {
if (floor >= location) {
currentQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
} else {
upQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
}
} else {
if (floor <= location) {
currentQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
} else {
downQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
}
}
}
public void go(int floor) {
call(floor, direction);
}
public void process() {
while (true) {
if (!upQueue.isEmpty() && !downQueue.isEmpty()) {
Request r = currentQueue.poll();
if (r != null) {
goToFloor(r.floor);
} else {
preProcessNextQueue();
}
}
}
}
public void goToFloor(int floor) {
state = State.MOVING;
for (float i = location; i <= floor; i = (float) (i + 0.1)) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
location = floor;
door = Door.OPEN;
state = State.STOPPED;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
door = Door.CLOSED;
}
private void preProcessNextQueue() {
if (getLowestTimeUpQueue() > getLowestTimeDownQueue()) {
this.direction = Direction.UP;
currentQueue = upQueue;
upQueue = new PriorityQueue<>(upComparator);
} else {
this.direction = Direction.DOWN;
currentQueue = downQueue;
downQueue = new PriorityQueue<>(downComparator);
}
}
private long getLowestTimeUpQueue() {
long lowest = Long.MAX_VALUE;
for (Request r : upQueue) {
if (r.time < lowest)
lowest = r.time;
}
return lowest;
}
private long getLowestTimeDownQueue() {
long lowest = Long.MAX_VALUE;
for (Request r : downQueue) {
if (r.time < lowest)
lowest = r.time;
}
return lowest;
}
public class Process implements Runnable {
@Override
public void run() {
process();
}
}
public class Listen implements Runnable {
@Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(90000);
while (true) {
Socket socket = serverSocket.accept();
Thread thread = new Thread(new Worker(socket));
thread.start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Worker implements Runnable {
private Socket s;
public Worker(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(s.getInputStream()));
String line;
while (true) {
if ((line = reader.readLine()) != null) {
String[] tokens = line.split(" ");
if(tokens.length == 3 && tokens[0].equals("call")){
call(Integer.parseInt(tokens[1]), tokens[2].equals("up")?Direction.UP:Direction.DOWN);
}else if(tokens.length == 2 && tokens[0].equals("go")){
go(Integer.parseInt(tokens[1]));
}else{
s.getOutputStream().write("Wrong input".getBytes());
}
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Elevator elevator = new Elevator();
elevator.listeningThread = new Thread(elevator.new Listen());
elevator.listeningThread.start();
elevator.processingThread = new Thread(elevator.new Process());
elevator.processingThread.start();
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Elevator {
private float location = 0;
private Direction direction = Direction.UP;
private State state = State.STOPPED;
private Door door = Door.CLOSED;
private Thread processingThread;
private Thread listeningThread;
public class Request {
public long time;
public Integer floor;
public Direction direction;
public Request(long time, Integer floor, Direction direction) {
this.time = time;
this.floor = floor;
this.direction = direction;
}
}
public enum Direction {
UP, DOWN
}
public enum State {
MOVING, STOPPED
}
public enum Door {
OPEN, CLOSED
}
public Comparator<Request> upComparator = new Comparator<Request>() {
public int compare(Request u1, Request u2) {
return u1.floor.compareTo(u2.floor);
}
};
public Comparator<Request> downComparator = upComparator.reversed();
private Queue<Request> upQueue = new PriorityQueue<>(upComparator);
private Queue<Request> currentQueue = upQueue;
private Queue<Request> downQueue = new PriorityQueue<>(downComparator);
public void call(int floor, Direction direction) {
if (direction == Direction.UP) {
if (floor >= location) {
currentQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
} else {
upQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
}
} else {
if (floor <= location) {
currentQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
} else {
downQueue.add(new Request(System.currentTimeMillis(), floor,
direction));
}
}
}
public void go(int floor) {
call(floor, direction);
}
public void process() {
while (true) {
if (!upQueue.isEmpty() && !downQueue.isEmpty()) {
Request r = currentQueue.poll();
if (r != null) {
goToFloor(r.floor);
} else {
preProcessNextQueue();
}
}
}
}
public void goToFloor(int floor) {
state = State.MOVING;
for (float i = location; i <= floor; i = (float) (i + 0.1)) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
location = floor;
door = Door.OPEN;
state = State.STOPPED;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
door = Door.CLOSED;
}
private void preProcessNextQueue() {
if (getLowestTimeUpQueue() > getLowestTimeDownQueue()) {
this.direction = Direction.UP;
currentQueue = upQueue;
upQueue = new PriorityQueue<>(upComparator);
} else {
this.direction = Direction.DOWN;
currentQueue = downQueue;
downQueue = new PriorityQueue<>(downComparator);
}
}
private long getLowestTimeUpQueue() {
long lowest = Long.MAX_VALUE;
for (Request r : upQueue) {
if (r.time < lowest)
lowest = r.time;
}
return lowest;
}
private long getLowestTimeDownQueue() {
long lowest = Long.MAX_VALUE;
for (Request r : downQueue) {
if (r.time < lowest)
lowest = r.time;
}
return lowest;
}
public class Process implements Runnable {
@Override
public void run() {
process();
}
}
public class Listen implements Runnable {
@Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(90000);
while (true) {
Socket socket = serverSocket.accept();
Thread thread = new Thread(new Worker(socket));
thread.start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Worker implements Runnable {
private Socket s;
public Worker(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(s.getInputStream()));
String line;
while (true) {
if ((line = reader.readLine()) != null) {
String[] tokens = line.split(" ");
if(tokens.length == 3 && tokens[0].equals("call")){
call(Integer.parseInt(tokens[1]), tokens[2].equals("up")?Direction.UP:Direction.DOWN);
}else if(tokens.length == 2 && tokens[0].equals("go")){
go(Integer.parseInt(tokens[1]));
}else{
s.getOutputStream().write("Wrong input".getBytes());
}
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Elevator elevator = new Elevator();
elevator.listeningThread = new Thread(elevator.new Listen());
elevator.listeningThread.start();
elevator.processingThread = new Thread(elevator.new Process());
elevator.processingThread.start();
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I have tried to build a more complete system, but it has flaws.
Here is my design:
System class: handles the elevator calling algorithm, which request to send to which elevator, etc.
Elevator class: models an elevator
Request class: Models a request
- Anonymous April 19, 2011