Задача симулятор лифта

Задача на симулятор лифта, задача решена, все работает, но было отвергнуто словами что мне нужно подтянуть алгоритмы. Что под этим подразумевается, как еще можно решить задачу?


/**
 * Написать программу «симулятор лифта».
 * Программа запускается из коммандной строки, в качестве параметров задается:
 *      кол-во этажей в подъезде - 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 шт):

Автор решения: Aziz Umarov

Я лично думаю, что надо бы почитать SOLID и паттерны. И сделать по первому принципу единственной ответственности. А паттерн посмотреть в сторону Command и прочих поведенческих. Почему то у вас сам лифт и ожидает команды и двигается. Сделайте так чтоб с минимальными изменениями программа могла получать команды из файла из консоли из космоса. По поводу алгоритмов я не думаю что они исходили из этой задачи.

→ Ссылка
Автор решения: Roman Konoval

Фраза о реальном времени в условии, думаю, предполагает, что нужно уметь принимать новые команды в то время, как текущая(ие) уже выполняется(ются). Т.е. подход "прочитать команду - выполнить" не годится. Нужно оптимизировать работу лифта учитывая новые поступившие команды. С точки зрения алгоритмов в таком понимании задача гораздо интереснее и сложнее.

→ Ссылка
Автор решения: Perfect Voyage

Я бы сделал задание по другому. Сделал бы класс лифт, от которого наследуются 2 класса кнопки вызова на этаж, и кнопки в самой кабине. У лифта будет только один метод - двигаться(вверх или вниз). все принимаемые команды от кнопок, загонять в какой-нибудь стек и выполнять по очереди.Если направление движения совпадает с вызовом, остановиться на этом этаже, и удалить из стэка.

→ Ссылка
Автор решения: tym32167

Я бы сделал немножко по другому.

Для начала, там есть ремарка про реальное время, то есть, по идее, лифт должен кататься в своем потоке.

А если лифт в своем потоке и ещё принимает команды, то возникает вопрос синхронизации. Который легко решается, если команды выстроить в цепочку команд. Как это сделать? использовать 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");
        }
    }
}

Получается что то вроде такого

...

→ Ссылка