Моделирование очереди эспрессо

Меня попросили выполнить технический тест со следующей спецификацией, но мое решение было отклонено, и я не был выбран для доступной позиции (младший для «нормального» уровня, с 4 днями времени, чтобы закончить тест). Не могли бы вы указать, какие области нуждаются в улучшении моего решения?

  

В программной компании X инженеры работают лучше всего, когда потребляют одну чашку   эспрессо в час. Офисная эспрессо-машина имеет   очередь первого-первого-обслуживать, которая применяется ко всем, за исключением   некоторые «суперзабытые» инженеры, которые   не-суперзабытые. Среди конкурирующих супертуристов   принцип «первым пришел-первым-служи» снова применяется.

     

Внедрите симулятор для этой машины эспрессо. вход   параметрами являются число инженеров, вероятность того, что инженер   становится чрезмерно занятым в какой-то единице времени, и как долго они остаются   супер-занят.

И мое решение в Python 3.4: ( версия GitHub )

machine.py

import msvcrt # Windows-only non-blocking input. Universal would need a lot more things
import random
from classes.espresso import Espresso
from classes.queue import Queue
from classes.coffeeenum import CoffeeEnum
from classes.order import Order

# Launch the machine
num_engineers = 1705
chance_superbusy = 25 # percent
max_time_superbusy = 120 # minutes
espresso_machine = Espresso(num_engineers, chance_superbusy, max_time_superbusy)
espresso_machine.start()

# Setup a few things
queue = Queue()
queue_id = 0
coffee_name = CoffeeEnum()
superbusy = False

# Run the show!
espresso_machine.display_coffee_choices()
while True:
    if queue.has_orders() and espresso_machine.is_ready():
        espresso_machine.brew(queue.get_next(), queue)

    # Read input to get new orders and enter superbusy mode
    if msvcrt.kbhit():
        # There's a chance the engineer is superbusy!
        if random.randrange(0, 100) < chance_superbusy:
            print("By surprise, you are now superbusy!")
            superbusy = True

        input = msvcrt.getch().decode("ascii").upper()
        # Engineer can also choose to be superbusy to skip the line (hmm...)
        if input == "Y":
            print("You are superbusy! Your order now has priority.")
            superbusy = True
        if input == "S":
            queue.status()
        if input.isdigit():
            if int(input) in range(1, 6):
                print("You ordered:", coffee_name.get_name(input))
                queue_id += 1
                print("Your queue ID is", queue_id)
                new_order = [queue_id, input, superbusy]
                queue.append(new_order)
                superbusy = False
                print("Ready for a new order.")

Классы /queue.py:

from classes.coffeeenum import CoffeeEnum
from classes.names import Names

class Queue:
    normal_queue = []
    super_queue = []
    # Gets names of coffee types
    coffee_enum = CoffeeEnum()
    # Connect queue ID with a person name
    names = Names()

    def __init__(self):
        print("Queue is ready")
        print("----------")

    def get_next(self):
        if self.super_queue:
            return self.super_queue[0]
        elif self.normal_queue:
            return self.normal_queue[0]

    def has_orders(self):
        if self.super_queue or self.normal_queue:
            return True
        else:
            return False

    def status(self):       
        if self.has_orders():
            print("Queue contains:")
            print("=====")
            if self.super_queue:
                print("> Superbusy orders:")
                for order in self.super_queue:
                    print(self.names.get_name(order[0]), 
                          "ordered:", self.coffee_enum.get_name(order[1]))
            if self.normal_queue:
                print("> Normal orders:")
                for order in self.normal_queue:
                    print(self.names.get_name(order[0]), 
                          "ordered:", self.coffee_enum.get_name(order[1]))
            print("=====")
        else:
            print("Queue is empty! Ready for orders...")

    def append(self, list_order):
        print("> Received order:", 
              self.coffee_enum.get_name(list_order[1]), 
              "for", self.names.get_name(list_order[0]), 
              "(Superbusy:", list_order[2], ")")
        if list_order[2]: # Superbusy
            self.super_queue.append(list_order)
        else:
            self.normal_queue.append(list_order)

    def remove_order(self, list_order):
        if list_order:
            if list_order[2]: # Superbusy order
                self.super_queue.remove(list_order)
            else:
                self.normal_queue.remove(list_order)

Классы /espresso.py:

from time import time
from classes.queue import Queue

