2023-05-14 14:23:37 +02:00
|
|
|
|
import time
|
2023-05-05 02:56:22 +02:00
|
|
|
|
import pygame
|
2023-06-01 17:45:01 +02:00
|
|
|
|
from .obj.Goal import Goal
|
2023-05-05 02:56:22 +02:00
|
|
|
|
from .obj.Object import Object
|
2023-05-26 03:02:16 +02:00
|
|
|
|
from .obj.Waiter import Waiter
|
2023-06-01 17:45:01 +02:00
|
|
|
|
from .obj.Kitchen import Kitchen
|
2023-05-05 02:56:22 +02:00
|
|
|
|
from .UserController import UserController
|
|
|
|
|
from .StateController import StateController
|
2023-06-01 12:44:29 +02:00
|
|
|
|
from .decisionTree.TreeConcept import TreeEngine
|
|
|
|
|
from queue import PriorityQueue
|
2023-05-05 02:56:22 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Engine:
|
|
|
|
|
|
2023-06-01 17:45:01 +02:00
|
|
|
|
def __init__(self, screen_size, square_size, kitchen: Kitchen, user: UserController, state: StateController):
|
2023-05-14 14:23:37 +02:00
|
|
|
|
pygame.display.set_caption('Waiter Agent')
|
|
|
|
|
|
2023-05-26 03:02:16 +02:00
|
|
|
|
self.action_clock = 0
|
2023-06-01 12:44:29 +02:00
|
|
|
|
self.tree = TreeEngine()
|
2023-05-26 03:02:16 +02:00
|
|
|
|
|
2023-06-01 17:45:01 +02:00
|
|
|
|
self.kitchen: Kitchen = kitchen
|
2023-05-26 03:02:16 +02:00
|
|
|
|
self.user: Waiter = user
|
|
|
|
|
self.state: StateController = state
|
|
|
|
|
self.screen_size: list[int] = screen_size
|
2023-05-05 02:56:22 +02:00
|
|
|
|
self.screen = pygame.display.set_mode(self.screen_size)
|
|
|
|
|
|
2023-05-26 03:02:16 +02:00
|
|
|
|
self.square_size: int = square_size
|
2023-05-05 02:56:22 +02:00
|
|
|
|
self.num_squares = self.screen_size[0] // self.square_size
|
|
|
|
|
self.squares = self.__init_squares_field__(
|
|
|
|
|
self.num_squares, self.square_size)
|
|
|
|
|
|
|
|
|
|
self.objects: list[Object] = []
|
2023-05-14 14:23:37 +02:00
|
|
|
|
self.goals: list = []
|
2023-05-05 02:56:22 +02:00
|
|
|
|
|
2023-05-26 03:02:16 +02:00
|
|
|
|
self.runnin: bool = False
|
2023-05-05 02:56:22 +02:00
|
|
|
|
|
|
|
|
|
def __init_squares_field__(self, num_squares, square_size):
|
|
|
|
|
squares = []
|
|
|
|
|
for i in range(num_squares):
|
|
|
|
|
row = []
|
|
|
|
|
for j in range(num_squares):
|
|
|
|
|
square_rect = pygame.Rect(
|
|
|
|
|
j * square_size, i * square_size,
|
|
|
|
|
square_size, square_size)
|
|
|
|
|
row.append(square_rect)
|
|
|
|
|
squares.append(row)
|
|
|
|
|
|
|
|
|
|
return squares
|
|
|
|
|
|
|
|
|
|
def subscribe(self, object: Object):
|
|
|
|
|
self.objects.append(object)
|
|
|
|
|
|
|
|
|
|
def loop(self):
|
|
|
|
|
self.running = True
|
|
|
|
|
while self.running:
|
|
|
|
|
|
|
|
|
|
self.action()
|
|
|
|
|
self.redraw()
|
|
|
|
|
|
|
|
|
|
def quit(self):
|
|
|
|
|
self.running = False
|
|
|
|
|
|
|
|
|
|
def action(self):
|
2023-05-14 14:23:37 +02:00
|
|
|
|
if not self.state.path:
|
|
|
|
|
if self.goals:
|
|
|
|
|
self.state.graphsearch(self)
|
|
|
|
|
self.user.handler(self)
|
2023-06-01 12:44:29 +02:00
|
|
|
|
self.predict()
|
2023-05-05 02:56:22 +02:00
|
|
|
|
else:
|
2023-05-26 03:02:16 +02:00
|
|
|
|
# went path
|
|
|
|
|
|
2023-05-14 14:23:37 +02:00
|
|
|
|
state = self.user.obj.changeState(self.state.path.pop())
|
2023-05-26 03:02:16 +02:00
|
|
|
|
self.clock_increment(state.cost)
|
|
|
|
|
|
|
|
|
|
print("Action:\t{0}\tCost:\t{1}\tCost so far: {2}\tBattery: {3}".format(
|
2023-05-14 14:23:37 +02:00
|
|
|
|
state.agent_role,
|
|
|
|
|
state.cost,
|
2023-05-26 03:02:16 +02:00
|
|
|
|
state.cost_so_far,
|
|
|
|
|
self.user.obj.battery)
|
2023-05-14 14:23:37 +02:00
|
|
|
|
)
|
2023-05-26 03:02:16 +02:00
|
|
|
|
|
|
|
|
|
# waiter interaction
|
|
|
|
|
|
|
|
|
|
for o in self.objects:
|
2023-06-01 17:45:01 +02:00
|
|
|
|
if self.user.obj.chechNeighbor(o):
|
|
|
|
|
o.updateState(self.action_clock)
|
2023-05-26 03:02:16 +02:00
|
|
|
|
if o.compare_pos(self.user.obj.position):
|
2023-06-01 17:45:01 +02:00
|
|
|
|
o.action(self.user.obj, self.action_clock)
|
|
|
|
|
|
|
|
|
|
if self.kitchen.compare_pos(self.user.obj.position):
|
|
|
|
|
self.kitchen.action(self.user.obj, self.action_clock)
|
2023-05-26 03:02:16 +02:00
|
|
|
|
|
2023-05-14 14:23:37 +02:00
|
|
|
|
time.sleep(0.5)
|
2023-05-05 02:56:22 +02:00
|
|
|
|
|
2023-05-26 03:02:16 +02:00
|
|
|
|
def clock_increment(self, action_time):
|
|
|
|
|
self.action_clock += action_time
|
|
|
|
|
|
2023-05-05 02:56:22 +02:00
|
|
|
|
def redraw(self):
|
|
|
|
|
self.screen.fill((255, 255, 255))
|
|
|
|
|
|
|
|
|
|
for row in self.squares:
|
|
|
|
|
for square_rect in row:
|
|
|
|
|
pygame.draw.rect(self.screen, (0, 0, 0), square_rect, 1)
|
|
|
|
|
|
|
|
|
|
for o in self.objects:
|
|
|
|
|
o.blit(self.screen)
|
|
|
|
|
|
2023-06-01 17:45:01 +02:00
|
|
|
|
self.kitchen.blit(self.screen)
|
2023-05-05 02:56:22 +02:00
|
|
|
|
self.user.obj.blit(self.screen)
|
|
|
|
|
|
2023-05-14 14:23:37 +02:00
|
|
|
|
for f in self.state.fringe.queue:
|
|
|
|
|
f.blit(self.screen)
|
|
|
|
|
|
2023-05-05 02:56:22 +02:00
|
|
|
|
for s in self.state.path:
|
|
|
|
|
s.blit(self.screen)
|
|
|
|
|
|
2023-06-01 17:45:01 +02:00
|
|
|
|
if self.goals:
|
|
|
|
|
self.goals[-1].blit(self.screen)
|
|
|
|
|
|
2023-05-05 02:56:22 +02:00
|
|
|
|
pygame.display.flip()
|
2023-05-14 14:23:37 +02:00
|
|
|
|
|
|
|
|
|
def appendGoalPosition(self, position):
|
2023-06-01 17:45:01 +02:00
|
|
|
|
self.goals.append(Goal(position, self.square_size, self.screen_size))
|
2023-06-01 12:44:29 +02:00
|
|
|
|
|
|
|
|
|
def predict(self):
|
|
|
|
|
|
|
|
|
|
goal_queue = PriorityQueue()
|
|
|
|
|
|
|
|
|
|
for o in self.objects:
|
|
|
|
|
|
|
|
|
|
condition = o.agent_role in [
|
2023-06-01 17:45:01 +02:00
|
|
|
|
"table",
|
2023-06-01 12:44:29 +02:00
|
|
|
|
"order",
|
|
|
|
|
"wait",
|
|
|
|
|
"done"
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
if not condition or o.compare_pos(self.user.obj.position):
|
|
|
|
|
continue
|
|
|
|
|
|
2023-06-01 17:45:01 +02:00
|
|
|
|
medium_dist = (self.screen_size[0] // self.square_size) // 2
|
|
|
|
|
|
|
|
|
|
dataset = [
|
|
|
|
|
# battery
|
|
|
|
|
self.user.obj.battery_status(),
|
|
|
|
|
# high | low |
|
|
|
|
|
|
|
|
|
|
# distance between kitchen and object
|
|
|
|
|
0 if o.distance_to(self.kitchen.position) > medium_dist else 1,
|
|
|
|
|
# far | close |
|
|
|
|
|
|
|
|
|
|
# mood
|
|
|
|
|
o.get_mood(self.action_clock),
|
|
|
|
|
# undefined | good | bad |
|
|
|
|
|
|
|
|
|
|
# basket is empty
|
|
|
|
|
1 if self.user.obj.basket_is_empty() else 0,
|
|
|
|
|
# yes | no |
|
2023-06-01 12:44:29 +02:00
|
|
|
|
|
2023-06-01 17:45:01 +02:00
|
|
|
|
# dish is ready
|
|
|
|
|
1 if o.dish_is_ready(self.action_clock) else 0,
|
|
|
|
|
# yes | no |
|
|
|
|
|
|
|
|
|
|
# dish in basket
|
|
|
|
|
1 if self.user.obj.dish_in_basket(o) else 0,
|
|
|
|
|
# yes | no |
|
|
|
|
|
|
|
|
|
|
# status
|
|
|
|
|
o.get_state_number(),
|
|
|
|
|
# empty | new order | waiting for dish | have a dish |
|
|
|
|
|
|
|
|
|
|
# is actual
|
|
|
|
|
1 if o.isActual() else 0,
|
|
|
|
|
# yes | no |
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
p = self.tree.make_predict(dataset)
|
2023-06-01 12:44:29 +02:00
|
|
|
|
goal_queue.put((p, o.position))
|
|
|
|
|
|
2023-06-01 17:45:01 +02:00
|
|
|
|
if goal_queue.queue:
|
|
|
|
|
priority, goal = goal_queue.queue[0]
|
|
|
|
|
if priority == 2:
|
|
|
|
|
self.appendGoalPosition(self.kitchen.position)
|
2023-06-01 12:44:29 +02:00
|
|
|
|
else:
|
2023-06-01 17:45:01 +02:00
|
|
|
|
self.appendGoalPosition(goal)
|