def handle(self, model):
        """
        If request is waiting more then N minutes or request does not like a menu, we will lost it
        When request is leaving, it makes its table free
        :param model: current state of model
        """

        if self.request.state == RequestState.WAITING_FOR_WAITER or self.request.state == RequestState.LEAVING_BAD_MENU:
            self.request.table.available = True
            self.request.table.owner = None

            if self.request.state == RequestState.WAITING_FOR_WAITER:
                st.stay_times_long_waiting_leave.append(
                    model.global_time - self.request.income_time)
                st.long_waiting_leave_counter += 1
                logging.info("%s: Request %d left because of too long waiting",
                             human_readable_date_time(model.global_time),
                             self.request.id)
            elif self.request.state == RequestState.LEAVING_BAD_MENU:
                st.stay_times_bad_menu_leave.append(model.global_time -
                                                    self.request.income_time)
                st.disliked_menu_counter += 1
                logging.info("%s: Request %d left because of disliking a menu",
                             human_readable_date_time(model.global_time),
                             self.request.id)
    def handle(self, model):
        """
        Delivered dishes decremented (ate).
        If there are no dish we wait, we will call a waiter for an extra order with reorder_probability.
        On the other way, request will call a waiter for a bill.
        If there are no waiter we will wait while he comes.
        :param model: current state of model
        """
        self.request.dish_count -= 1
        self.request.state = RequestState.OK
        self.request.waiting_start_time = model.global_time
        logging.info("%s: Request %d ate a dish %d. Remaining dishes: %d",
                     human_readable_date_time(model.global_time),
                     self.request.id, self.dish.id, self.request.dish_count)

        # to fix a bug with negative dishes
        if self.request.dish_count < 1:
            self.request.dish_count = 0
            waiters = list(
                filter(lambda wait: wait.state == WaiterState.FREE,
                       model.restaurant.waiters))
            reorder = choices([False, True], [
                1 - self.request.reorder_probability,
                self.request.reorder_probability
            ])[0]

            if reorder and model.global_time <= model.restaurant.last_entrance_time:
                self.request.state = RequestState.WAITING_FOR_WAITER
                self.request.waiting_start_time = model.global_time
                logging.info("%s: Request %d will make a reorder.",
                             human_readable_date_time(model.global_time),
                             self.request.id)

                if not self.request.reorder:
                    st.reorder_counter += 1

                self.request.reorder = True

                if waiters:
                    waiter = waiters[0]
                    logging.info(
                        "%s: Waiter %d is taking a reorder of request %d.",
                        human_readable_date_time(model.global_time), waiter.id,
                        self.request.id)
                    waiter.service(model, self.request)

            else:
                self.request.state = RequestState.WAITING_FOR_BILL
                logging.info("%s: Request %d is going to leave.",
                             human_readable_date_time(model.global_time),
                             self.request.id)
                if waiters:
                    waiter = waiters[0]
                    waiter.invoice(model)

            self.request.reorder_probability *= 0.5
    def invoice(self, model):
        """
        Check if somebody is waiting for a bill.
        If somebody is waiting, waiter change state to BILLINg and request's state to OK.
        Increase working hours.
        Call WaiterFree and TableFree events.
        :param model: current state of model
        """
        waiting_for_bill = list(
            map(
                lambda t: t.owner,
                filter(
                    lambda table: not table.available and table.owner.state == RequestState.WAITING_FOR_BILL,
                    model.restaurant.tables
                )
            )
        )

        if waiting_for_bill:
            self.state = WaiterState.BILLING
            leaving = waiting_for_bill[0]
            st.request_waiting[leaving.id] += model.global_time - leaving.waiting_start_time
            logging.info("%s: Request %d is billing by waiter %d",
                         human_readable_date_time(model.global_time),
                         leaving.id, self.id)
            leaving.state = RequestState.OK
            service_time = expovariate(1 / self.service_time)
            st.service_time.append(service_time)
            st.waiter_hours[self.id][model.current_request_interval()] += round(service_time)

            model.next_events.append(Event(model.global_time + service_time,
                                           WaiterFreeEvent(self, leaving)))
            model.next_events.append(Event(model.global_time + service_time,
                                           TableFreeEvent(leaving.table)))
    def service(self, model, request):
        """
        Change waiter's state to SERVICING, generate dishes for each human in request's size.
        Call CookerCallEvent for each generated dish.
        After that generate WaiterFreeEvent.
        Increase working time.
        :param self: who will work
        :param model: current state of model
        :param request:
        """
        self.state = WaiterState.SERVICING
        st.request_waiting[request.id] += model.global_time - request.waiting_start_time
        request.state = RequestState.OK  # because request already has a waiter
        logging.info("%s: Waiter %d is started servicing request %d",
                     human_readable_date_time(model.global_time),
                     self.id,
                     request.id)
        service_time = 0
        dish_count = 0

        for human in range(request.size):
            service_time += expovariate(1 / self.service_time)
            dish_count += randrange(1, 3, 1)

        request.dish_count = dish_count
        request.billed_dish_counter += dish_count
        st.dish_counter.append(dish_count)

        logging.info("%s: Request %d ordered %d dishes",
                     human_readable_date_time(model.global_time),
                     request.id,
                     dish_count)

        for dish in range(dish_count):
            model.next_events.append(
                Event(model.global_time + service_time, CookerCallEvent(Dish(request)))
            )

        model.next_events.append(
            Event(model.global_time + service_time, WaiterFreeEvent(self, request)))

        st.service_time.append(round(service_time))
        st.waiter_hours[self.id][model.current_request_interval()] += round(service_time)

        request.waiting_start_time = model.global_time + service_time
    def handle(self, model):
        """
        Check if there are ready dishes, if not check if there are requests waiting for waiter,
        if not check if there requests waiting for bill, if not become free.
        :param model: current state of model
        """

        if self.waiter.state == WaiterState.DELIVERING_DISH:
            logging.info("%s: Waiter %d delivered dish %d to request %d",
                         human_readable_date_time(model.global_time),
                         self.waiter.id, self.dish.id, self.request.id)
        elif self.waiter.state == WaiterState.BILLING:
            logging.info("%s: Waiter %d finished billing request %d",
                         human_readable_date_time(model.global_time),
                         self.waiter.id, self.request.id)
        elif self.waiter.state == WaiterState.SERVICING:
            logging.info("%s: Waiter %d finished servicing request %d",
                         human_readable_date_time(model.global_time),
                         self.waiter.id, self.request.id)

        self.waiter.state = WaiterState.FREE
        dishes = model.restaurant.ready_dishes

        if dishes:
            self.waiter.state = WaiterState.DELIVERING_DISH
            dish = dishes[0]
            self.waiter.deliver(model, dish)

        else:
            tables = list(
                filter(
                    lambda t: not t.available and t.owner.state == RequestState.WAITING_FOR_WAITER,
                    model.restaurant.tables
                )
            )

            if tables:
                request = tables[0].owner
                self.waiter.service(model, request)

            else:
                self.waiter.invoice(model)
    def handle(self, model):
        """
        Make cooker available again.
        If there are dishes to cook, cooker will be cook them now.
        :param model: current state of model
        """
        waiting_dishes = model.restaurant.waiting_dishes
        self.cooker.available = True
        logging.info("%s: Cooker %d finished cooking dish %d for request %d",
                     human_readable_date_time(model.global_time),
                     self.cooker.id, self.dish.id, self.dish.request.id)

        if waiting_dishes:
            self.cooker.cook(model, waiting_dishes[0])
 def handle(self, model):
     """
     Billed dishes counter increased.
     Serviced counter incremented.
     Stay times calculated.
     Free table.
     :param model: current state of model
     """
     logging.info("%s: Request %d is leaving table %d",
                  human_readable_date_time(model.global_time),
                  self.table.owner.id,
                  self.table.id)
     st.billed_dish_counter.append(self.table.owner.billed_dish_counter)
     st.serviced_counter += 1
     st.stay_times_normal_leave.append(model.global_time - self.table.owner.income_time)
     self.table.available = True
     self.table.owner = None
 def cook(self, model, dish):
     """
     Cooker isn't available for cooking time.
     Dish will be ready in cooking time.
     :param model: current state of model
     :param dish: dish obj which cooker is going to cook
     """
     self.available = False
     logging.info("%s: Cooker %d started cooking dish %d for request %d",
                  human_readable_date_time(model.global_time), self.id,
                  dish.id, dish.request.id)
     # cooking_time = expovariate(1 / self.cooking_time)
     cooking_time = uniform(10 * 60, 20 * 60)
     st.cook_time.append(cooking_time)
     st.cooker_hours[self.id][
         model.current_request_interval()] += cooking_time
     model.restaurant.waiting_dishes.remove(dish)
     model.next_events.append(
         Event(model.global_time + cooking_time, DishEvent(dish, self)))
    def handle(self, model):
        """
        Ready dish appends to ready dishes queue.
        If there any free waiter, he will deliver this dish now.
        CookerFreeEvent is called here.
        :param model: current state of model
        """
        waiters = list(
            filter(lambda wait: wait.state == WaiterState.FREE,
                   model.restaurant.waiters))
        model.restaurant.ready_dishes.append(self.dish)

        if waiters:
            waiter = waiters[0]
            waiter.deliver(model, self.dish)
        else:
            logging.info(
                "%s: No free waiter for cooker %d  and dish %d for request %d",
                human_readable_date_time(model.global_time), self.cooker.id,
                self.dish.id, self.dish.request.id)

        model.next_events.append(
            Event(model.global_time, CookerFreeEvent(self.cooker, self.dish)))
