Przyrost 2
This commit is contained in:
parent
71fcd755aa
commit
d6a8a7481e
@ -31,7 +31,7 @@
|
||||
|
||||
---
|
||||
|
||||
- [ ] Planowanie ruchu: Wymagania dot. drugiego przyrostu
|
||||
- [ ] **Planowanie ruchu: Wymagania dot. drugiego przyrostu**
|
||||
- [ ] Należy wykorzystać „Schemat procedury przeszukiwania grafu stanów z uwzględnieniem kosztu“
|
||||
- [ ] Należy zaimplementować strategię A\*, czyli zdefiniować funkcję wyznaczającą priorytet następników uwzględniającą zarówno koszt jak i odpowiednią heurystykę.
|
||||
- [x] Agent powinien dysponować co najmniej następującymi akcjami: ruch do przodu, obrót w lewo, obrót w prawo.
|
||||
@ -40,3 +40,9 @@
|
||||
> _Przykład: Koszt wjazdu traktora na pole marchewek to 10 a koszt wjazdu na pole puste to 1._
|
||||
|
||||
---
|
||||
|
||||
- [ ] **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 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.
|
||||
- [ ] Powinna pojawić się opcja podglądu wyuczonego drzewa (np. w logach lub w pliku z graficzną reprezentacją drzewa).
|
||||
|
30
agent.py
30
agent.py
@ -1,3 +1,4 @@
|
||||
import random
|
||||
from src.Engine import Engine
|
||||
from src.obj.Waiter import Waiter
|
||||
from src.obj.Block import Block
|
||||
@ -6,20 +7,31 @@ from src.obj.Table import Table
|
||||
from src.UserController import UserController
|
||||
from src.StateController import StateController
|
||||
|
||||
waiter = Waiter([0, 0], 0, 50, 450//50)
|
||||
SCREEN_SIZE = (800, 800)
|
||||
SQUARE_SIZE = 40
|
||||
|
||||
waiter = Waiter([0, 0], 0, SQUARE_SIZE, SCREEN_SIZE)
|
||||
objects = [
|
||||
Kitchen([0, 0], 0, 50, 450//50),
|
||||
Table([3, 6], 0, 50, 450//50),
|
||||
Table([2, 4], 0, 50, 450//50),
|
||||
Table([1, 5], 0, 50, 450//50),
|
||||
Block([3, 5], 0, 50, 450//50),
|
||||
Block([1, 4], 0, 50, 450//50),
|
||||
Block([2, 5], 0, 50, 450//50)
|
||||
Kitchen([0, 0], 0, SQUARE_SIZE, SCREEN_SIZE)
|
||||
]
|
||||
|
||||
for i in range(150):
|
||||
|
||||
pos = [0, 0]
|
||||
|
||||
while any([o.compare_pos(pos) for o in objects]):
|
||||
pos = [random.randint(1, SCREEN_SIZE[0]/SQUARE_SIZE),
|
||||
random.randint(1, SCREEN_SIZE[0]/SQUARE_SIZE)]
|
||||
|
||||
if (random.randint(0, 1)):
|
||||
objects.append(Block(pos, 0, SQUARE_SIZE, SCREEN_SIZE))
|
||||
else:
|
||||
objects.append(Table(pos, 0, SQUARE_SIZE,
|
||||
SCREEN_SIZE, random.randint(0, 3)))
|
||||
|
||||
user = UserController(waiter)
|
||||
state = StateController(waiter)
|
||||
engine = Engine((450, 450), 50, user, state)
|
||||
engine = Engine(SCREEN_SIZE, SQUARE_SIZE, user, state)
|
||||
|
||||
for o in objects:
|
||||
engine.subscribe(o)
|
||||
|
@ -1,3 +1,4 @@
|
||||
import time
|
||||
import pygame
|
||||
from .obj.Object import Object
|
||||
from .UserController import UserController
|
||||
@ -7,6 +8,8 @@ from .StateController import StateController
|
||||
class Engine:
|
||||
|
||||
def __init__(self, screen_size, square_size, user: UserController, state: StateController):
|
||||
pygame.display.set_caption('Waiter Agent')
|
||||
|
||||
self.user = user
|
||||
self.state = state
|
||||
self.screen_size = screen_size
|
||||
@ -18,6 +21,7 @@ class Engine:
|
||||
self.num_squares, self.square_size)
|
||||
|
||||
self.objects: list[Object] = []
|
||||
self.goals: list = []
|
||||
|
||||
self.runnin = False
|
||||
|
||||
@ -48,19 +52,18 @@ class Engine:
|
||||
self.running = False
|
||||
|
||||
def action(self):
|
||||
self.user.handler(self)
|
||||
|
||||
conditionals = [
|
||||
not self.user.obj.collide_test(self.user.obj),
|
||||
all([not o.collide_test(self.user.obj) for o in self.objects])
|
||||
]
|
||||
|
||||
if all(conditionals):
|
||||
self.user.obj.dampState()
|
||||
if not self.state.path:
|
||||
if self.goals:
|
||||
self.state.graphsearch(self)
|
||||
self.user.handler(self)
|
||||
else:
|
||||
self.user.obj.rollbackState()
|
||||
|
||||
self.user.obj.goal_test(self)
|
||||
state = self.user.obj.changeState(self.state.path.pop())
|
||||
print("Action:\t{0}\tCost:\t{1}\tCost so far: {2}".format(
|
||||
state.agent_role,
|
||||
state.cost,
|
||||
state.cost_so_far)
|
||||
)
|
||||
time.sleep(0.5)
|
||||
|
||||
def redraw(self):
|
||||
self.screen.fill((255, 255, 255))
|
||||
@ -74,7 +77,13 @@ class Engine:
|
||||
|
||||
self.user.obj.blit(self.screen)
|
||||
|
||||
for f in self.state.fringe.queue:
|
||||
f.blit(self.screen)
|
||||
|
||||
for s in self.state.path:
|
||||
s.blit(self.screen)
|
||||
|
||||
pygame.display.flip()
|
||||
|
||||
def appendGoalPosition(self, position):
|
||||
self.goals.append(position)
|
||||
|
@ -1,37 +1,45 @@
|
||||
from .obj.TemporaryState import TemporaryState
|
||||
from queue import PriorityQueue
|
||||
|
||||
|
||||
class StateController:
|
||||
def __init__(self, istate):
|
||||
self.path = []
|
||||
self.explored = []
|
||||
self.fringe = []
|
||||
self.fringe = PriorityQueue()
|
||||
self.istate = istate
|
||||
self.goal = istate.position
|
||||
|
||||
def reset(self):
|
||||
self.path.clear()
|
||||
self.explored.clear()
|
||||
self.fringe.clear()
|
||||
self.fringe = PriorityQueue()
|
||||
|
||||
def build_path(self, goal_state):
|
||||
total_cost = goal_state.cost
|
||||
self.path.append(goal_state)
|
||||
while self.path[-1].agent_role != "blank":
|
||||
while self.path[-1].parent.agent_role != "blank":
|
||||
self.path.append(self.path[-1].parent)
|
||||
total_cost += self.path[-1].cost
|
||||
|
||||
print("Total path cost:\t{0}".format(total_cost))
|
||||
return self.path
|
||||
|
||||
def graphsearch(self, engine): # BFS
|
||||
def graphsearch(self, engine): # A*
|
||||
print("Search path")
|
||||
|
||||
self.goal = list(engine.goals.pop())
|
||||
|
||||
self.reset()
|
||||
|
||||
self.fringe.append(TemporaryState(self.istate))
|
||||
start = TemporaryState(self.istate, 0)
|
||||
|
||||
while self.fringe:
|
||||
self.explored.append(self.fringe.pop(0))
|
||||
self.fringe.put(start)
|
||||
|
||||
if self.explored[-1].goal_test(engine):
|
||||
print("Goal!")
|
||||
while self.fringe and not self.path:
|
||||
self.explored.append(self.fringe.get())
|
||||
|
||||
if self.explored[-1].position == self.goal:
|
||||
goal_state = self.explored[-1]
|
||||
self.reset()
|
||||
return self.build_path(goal_state)
|
||||
@ -40,7 +48,6 @@ class StateController:
|
||||
self.succ(self.explored[-1].left(), engine)
|
||||
self.succ(self.explored[-1].right(), engine)
|
||||
|
||||
self.path = self.fringe
|
||||
engine.redraw()
|
||||
|
||||
self.reset()
|
||||
@ -57,4 +64,29 @@ class StateController:
|
||||
elif any([o.collide_test(state) for o in engine.objects]):
|
||||
return
|
||||
|
||||
self.fringe.append(state)
|
||||
for o in engine.objects:
|
||||
if state.cost != 1:
|
||||
break
|
||||
if o.position == state.position:
|
||||
state.change_cost(o)
|
||||
|
||||
state.cost_so_far = self.explored[-1].cost_so_far + state.cost
|
||||
|
||||
in_explored = any([state.compare(s) for s in self.explored]
|
||||
)
|
||||
|
||||
in_frige = any([state.compare(f) for f in self.fringe.queue])
|
||||
|
||||
if not in_explored and not in_frige:
|
||||
state.heuristic(self.goal)
|
||||
self.fringe.put(state)
|
||||
|
||||
elif in_frige:
|
||||
fringe = state
|
||||
for f in self.fringe.queue:
|
||||
if state.compare(f):
|
||||
fringe = f
|
||||
break
|
||||
|
||||
if state.cost_so_far < fringe.cost_so_far:
|
||||
fringe.replace(state)
|
||||
|
@ -9,12 +9,8 @@ class UserController:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
engine.quit()
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_UP:
|
||||
self.obj.front()
|
||||
elif event.key == pygame.K_LEFT:
|
||||
self.obj.left()
|
||||
elif event.key == pygame.K_RIGHT:
|
||||
self.obj.right()
|
||||
elif event.key == pygame.K_SPACE:
|
||||
engine.state.graphsearch(engine)
|
||||
elif event.type == pygame.MOUSEBUTTONDOWN:
|
||||
pos = pygame.mouse.get_pos()
|
||||
pos = (pos[0] // engine.square_size,
|
||||
pos[1] // engine.square_size)
|
||||
engine.appendGoalPosition(pos)
|
||||
|
@ -2,8 +2,8 @@ from src.obj.Object import Object
|
||||
|
||||
|
||||
class Block(Object):
|
||||
def __init__(self, position, orientation, square_size, square_count):
|
||||
super().__init__("block", position, orientation, square_size, square_count)
|
||||
def __init__(self, position, orientation, square_size, screen_size):
|
||||
super().__init__("block", position, orientation, square_size, screen_size)
|
||||
|
||||
def collide_test(self, waiter: Object) -> bool:
|
||||
return waiter.position == self.position
|
||||
|
@ -2,19 +2,5 @@ from src.obj.Object import Object
|
||||
|
||||
|
||||
class Kitchen(Object):
|
||||
def __init__(self, position, orientation, square_size, square_count):
|
||||
super().__init__("kitchen", position, orientation, square_size, square_count)
|
||||
|
||||
def goal_test(self, waiter) -> bool:
|
||||
conditions = [
|
||||
waiter.orders_in_basket(),
|
||||
self.position == waiter.position
|
||||
]
|
||||
|
||||
if all(conditions):
|
||||
for table in waiter.basket:
|
||||
if table.agent_role == "wait":
|
||||
table.next_role(waiter)
|
||||
return True
|
||||
|
||||
return False
|
||||
def __init__(self, position, orientation, square_size, screen_size):
|
||||
super().__init__("kitchen", position, orientation, square_size, screen_size)
|
||||
|
@ -2,12 +2,13 @@ import pygame
|
||||
|
||||
|
||||
class Object:
|
||||
def __init__(self, agent_role, position, orientation, square_size, square_count):
|
||||
def __init__(self, agent_role, position, orientation, square_size, screen_size):
|
||||
self.agent_role = agent_role
|
||||
self.position = position
|
||||
self.orientation = orientation % 4
|
||||
self.square_size = square_size
|
||||
self.square_count = square_count
|
||||
self.screen_size = screen_size
|
||||
self.square_count = screen_size[0] // square_size
|
||||
|
||||
self.image = pygame.image.load(
|
||||
'src/img/{0}.png'.format(self.agent_role))
|
||||
@ -37,11 +38,11 @@ class Object:
|
||||
def collide_test(self, obj) -> bool:
|
||||
return False
|
||||
|
||||
def goal_test(self, waiter) -> bool:
|
||||
return False
|
||||
|
||||
def blit(self, screen: pygame.Surface):
|
||||
image = pygame.transform.rotate(self.image, self.get_angle())
|
||||
self.rect.x = self.position[0] * self.square_size
|
||||
self.rect.y = self.position[1] * self.square_size
|
||||
screen.blit(image, self.rect)
|
||||
|
||||
def compare_pos(self, pos) -> bool:
|
||||
return self.position == pos
|
||||
|
@ -2,8 +2,8 @@ from src.obj.Object import Object
|
||||
|
||||
|
||||
class Table(Object):
|
||||
def __init__(self, position, orientation, square_size, square_count, current_role=1):
|
||||
super().__init__("table", position, orientation, square_size, square_count)
|
||||
def __init__(self, position, orientation, square_size, screen_size, current_role=0):
|
||||
super().__init__("table", position, orientation, square_size, screen_size)
|
||||
self.roles = ["table", "order", "wait", "done"]
|
||||
self.current_role = current_role
|
||||
self.change_role(self.roles[self.current_role])
|
||||
@ -12,13 +12,3 @@ class Table(Object):
|
||||
if waiter.agent_role == "waiter":
|
||||
self.current_role = (self.current_role + 1) % 4
|
||||
self.change_role(self.roles[self.current_role])
|
||||
|
||||
def goal_test(self, waiter) -> bool:
|
||||
if self.position == waiter.position:
|
||||
|
||||
if self.agent_role == "order":
|
||||
return waiter.take_order(self)
|
||||
elif self.agent_role == "done":
|
||||
return waiter.drop_order(self)
|
||||
|
||||
return False
|
||||
|
@ -3,15 +3,24 @@ import copy
|
||||
|
||||
|
||||
class TemporaryState(Waiter):
|
||||
def __init__(self, parent, action="blank"):
|
||||
def __init__(self, parent, cost_so_far, action="blank", cost=0, h=0):
|
||||
super().__init__(copy.deepcopy(parent.position),
|
||||
copy.copy(parent.orientation),
|
||||
copy.copy(parent.square_size),
|
||||
copy.copy(parent.square_count),
|
||||
copy.copy(parent.screen_size),
|
||||
copy.copy(parent.basket))
|
||||
self.agent_role = action
|
||||
self.parent = parent
|
||||
self.change_role(action)
|
||||
self.apply_transformation()
|
||||
self.cost = cost
|
||||
self.cost_so_far = cost_so_far
|
||||
self.h = h
|
||||
|
||||
def replace(self, repl):
|
||||
self.basket = copy.copy(repl.basket)
|
||||
self.parent = repl.parent
|
||||
self.cost_so_far = repl.cost_so_far
|
||||
|
||||
def apply_transformation(self):
|
||||
if self.agent_role == "left":
|
||||
@ -25,13 +34,13 @@ class TemporaryState(Waiter):
|
||||
self.position[1] += self.orientation - 1 # y (-1 or +1)
|
||||
|
||||
def left(self):
|
||||
return TemporaryState(self, "left")
|
||||
return TemporaryState(self, self.cost_so_far, "left", 1)
|
||||
|
||||
def right(self):
|
||||
return TemporaryState(self, "right")
|
||||
return TemporaryState(self, self.cost_so_far, "right", 1)
|
||||
|
||||
def front(self):
|
||||
return TemporaryState(self, "front")
|
||||
return TemporaryState(self, self.cost_so_far, "front", 1)
|
||||
|
||||
def collide_test(self) -> bool:
|
||||
out_of_range = [
|
||||
@ -49,3 +58,45 @@ class TemporaryState(Waiter):
|
||||
self.orientation == state.orientation
|
||||
]
|
||||
return all(conditions)
|
||||
|
||||
def change_cost(self, obj):
|
||||
self.cost = 1 # default cost
|
||||
|
||||
if self.agent_role == "front":
|
||||
|
||||
costs = {
|
||||
"kitchen": 5,
|
||||
"table": 5,
|
||||
"order": 20,
|
||||
"wait": 10,
|
||||
"done": 15,
|
||||
}
|
||||
|
||||
if obj.agent_role in costs.keys():
|
||||
self.cost = costs[obj.agent_role]
|
||||
|
||||
def heuristic(self, goal):
|
||||
x = abs(self.position[0] - goal[0])
|
||||
y = abs(self.position[1] - goal[1])
|
||||
|
||||
self.h = x + y
|
||||
|
||||
return self.h
|
||||
|
||||
def current_cost(self):
|
||||
return self.cost_so_far + self.h
|
||||
|
||||
def __eq__(self, __value) -> bool:
|
||||
return self.current_cost() == __value.current_cost()
|
||||
|
||||
def __lt__(self, __value) -> bool:
|
||||
return self.current_cost() < __value.current_cost()
|
||||
|
||||
def __le__(self, __value) -> bool:
|
||||
return self.current_cost() <= __value.current_cost()
|
||||
|
||||
def __gt__(self, __value) -> bool:
|
||||
return self.current_cost() > __value.current_cost()
|
||||
|
||||
def __ge__(self, __value) -> bool:
|
||||
return self.current_cost() >= __value.current_cost()
|
||||
|
@ -3,13 +3,19 @@ from src.obj.Object import Object
|
||||
|
||||
|
||||
class Waiter(Object):
|
||||
def __init__(self, position, orientation, square_size, square_count, basket=[]):
|
||||
super().__init__("waiter", position, orientation, square_size, square_count)
|
||||
def __init__(self, position, orientation, square_size, screen_size, basket=[]):
|
||||
super().__init__("waiter", position, orientation, square_size, screen_size)
|
||||
self.basket_size = 2
|
||||
self.basket = basket
|
||||
self.prev_position = copy.deepcopy(self.position)
|
||||
self.prev_orientation = copy.copy(self.orientation)
|
||||
|
||||
def changeState(self, state):
|
||||
self.position = copy.deepcopy(state.position)
|
||||
self.orientation = copy.copy(state.orientation)
|
||||
self.basket = copy.copy(state.basket)
|
||||
return state
|
||||
|
||||
def dampState(self):
|
||||
self.prev_position = copy.deepcopy(self.position)
|
||||
self.prev_orientation = copy.copy(self.orientation)
|
||||
@ -18,21 +24,6 @@ class Waiter(Object):
|
||||
self.position = copy.deepcopy(self.prev_position)
|
||||
self.orientation = copy.copy(self.prev_orientation)
|
||||
|
||||
def take_order(self, table) -> bool:
|
||||
if table.agent_role == "order":
|
||||
if len(self.basket) < self.basket_size:
|
||||
table.next_role(self)
|
||||
self.basket.append(table)
|
||||
return True
|
||||
return False
|
||||
|
||||
def drop_order(self, table) -> bool:
|
||||
if table.agent_role == "done":
|
||||
self.basket.remove(table)
|
||||
table.next_role(self)
|
||||
return True
|
||||
return False
|
||||
|
||||
def orders_in_basket(self) -> bool:
|
||||
return self.basket
|
||||
|
||||
@ -57,6 +48,3 @@ class Waiter(Object):
|
||||
]
|
||||
|
||||
return any(out_of_range)
|
||||
|
||||
def goal_test(self, engine):
|
||||
return any([o.goal_test(self) for o in engine.objects])
|
||||
|
Loading…
Reference in New Issue
Block a user