code refactoring, preparation to decision tree integration

This commit is contained in:
Vadzim Valchkovich 2023-05-26 03:02:16 +02:00
parent c74d1f0925
commit 51bab9921d
10 changed files with 160 additions and 50 deletions

View File

@ -44,5 +44,5 @@
- [ ] **Drzewa decyzyjne: wymagania dot. trzeciego przyrostu** - [ ] **Drzewa decyzyjne: wymagania dot. trzeciego przyrostu**
- [ ] Należy wykorzystać algorytm ID3 (tj. schemat indukcyjnego uczenia drzewa decyzyjnego oraz procedurę wyboru atrybutu o największym przyroście informacji) lub któreś z jego uogólnień. - [ ] Należy wykorzystać algorytm ID3 (tj. schemat indukcyjnego uczenia drzewa decyzyjnego oraz procedurę wyboru atrybutu o największym przyroście informacji) lub któreś z jego uogólnień.
- [ ] Należy przygotować zbiór uczący złożony z co najmniej 200 przykładów. - [ ] Należy przygotować zbiór uczący złożony z co najmniej 200 przykładów.
- [ ] Decyzja stanowiąca cel uczenia powinna zostać opisana przynajmniej ośmioma atrybutami. - [x] Decyzja stanowiąca cel uczenia powinna zostać opisana przynajmniej ośmioma atrybutami.
- [ ] Powinna pojawić się opcja podglądu wyuczonego drzewa (np. w logach lub w pliku z graficzną reprezentacją drzewa). - [ ] Powinna pojawić się opcja podglądu wyuczonego drzewa (np. w logach lub w pliku z graficzną reprezentacją drzewa).

View File

@ -7,7 +7,7 @@ from src.obj.Table import Table
from src.UserController import UserController from src.UserController import UserController
from src.StateController import StateController from src.StateController import StateController
SCREEN_SIZE = (800, 800) SCREEN_SIZE = [800, 800]
SQUARE_SIZE = 40 SQUARE_SIZE = 40
waiter = Waiter([0, 0], 0, SQUARE_SIZE, SCREEN_SIZE) waiter = Waiter([0, 0], 0, SQUARE_SIZE, SCREEN_SIZE)
@ -26,8 +26,7 @@ for i in range(150):
if (random.randint(0, 1)): if (random.randint(0, 1)):
objects.append(Block(pos, 0, SQUARE_SIZE, SCREEN_SIZE)) objects.append(Block(pos, 0, SQUARE_SIZE, SCREEN_SIZE))
else: else:
objects.append(Table(pos, 0, SQUARE_SIZE, objects.append(Table(pos, 0, SQUARE_SIZE, SCREEN_SIZE))
SCREEN_SIZE, random.randint(0, 3)))
user = UserController(waiter) user = UserController(waiter)
state = StateController(waiter) state = StateController(waiter)

View File

@ -1,6 +1,7 @@
import time import time
import pygame import pygame
from .obj.Object import Object from .obj.Object import Object
from .obj.Waiter import Waiter
from .UserController import UserController from .UserController import UserController
from .StateController import StateController from .StateController import StateController
@ -10,12 +11,14 @@ class Engine:
def __init__(self, screen_size, square_size, user: UserController, state: StateController): def __init__(self, screen_size, square_size, user: UserController, state: StateController):
pygame.display.set_caption('Waiter Agent') pygame.display.set_caption('Waiter Agent')
self.user = user self.action_clock = 0
self.state = state
self.screen_size = screen_size self.user: Waiter = user
self.state: StateController = state
self.screen_size: list[int] = screen_size
self.screen = pygame.display.set_mode(self.screen_size) self.screen = pygame.display.set_mode(self.screen_size)
self.square_size = square_size self.square_size: int = square_size
self.num_squares = self.screen_size[0] // self.square_size self.num_squares = self.screen_size[0] // self.square_size
self.squares = self.__init_squares_field__( self.squares = self.__init_squares_field__(
self.num_squares, self.square_size) self.num_squares, self.square_size)
@ -23,7 +26,7 @@ class Engine:
self.objects: list[Object] = [] self.objects: list[Object] = []
self.goals: list = [] self.goals: list = []
self.runnin = False self.runnin: bool = False
def __init_squares_field__(self, num_squares, square_size): def __init_squares_field__(self, num_squares, square_size):
squares = [] squares = []
@ -57,14 +60,29 @@ class Engine:
self.state.graphsearch(self) self.state.graphsearch(self)
self.user.handler(self) self.user.handler(self)
else: else:
# went path
state = self.user.obj.changeState(self.state.path.pop()) state = self.user.obj.changeState(self.state.path.pop())
print("Action:\t{0}\tCost:\t{1}\tCost so far: {2}".format( self.clock_increment(state.cost)
print("Action:\t{0}\tCost:\t{1}\tCost so far: {2}\tBattery: {3}".format(
state.agent_role, state.agent_role,
state.cost, state.cost,
state.cost_so_far) state.cost_so_far,
self.user.obj.battery)
) )
# waiter interaction
for o in self.objects:
if o.compare_pos(self.user.obj.position):
o.action(self.user.obj)
time.sleep(0.5) time.sleep(0.5)
def clock_increment(self, action_time):
self.action_clock += action_time
def redraw(self): def redraw(self):
self.screen.fill((255, 255, 255)) self.screen.fill((255, 255, 255))

