Задача симулятор лифта
Задача на симулятор лифта, задача решена, все работает, но было отвергнуто словами что мне нужно подтянуть алгоритмы. Что под этим подразумевается, как еще можно решить задачу?
/**
* Написать программу «симулятор лифта».
* Программа запускается из коммандной строки, в качестве параметров задается:
* кол-во этажей в подъезде - N (от 5 до 20);
* высота одного этажа;
* скорость лифта при движении в метрах в секунду (ускорением пренебрегаем, считаем, что когда лифт едет - он сразу едет с определенной скоростью);
* время между открытием и закрытием дверей.
*
* После запуска программа должна постоянно ожидать ввода от пользователя и выводить действия лифта в реальном времени.
* События, которые нужно выводить:
* лифт проезжает некоторый этаж;
* лифт открыл двери;
* лифт закрыл двери.
*
* Возможный ввод пользователя:
* вызов лифта на этаж из подъезда;
* нажать на кнопку этажа внутри лифта.
*
* Считаем, что пользователь не может помешать лифту закрыть двери.
* Все данные, которых не хватает в задаче можно выбрать на свое усмотрение.
* В результате должен получиться компилируемый код (в случае с java предлагается писать код в одном файле).
*/
public class Test {
public static void main(String[] args) throws InterruptedException {
Elevator elevator = new Elevator(20, 3, 2, 2);
elevator.init();
}
private static class Elevator {
private static final long MILLISECONDS = 100; //1000
private final int doorTime;
private final int floors;
private final long floorSpeedSeconds;
private int currentFloor = 1;
private Elevator(int floors, int height, int speed, int doorTime) {
this.doorTime = doorTime;
this.floors = floors;
floorSpeedSeconds = height / speed * MILLISECONDS;
}
private void init() throws InterruptedException {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
Command command = new Command(scanner.nextLine());
if (command.targetFloor > floors) {
System.out.println("Target floor should be less than " + floors);
continue;
}
if (command.targetFloor > currentFloor) {
moveUp(command);
} else if (command.targetFloor < currentFloor) {
moveDown(command);
}
currentFloor = command.targetFloor;
openAndCloseDoor(doorTime);
}
}
private void printCurrentFloor(int i) {
System.out.println("Current floor is " + i);
}
private void openAndCloseDoor(int doorTime) throws InterruptedException {
System.out.println("Open door");
Thread.sleep(doorTime * MILLISECONDS);
System.out.println("Close door");
}
private void moveDown(Command command) throws InterruptedException {
for (int i = currentFloor; i >= command.targetFloor; i--) {
Thread.sleep(floorSpeedSeconds);
printCurrentFloor(i);
}
}
private void moveUp(Command command) throws InterruptedException {
for (int i = currentFloor; i <= command.targetFloor; i++) {
Thread.sleep(floorSpeedSeconds);
printCurrentFloor(i);
}
}
}
private static class Command {
private final PressType type;
private final int targetFloor;
private Command(String type) {
String[] commands = type.split(" ");
this.type = PressType.type(commands[0]);
this.targetFloor = parseInt(commands[1]);
}
}
private enum PressType {
IN("in"),
OUT("out");
private final String type;
PressType(String type) {
this.type = type;
}
private static PressType type(String s) {
return valueOf(s);
}
}
}
Ответы (4 шт):
Я лично думаю, что надо бы почитать SOLID и паттерны. И сделать по первому принципу единственной ответственности. А паттерн посмотреть в сторону Command и прочих поведенческих. Почему то у вас сам лифт и ожидает команды и двигается. Сделайте так чтоб с минимальными изменениями программа могла получать команды из файла из консоли из космоса. По поводу алгоритмов я не думаю что они исходили из этой задачи.
Фраза о реальном времени в условии, думаю, предполагает, что нужно уметь принимать новые команды в то время, как текущая(ие) уже выполняется(ются). Т.е. подход "прочитать команду - выполнить" не годится. Нужно оптимизировать работу лифта учитывая новые поступившие команды. С точки зрения алгоритмов в таком понимании задача гораздо интереснее и сложнее.
Я бы сделал задание по другому. Сделал бы класс лифт, от которого наследуются 2 класса кнопки вызова на этаж, и кнопки в самой кабине. У лифта будет только один метод - двигаться(вверх или вниз). все принимаемые команды от кнопок, загонять в какой-нибудь стек и выполнять по очереди.Если направление движения совпадает с вызовом, остановиться на этом этаже, и удалить из стэка.
Я бы сделал немножко по другому.
Для начала, там есть ремарка про реальное время, то есть, по идее, лифт должен кататься в своем потоке.
А если лифт в своем потоке и ещё принимает команды, то возникает вопрос синхронизации. Который легко решается, если команды выстроить в цепочку команд. Как это сделать? использовать Executors.newSingleThreadExecutor()
Далее, нажатие на кнопку совсем не означает, что лифт вдруг ломанется на тот этаж. Лифт может быть уже в движении, когда на кнопку нажали, и он может ехать в противоположном направлении. То есть, по идее, нажатие на кнопку просто дает знать об этом лифту, но когда лифт туда поедет - отдельный вопрос.
Конечно, в идеале, надо ещё учитывать, куда человек ехать хочет (наверх или вниз) - наверное это имелось ввиду под нажатиеи из подъезда / из лифта. Это несложно сделать, но я не хочу усложнять пример.
По сути, самый простецкий вариант будет такой: При нажатии на кнопку, просто пометить этаж и добавить задачу лифту сгонять вверх и вниз по всем отмеченным этажам. Если лифт уже едет, и наткнется на отмеченный этаж - то остановится и откроет двери.
Код выгляит как то так (я в java не сильно разбираюсь, так что пардон если что не так)
class Elevator {
private final long floorInterval;
private final long waitingInterval;
private int currentFloor = 0;
private boolean[] floorButtons;
наш ExecutorService
private ExecutorService executor = Executors.newSingleThreadExecutor();
public Elevator(int floors, long floorInterval, long waitingInterval) {
this.floorInterval = floorInterval;
this.waitingInterval = waitingInterval;
this.floorButtons = new boolean[floors];
}
Нажималка на кнопку
public void buttonPressedForFloor(final int floor) {
floorButtons[floor] = true;
executor.submit(() -> {
try {
this.moveUp();
this.moveDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
Проверка необходимости движения вверх
private void moveUp() throws InterruptedException {
for (int i = currentFloor; i < floorButtons.length; i++)
if (floorButtons[i]) {
moveTo(i);
return;
}
}
Проверка необходимости движения вниз
private void moveDown() throws InterruptedException {
for (int i = currentFloor; i > 0; i--)
if (floorButtons[i]) {
moveTo(i);
return;
}
}
Само передвижение
private void moveTo(int targetFloor) throws InterruptedException {
int step = 1;
if (targetFloor < currentFloor) step = -1;
while (currentFloor != targetFloor) {
Thread.sleep(floorInterval);
currentFloor += step;
sendMessage("CURRENT FLOOR: " + currentFloor);
if (floorButtons[currentFloor]) {
floorButtons[currentFloor] = false;
doorOpenClose();
}
}
}
Вспомогательный код
private void doorOpenClose() throws InterruptedException {
sendMessage("DOORS OPENED");
Thread.sleep(waitingInterval);
sendMessage("DOORS CLOSED");
}
private static void sendMessage(String message) {
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME) + " " + message);
}
public void stop() {
executor.shutdown();
}
}
Запустить эту радость можно так
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("input number of floors: ");
int numOfFlors = scanner.nextInt();
System.out.println("input floor height (m): ");
double floorHeight = scanner.nextDouble();
System.out.println("input floor velocity (m/s): ");
double floorVelocity = scanner.nextDouble();
System.out.println("input floor doors time (seconds): ");
long waitingInterval = scanner.nextLong() * 1000;
long floorTime = (long) (1000.0 * floorHeight / floorVelocity);
Elevator elevator = new Elevator(numOfFlors, floorTime, waitingInterval);
scanner.nextLine();
while (true) {
String line = scanner.nextLine();
if ("q".equals(line)) {
elevator.stop();
return;
}
try {
int nextFloor = Integer.parseInt(line);
if (nextFloor < 1 || nextFloor > numOfFlors) {
System.out.println("Wrong floor. Try again.");
} else {
elevator.buttonPressedForFloor(nextFloor);
}
} catch (Exception e) {
System.out.println(line + " not a number");
}
}
}
Получается что то вроде такого