class Espresso:
    num_engineers = 0
    chance_superbusy = 0 # percent
    max_time_superbusy = 0 # minutes
    is_running = False
    is_brewing = False
    brew_started_time = 0
    brew_ready_time = time() + 2 # +2 to prevent unneeded message on launch
    queue = 0
    current_brew = 0

    def __init__(self, num_engineers, chance_superbusy, max_time_superbusy):
        print("Espresso is booting...")
        print("> Engineer count:", num_engineers)
        print("> Chance superbusy:", chance_superbusy, "%")
        print("> Max time being superbusy:", max_time_superbusy, "minutes")

    def start(self):
        is_running = True
        print("Espresso machine started OK")
        print("> Press any key except A-Z or 0-9 to exit")

    def display_coffee_choices(self):
        print("Pick your poison, Mr. Engineer! \n"
              "If you are superbusy, press (Y) for priority lane! \n"
              "(S) for Queue Status")
        print("1 - Espresso")
        print("2 - Cappuccino")
        print("3 - Latte")
        print("4 - Macchiato")
        print("5 - Irish Coffee")
        return "" # Otherwise will display "None"

    def is_ready(self):
        if time() >= self.brew_ready_time and self.is_brewing:
            print("Brew ready!")
            self.queue.remove_order(self.current_brew)
            if not self.queue.has_orders():
                print("Queue empty, ready for new orders!")
            self.is_brewing = False
        if self.is_brewing:
            return False
        else:
            return True

    def brew(self, coffee, queue):
        if queue.has_orders():
            self.queue = queue
            self.current_brew = coffee
            print("Brewing now... ready in 15 seconds!")
            self.brew_started_time = time()
            self.brew_ready_time = time() + 15
            self.is_brewing = True

Классы /order.py:

from classes.coffeeenum import CoffeeEnum

class Order:
    id = 0
    product = 0
    is_superbusy = False

    def __init__(self, list_order):
        # This is used to get the coffee names from the id
        coff = CoffeeEnum()

        # Order comes in as a list: [id, product, boolean superbusy]
        self.id = list_order[0]
        self.product = coff.get_name(list_order[1])
        self.is_superbusy = list_order[2]

Классы /names.py:

import random

class Names:
    def get_name(self, id):
        id = int(id)
        # Keep value in 0-9 range for demo purposes
        if id >= 10:
            id = random.randint(0, 9)
        return {
            1: "Albert",
            2: "Benjamin",
            3: "Charles",
            4: "Dmitri",
            5: "Euclid",
            6: "Francis",
            7: "Gustav",
            8: "Hermann",
            9: "Isaac",
            0: "John",
        }.get(id, "Bjarne")

Классы /names.py:

class CoffeeEnum:
    def get_name(self, id):
        id = int(id)
        return {
            1: "Espresso",
            2: "Cappuccino",
            3: "Latte",
            4: "Macchiato",
            5: "Irish Coffee",
        }.get(id, "Coffee")
11 голосов | спросил Juha Untinen 11 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 11 Sep 2014 10:10:37 +0400 2014, 10:10:37

2 ответа


12

1. Неудачные требования

Программа не может выполнить следующие данные из спецификации:

  1. В спецификации говорится: «Входные параметры ...», но эти параметры реализованы как глобальные переменные, а не как входы.

  2. Одним из параметров является «количество инженеров», но программа не использует этот номер; он даже не представляет инженеров вообще.

  3. Другим параметром является «вероятность того, что инженер станет суперзанятым в течение некоторой единицы времени » (мой акцент). Но то, что реализует программа, - это шанс, что текущий инженер станет супер-занятым при нажатии клавиши .

  4. Третий параметр - «как долго они остаются суперзабытыми», но в этой реализации инженер перестает быть суперзабытым, как только они разместили заказ.