View File

@ -18,7 +18,7 @@ class StateController:
def build_path(self, goal_state): def build_path(self, goal_state):
total_cost = goal_state.cost total_cost = goal_state.cost
self.path.append(goal_state) self.path.append(goal_state)
while self.path[-1].parent.agent_role != "blank": while self.path[-1].parent.agent_role not in ["blank", "waiter"]:
self.path.append(self.path[-1].parent) self.path.append(self.path[-1].parent)
total_cost += self.path[-1].cost total_cost += self.path[-1].cost

View File

@ -11,6 +11,9 @@ class UserController:
engine.quit() engine.quit()
elif event.type == pygame.MOUSEBUTTONDOWN: elif event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos() pos = pygame.mouse.get_pos()
pos = (pos[0] // engine.square_size, pos = [pos[0] // engine.square_size,
pos[1] // engine.square_size) pos[1] // engine.square_size]
# for o in engine.objects:
# if o.compare_pos(pos):
# o.set_order(engine.action_clock)
engine.appendGoalPosition(pos) engine.appendGoalPosition(pos)

View File

@ -4,3 +4,7 @@ from src.obj.Object import Object
class Kitchen(Object): class Kitchen(Object):
def __init__(self, position, orientation, square_size, screen_size): def __init__(self, position, orientation, square_size, screen_size):
super().__init__("kitchen", position, orientation, square_size, screen_size) super().__init__("kitchen", position, orientation, square_size, screen_size)
def action(self, waiter):
waiter.combine_orders()
waiter.recharge()

View File

@ -46,3 +46,14 @@ class Object:
def compare_pos(self, pos) -> bool: def compare_pos(self, pos) -> bool:
return self.position == pos return self.position == pos
def distance_to(self, pos) -> int:
x = abs(self.position[0] - pos[0])
y = abs(self.position[1] - pos[1])
self.h = x + y
return self.h
def action(self, obj):
pass

View File

@ -1,14 +1,62 @@
import random
from src.obj.Object import Object from src.obj.Object import Object
class Table(Object): class Table(Object):
def __init__(self, position, orientation, square_size, screen_size, current_role=0): def __init__(self, position, orientation, square_size, screen_size):
super().__init__("table", position, orientation, square_size, screen_size) super().__init__("order", position, orientation, square_size, screen_size)
self.roles = ["table", "order", "wait", "done"] self.order_time = 0
self.current_role = current_role self.customers = 0
self.change_role(self.roles[self.current_role]) # roles = ["table", "order", "wait", "done"]
def next_role(self, waiter): def reset(self):
if waiter.agent_role == "waiter": self.change_role("table")
self.current_role = (self.current_role + 1) % 4 self.order_time = 0
self.change_role(self.roles[self.current_role]) self.customers = 0
def set_order(self, current_time):
if self.agent_role == "table":
self.change_role("order")
self.customers = random.randint(1, 6)
self.order_time = current_time
def set_wait(self):
if self.agent_role == "order":
self.change_role("wait")
def set_done(self):
if self.agent_role == "wait":
self.change_role("done")
def is_order(self):
return self.agent_role == "order"
def is_wait(self):
return self.agent_role == "wait"
def is_done(self):
return self.agent_role == "done"
def waiting_for_dish(self):
return self.agent_role in ["wait", "done"]
def get_customers_count(self) -> int:
return self.customers
def get_mood(self, current_time) -> str:
if self.agent_role == "table":
return None
diff = current_time - self.order_time
if diff < 200:
return "good"
elif diff < 400:
return "medium"
else:
return "bad"
def action(self, waiter):
if self.is_order():
waiter.collect_order(self)
elif self.is_done():
waiter.deliver_dish(self)

View File

@ -11,11 +11,11 @@ class TemporaryState(Waiter):
copy.copy(parent.basket)) copy.copy(parent.basket))
self.agent_role = action self.agent_role = action
self.parent = parent self.parent = parent
self.change_role(action)
self.apply_transformation()
self.cost = cost self.cost = cost
self.cost_so_far = cost_so_far self.cost_so_far = cost_so_far
self.h = h self.h = h
self.change_role(action)
self.apply_transformation()
def replace(self, repl): def replace(self, repl):
self.cost_so_far = copy.copy(repl.cost_so_far) self.cost_so_far = copy.copy(repl.cost_so_far)
@ -76,11 +76,7 @@ class TemporaryState(Waiter):
self.cost = costs[obj.agent_role] self.cost = costs[obj.agent_role]
def heuristic(self, goal): def heuristic(self, goal):
x = abs(self.position[0] - goal[0]) self.h = self.distance_to(goal)
y = abs(self.position[1] - goal[1])
self.h = x + y
return self.h return self.h
def current_cost(self): def current_cost(self):

