264 lines
12 KiB
Python
264 lines
12 KiB
Python
import threading
|
|
import time
|
|
import sys
|
|
from math import sqrt
|
|
from kelner.src.components.Table import Status
|
|
from kelner.src.algorithms.AStar.Finder import Finder
|
|
from kelner.src.algorithms.BFS.BFS import BFS
|
|
from kelner.src.components.Table import Status
|
|
from kelner.src.algorithms.CNN.ModelPrediction import Predictor
|
|
|
|
|
|
# creates new thread
|
|
class WaiterManager(threading.Thread):
|
|
|
|
def __init__(self, drawableManager, waiters, kitchen_manager, menu_manager, table_manager):
|
|
super().__init__()
|
|
self.__drawableManager = drawableManager
|
|
self.__waiters = waiters
|
|
self.__runThread = True
|
|
self._kitchen_manager = kitchen_manager
|
|
self._menu_manager = menu_manager
|
|
self._table_manager = table_manager
|
|
|
|
def __getDistance(self, waiter, tupleXY):
|
|
dx = waiter.getX() - tupleXY[0]
|
|
dy = waiter.getY() - tupleXY[1]
|
|
return sqrt(dx * dx + dy * dy)
|
|
|
|
def __sortTargets(self, waiter, targets):
|
|
return sorted(targets, key=lambda target: self.__getDistance(waiter, (target[0], target[1])))
|
|
|
|
def __getTargets(self, waiter, finder):
|
|
found = []
|
|
tables = self.__drawableManager.getTables(Status.Ready)
|
|
if tables:
|
|
origin = (waiter.getX(), waiter.getY())
|
|
for table in tables:
|
|
if table.hasOrder():
|
|
targets = finder.getNeighbours((table.getX(), table.getY()), False)
|
|
for target in targets:
|
|
if target == origin:
|
|
return []
|
|
else:
|
|
found.append(target)
|
|
return self.__sortTargets(waiter, found)
|
|
|
|
def __getNearestTargetPath(self, waiter, targets=None):
|
|
distance = sys.maxsize
|
|
nearestTargetPath = None
|
|
reservedPlaces = self.__drawableManager.getReservedPlaces(waiter)
|
|
finder = Finder(reservedPlaces)
|
|
origin = (waiter.getX(), waiter.getY())
|
|
if targets is None:
|
|
targets = self.__getTargets(waiter, finder)
|
|
for target in targets:
|
|
if distance > self.__getDistance(waiter, target):
|
|
path = finder.getPath(origin, target, True)
|
|
if path:
|
|
result = len(path)
|
|
if result < distance:
|
|
distance = result
|
|
nearestTargetPath = path
|
|
|
|
return nearestTargetPath
|
|
|
|
def get_specified_path(self, waiter, table):
|
|
distance = sys.maxsize
|
|
nearestTargetPath = None
|
|
reserved_places = self.__drawableManager.getReservedPlaces(waiter)
|
|
finder = Finder(reserved_places)
|
|
origin = (waiter.getX(), waiter.getY())
|
|
targets = finder.getNeighbours((table[0], table[1]), False)
|
|
for target in targets:
|
|
if distance > self.__getDistance(waiter, target):
|
|
path = finder.getPath(origin, target, True)
|
|
if path:
|
|
result = len(path)
|
|
if result < distance:
|
|
distance = result
|
|
nearestTargetPath = path
|
|
|
|
return nearestTargetPath
|
|
|
|
def __changeWaiterDirection(self, waiter, x, y):
|
|
targetDirection = x - waiter.getX(), y - waiter.getY()
|
|
originDirection = waiter.getDirection()
|
|
while originDirection is not None:
|
|
originDirection = waiter.getNextDirection(originDirection, targetDirection, True)
|
|
if originDirection is not None:
|
|
time.sleep(0.3)
|
|
waiter.setDirection(originDirection[0], originDirection[1])
|
|
self.__drawableManager.forceRepaint()
|
|
|
|
def __moveWaiter(self, waiter, x, y):
|
|
time.sleep(0.4)
|
|
self.__drawableManager.moveWaiter(waiter, x, y)
|
|
self.__drawableManager.forceRepaint()
|
|
|
|
def __collectOrder(self, waiter):
|
|
doCollectOrder = True
|
|
while doCollectOrder and waiter.get_state():
|
|
tables = self.__drawableManager.getNearestTables(waiter, Status.Ready)
|
|
turns = sys.maxsize
|
|
lessTurnsTable = None
|
|
originDirection = waiter.getDirection()
|
|
|
|
for table in tables:
|
|
targetDirection = table.getX() - waiter.getX(), table.getY() - waiter.getY()
|
|
result = Finder.getTurnsCount(originDirection, targetDirection, True)
|
|
if result < turns:
|
|
turns = result
|
|
lessTurnsTable = table
|
|
|
|
if lessTurnsTable is not None:
|
|
tables.remove(lessTurnsTable)
|
|
self.__changeWaiterDirection(waiter, lessTurnsTable.getX(), lessTurnsTable.getY())
|
|
|
|
# order = lessTurnsTable.getOrder()
|
|
order = lessTurnsTable.get_order()
|
|
if order is not None and waiter.get_state:
|
|
waiter.addOrder(lessTurnsTable, order)
|
|
time.sleep(2)
|
|
lessTurnsTable.setStatus(Status.Waiting)
|
|
self.__drawableManager.forceRepaint()
|
|
doCollectOrder = len(tables) > 0
|
|
|
|
def pass_orders_to_kitchen(self, orders):
|
|
kitchen = self.__drawableManager.get_kitchen()
|
|
self._kitchen_manager.pass_orders(orders, kitchen)
|
|
|
|
def receive_ready_orders(self, waiter):
|
|
kitchen = self.__drawableManager.get_kitchen()
|
|
try:
|
|
ready_orders = self._kitchen_manager.get_ready_orders(kitchen)
|
|
for dish in ready_orders:
|
|
print("Orders ready to take", end=" ")
|
|
print(dish[1])
|
|
except IndexError as e:
|
|
print("No orders")
|
|
waiter.make_ready()
|
|
waiter.clear_accepted_orders()
|
|
print("Ready to go")
|
|
return ready_orders
|
|
|
|
def predict_order(self, order, kitchen):
|
|
food_list = self._menu_manager.get_menu()
|
|
image_predictor = Predictor(food_list)
|
|
paths = self._kitchen_manager.draw_single_order(order, kitchen)
|
|
predicted_dishes = []
|
|
self._kitchen_manager.run()
|
|
self._table_manager.pause()
|
|
# print("Printed images paths: {}".format(paths))
|
|
if paths is not None:
|
|
for img_path in paths:
|
|
predicted_dish = image_predictor.predict_class(img_path)
|
|
predicted_dishes.append(predicted_dish)
|
|
time.sleep(2)
|
|
self.__drawableManager.forceRepaint()
|
|
return predicted_dishes
|
|
|
|
def match_predicted_orders(self, predicted_orders):
|
|
all_tables = self.__drawableManager.getTables(Status.Waiting)
|
|
located_orders = dict()
|
|
|
|
for p_order in predicted_orders:
|
|
p_order.sort()
|
|
for table in all_tables:
|
|
table_dishes = table.get_order()
|
|
table_dishes.sort()
|
|
|
|
if p_order == table_dishes:
|
|
located_orders[table] = p_order
|
|
return located_orders
|
|
|
|
def get_order_targets(self, orders):
|
|
targets = dict()
|
|
for table, dishes in orders.items():
|
|
targets[table.get_posistion()] = dishes
|
|
return targets
|
|
|
|
def set_next_waiter_targets(self, waiter, matched_targets):
|
|
for table in matched_targets.keys():
|
|
path = self.get_specified_path(waiter, table)
|
|
waiter.add_remaining_target(path)
|
|
|
|
def set_next_waiter_positions(self, waiter, matched_positions):
|
|
for position in matched_positions.keys():
|
|
waiter.add_remaining_position(position)
|
|
|
|
# changes the status of a random table from NotReady to Ready
|
|
def run(self):
|
|
while self.__runThread:
|
|
if self.__waiters:
|
|
for waiter in self.__waiters:
|
|
|
|
if len(waiter.getAcceptedOrders()) > 1:
|
|
waiter.set_target('kitchen')
|
|
path = self.__getNearestTargetPath(waiter, [(14, 1), (13, 0)])
|
|
waiter.make_busy()
|
|
else:
|
|
if waiter.get_target() == 'return_order' and waiter.isPathEmpty():
|
|
print("Order returned")
|
|
table = self._table_manager.get_table(waiter.get_remaining_positions()[0])
|
|
table.setStatus(Status.Served)
|
|
self.__changeWaiterDirection(waiter, table.getX(), table.getY())
|
|
waiter.get_remaining_positions().pop(0)
|
|
time.sleep(2)
|
|
|
|
if not waiter.get_remaining_positions() == []:
|
|
waiter.set_target('return_order')
|
|
path = self.get_specified_path(waiter, waiter.get_remaining_positions()[0])
|
|
else:
|
|
waiter.set_target('table')
|
|
path = self.__getNearestTargetPath(waiter)
|
|
|
|
waiter.setPath([] if path is None else path)
|
|
|
|
if not waiter.isPathEmpty():
|
|
step = waiter.popStepFromPath()
|
|
self.__changeWaiterDirection(waiter, step[0], step[1])
|
|
self.__moveWaiter(waiter, step[0], step[1])
|
|
|
|
# check if waiter is near kitchen
|
|
if (waiter.getX(), waiter.getY()) == (14, 1) or (waiter.getX(), waiter.getY()) == (13, 0):
|
|
if waiter.get_target() == 'kitchen':
|
|
self._table_manager.pause()
|
|
kitchen = self.__drawableManager.get_kitchen()
|
|
self.__changeWaiterDirection(waiter, kitchen.getX(), kitchen.getY())
|
|
waiter_orders = waiter.getAcceptedOrders()
|
|
# print("Waiter near kitchen. Collected orders: {}".format(waiter_orders))
|
|
kitchen.add_orders(waiter_orders)
|
|
received_orders = kitchen.get_ready_orders()
|
|
waiter.clear_accepted_orders()
|
|
if received_orders:
|
|
predicted_orders = []
|
|
for order in received_orders:
|
|
# get predicted dishes
|
|
predicted_dishes = self.predict_order(order, kitchen)
|
|
predicted_orders.append(predicted_dishes)
|
|
|
|
# check if all predicted orders were really ordered
|
|
matched_targets = self.match_predicted_orders(predicted_orders)
|
|
# get positions to matched orders (X,Y): dish
|
|
order_positions = self.get_order_targets(matched_targets)
|
|
self.set_next_waiter_positions(waiter, order_positions)
|
|
|
|
# set new ready paths to waiter
|
|
# self.set_next_waiter_targets(waiter, matched_targets)
|
|
|
|
self._kitchen_manager.stop()
|
|
self._table_manager.resume()
|
|
|
|
kitchen.clear_orders()
|
|
waiter.make_ready()
|
|
waiter.set_target('table')
|
|
elif waiter.get_target() not in ['return_order', 'check']:
|
|
self.__collectOrder(waiter)
|
|
|
|
def stop(self):
|
|
self.__runThread = False
|
|
|
|
def resume(self):
|
|
self.__runThread = True
|