2. Другие проблемы

  1. Нет документации.

  2. Мне кажется, что спецификация ищет симулятор в смысле " компьютерная модель явления »- программа, которую мы могли бы использовать для изучения таких вопросов, как« как меняется типичная длина очереди, когда мы меняем количество инженеров? » Но эта реализация - интерактивное моделирование, которое может быть не так полезно, потому что кто-то должен присматривать за ним, чтобы получить какие-либо результаты.

  3. Программа не может абстрагироваться от измерения времени. Это означает, что если какое-то событие занимает 15 секунд в симуляции, мы должны ждать 15 секунд в реальной жизни, чтобы это произошло. Это означает, что мы не можем использовать мощь компьютеров для имитации событий в тысячи или миллионы раз быстрее, чем они происходят.

  4. Программа содержит множество функций, отсутствовавших в спецификации, таких как имена инженеров, различные типы кофе, отчет о статусе очереди и т. д. Если спецификация была полностью реализована, такие дополнительные детали могут быть интересными, но в этих обстоятельствах это выглядит как отвлечение. (Также, учитывая, что вы выбрали имена для инженеров, действительно ли они все должны были быть мужскими именами?)

  5. Программа работает только в Windows!

  6. Есть много мелких проблем, которые указывают на отсутствие заботы и внимания. Существует класс Order, но он никогда не используется; класс Espresso поддерживает is_running и brew_started_time, но они не используются; Espresso.__init__ принимает параметры num_engineers, chance_superbusy, max_time_superbusy, но они просто распечатываются, а не в противном случае используется; модуль classs/espresso.py import Queue, но не используйте его.

3. Ответ модели

Спецификации редко предоставляют полное описание программы. Это означает, что почти всегда полезно записать проект design , который перечисляет и оправдывает принятые вами решения. Вот мои:

  1. В спецификации отсутствуют некоторые необходимые параметры для моделирования. Нам нужно добавить параметры для , как долго работает инженер, прежде чем принимать кофе-брейк и , как долго эспрессо берет заваривать .

  2. Я решил отвлечь понятие времени, проходящего в виде класса Schedule. Это обрабатывает события по порядку по их метке времени, которая является просто числом. Обоснование: нам не нужно разбираться со сложностью интерфейсов реального времени операционной системы; Кроме того, мы можем запускать симуляцию на любой скорости, которая нам нравится.

  3. Планировщик хранит будущие события в очереди приоритетов , реализованной как min-heap , используя ---- +: = 11 =: + ---- .Обоснование: может добавлять события и извлекать самое раннее событие в логарифмическом времени.

  4. Я решил представлять событие как функцию одного аргумента (время, в которое оно происходит). Обоснование: разделение проблем (планировщик не должен иметь никаких знаний о событиях); легко расширяемый с большим количеством событий.

  5. Я выполнил очередь для машины эспрессо как карту от инженера до времени, когда они присоединились к очереди. Приоритет инженеров с суперзанятыми инженерами над обычно занятыми инженерами реализуется, делая инженеров orderable , предоставляя им heapq . Обоснование: это гарантирует, что мы не сможем сделать ошибку, которая приводит к тому, что инженер находится в очереди несколько раз; он также избегает сложности, которая возникла бы, если бы у меня было две очереди (инженер может изменить статус суперзабытия в очереди, и это потребует от них изменения очереди).

  6. Я представил такие параметры, как «как долго работает инженер, прежде чем делать кофе-брейк» в форме случайные величины , реализованные как функции нулевых аргументов, возвращающих продолжительность. Обоснование: процессы реального мира имеют вариации в том, как долго они занимают; реализация дает нам гибкость, позволяющую легко изменить продолжительность продолжительности, если мы неправильно поняли требования к симуляции.

  7. В спецификации говорится: «шанс того, что инженер станет супер-занят за определенную единицу времени». Я понимаю, это означает, что время, в течение которого инженер остается (обычно) занят, экспоненциально распределен , и поэтому я его реализовал используя __lt__ .

Вот реализация:

random.expovariate
ответил Gareth Rees 13 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSat, 13 Sep 2014 01:31:00 +0400 2014, 01:31:00
3
  • Мое понимание спецификации заключается в том, что программа должна отслеживать сверхбыстрый статус каждого инженера и менять статус в нормальное состояние по прошествии определенного времени. Весь ваш код с параметром max_time_superbusy распечатывает его.
  • В спецификации указаны входные параметры. Ваша программа должна каким-то образом ввести их, например. из командной строки, вместо того, чтобы их закодировать в коде.
  • Вы неправильно используете атрибуты класса, где атрибуты экземпляра были бы подходящими. Создание нескольких экземпляров Queue приведет к неожиданному поведению, так как экземпляры будут использовать normal_queue и super_queue.
ответил Janne Karila 11 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowThu, 11 Sep 2014 16:39:11 +0400 2014, 16:39:11

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132