View File

@ -3,10 +3,13 @@ from src.obj.Object import Object
class Waiter(Object): class Waiter(Object):
def __init__(self, position, orientation, square_size, screen_size, basket=[]): def __init__(self, position, orientation, square_size, screen_size, basket=[], memory=[], battery=300):
super().__init__("waiter", position, orientation, square_size, screen_size) super().__init__("waiter", position, orientation, square_size, screen_size)
self.basket_size = 2 self.battery = battery
self.basket_size = 4
self.memory_size = 4
self.basket = basket self.basket = basket
self.memory = memory
self.prev_position = copy.deepcopy(self.position) self.prev_position = copy.deepcopy(self.position)
self.prev_orientation = copy.copy(self.orientation) self.prev_orientation = copy.copy(self.orientation)
@ -14,18 +17,56 @@ class Waiter(Object):
self.position = copy.deepcopy(state.position) self.position = copy.deepcopy(state.position)
self.orientation = copy.copy(state.orientation) self.orientation = copy.copy(state.orientation)
self.basket = copy.copy(state.basket) self.basket = copy.copy(state.basket)
self.battery -= state.cost
return state return state
def dampState(self): def dish_in_basket(self, table) -> bool:
self.prev_position = copy.deepcopy(self.position) return table in self.basket
self.prev_orientation = copy.copy(self.orientation)
def rollbackState(self): def basket_is_full(self) -> bool:
self.position = copy.deepcopy(self.prev_position) return self.basket_size == 0
self.orientation = copy.copy(self.prev_orientation)
def orders_in_basket(self) -> bool: def combine_orders(self):
return self.basket while not self.basket_is_full() and not self.memory_is_empty():
dish = self.memory.pop()
dish.set_done()
self.basket.append(dish)
self.basket_size -= 1
self.memory_size += 1
def deliver_dish(self, table):
if table in self.basket:
table.reset()
self.basket.remove(table)
self.basket_size += 1
def order_in_memory(self, table) -> bool:
return table in self.memory
def memory_is_empty(self) -> bool:
return not self.memory
def memory_is_full(self) -> bool:
return self.memory_size == 0
def collect_order(self, table):
if self.memory_is_full():
return
if table.agent_role == "order":
table.set_wait()
self.memory.append(table)
self.memory_size -= 1
def battary_status(self) -> str:
if self.battery >= 200:
return "hight"
elif self.battery >= 100:
return "medium"
else:
return "low"
def recharge(self):
self.battery = 300
def left(self): def left(self):
self.orientation = (self.orientation + 1) % 4 self.orientation = (self.orientation + 1) % 4
@ -38,13 +79,3 @@ class Waiter(Object):
self.position[0] += self.orientation - 2 # x (-1 or +1) self.position[0] += self.orientation - 2 # x (-1 or +1)
else: # y (0 or 2) else: # y (0 or 2)
self.position[1] += self.orientation - 1 # y (-1 or +1) self.position[1] += self.orientation - 1 # y (-1 or +1)
def collide_test(self, obj) -> bool:
out_of_range = [
self.position[0] >= self.square_count,
self.position[1] >= self.square_count,
self.position[0] < 0,
self.position[1] < 0
]
return any(out_of_range)