Example #10
0
    ])
    pretty_table.add_row([
        "Average ready dishes queue length",
        stats.avg_len_dict(
            stats.avg_dishes_queue, restaurant_model.restaurant.work_time_to -
            restaurant_model.restaurant.work_time_from)
    ])

    print(pretty_table)

    header = ["Cooker id"]
    header.extend([
        utils.human_readable_time(period.fromInterval) + "-" +
        utils.human_readable_time(period.toInterval) if not period.last else
        utils.human_readable_time(period.fromInterval) + "-" +
        utils.human_readable_date_time(restaurant_model.global_time)
        for period in restaurant_model.intervals
    ])
    header.append("Total")

    pretty_table = PrettyTable(header)

    for key, value in stats.multi_period_worker_load(
            stats.cooker_hours, restaurant_model.global_time).items():
        row = [key]
        row.extend(value)
        row.append(
            stats.total_worker_load(key, stats.cooker_hours,
                                    restaurant_model.global_time))
        pretty_table.add_row(row)
    def handle(self, model):
        """
        Generating new request (exponential with custom meaning) with N people.
        Take a table and waiting for the waiter or check menu and leave with leaving probability.
        If there are no free table, request is going to leave.
        Increment counter of visitors or lost.
        :param model: current state of model
        """
        st.total_counter += 1
        # trying to seize table
        tables = list(
            filter(lambda t: t.size >= self.request.size and t.available,
                   model.restaurant.tables))
        logging.info("%s: Income request %d",
                     human_readable_date_time(model.global_time),
                     self.request.id)

        if tables:
            self.request.table = tables[0]
            self.request.table.available = False
            self.request.table.owner = self.request
            st.seated_counter += 1

            logging.info("%s: Request %d took a table %d",
                         human_readable_date_time(model.global_time),
                         self.request.id, self.request.table.id)
            # here we have some time to read a menu and make a decision about state here or not
            leaving = choices([False, True], [
                1 - model.restaurant.leaving_probability,
                model.restaurant.leaving_probability
            ])[0]

            if leaving:
                self.request.state = RequestState.LEAVING_BAD_MENU
                model.next_events.append(
                    e.Event(
                        model.global_time +
                        expovariate(1 / model.restaurant.thinking_time),
                        LeaveEvent(self.request)))

            else:
                self.request.waiting_start_time = model.global_time
                model.next_events.append(
                    e.Event(
                        model.global_time +
                        expovariate(1 / model.restaurant.thinking_time),
                        w.WaiterEvent(self.request)))
        else:
            st.no_seat_counter += 1
            logging.info(
                "%s: Request %d left because there are not free table",
                human_readable_date_time(model.global_time), self.request.id)

        people_count = int(
            choices(list(model.class_probability.keys()),
                    list(model.class_probability.values()))[0])
        """
        Generating next event in seconds according to current_mean and until last_entrance_time.
        Increment counter of requests
        """
        next_request_time = expovariate(1 / model.current_request_mean())

        if model.global_time < model.restaurant.last_entrance_time \
                and model.global_time + next_request_time < model.current_request_interval().toInterval:
            model.next_events.append(
                e.Event(
                    model.global_time + next_request_time,
                    RequestEvent(
                        Request(people_count,
                                model.restaurant.reorder_probability,
                                model.global_time + next_request_time))))
Example #12
0
mean, error = confidence_interval(
    [a / b for (a, b) in zip(diffs, avg_total_dish_count)], False)
pretty_table.add_row([
    "Part of not billed dishes",
    str(round(mean, 3)) + " ± " + str(round(error, 3))
])

print(pretty_table)

header = ["Cooker id"]
header.extend([
    utils.human_readable_time(period.fromInterval) + "-" +
    utils.human_readable_time(period.toInterval)
    if not period.last else utils.human_readable_time(period.fromInterval) +
    "-" + utils.human_readable_date_time(rest_model.global_time)
    for period in rest_model.intervals
])
header.append("Total")

pretty_table = PrettyTable(header)

for key, value in stats.multi_period_worker_load(
        stats.cooker_hours, rest_model.global_time).items():
    if key <= len(rest_model.restaurant.cookers):
        row = [key]
        row.extend(value)
        row.append(
            stats.total_worker_load(key, stats.cooker_hours,
                                    rest_model.global_time))
        pretty_table.add_row(row)