Merge pull request 'engine_improvements' (#3) from engine_improvements into master

Reviewed-on: #3
This commit is contained in:
Aleksander Szamałek 2022-05-25 23:54:39 +02:00
commit b944eab69a
11 changed files with 303 additions and 100 deletions

View File

@ -1,18 +1,37 @@
from typing import Tuple, List from typing import Tuple, List
from AgentBase import AgentBase from AgentBase import AgentBase
from PatchAgent import PatchAgent
from PatchType import PatchType
from data.Item import Item
from data.Order import Order
from data.enum.Direction import Direction from data.enum.Direction import Direction
from data.enum.ItemType import ItemType
from decision.Action import Action from decision.Action import Action
from decision.ActionType import ActionType from decision.ActionType import ActionType
from pathfinding.PathFinderState import PathFinderState
from pathfinding.PathfinderOnStates import PathFinderOnStates
from util.PathDefinitions import GridLocation, GridWithWeights
class ForkliftAgent(AgentBase): class ForkliftAgent(AgentBase):
def __init__(self, model): def __init__(self, model, game_constants, client_delivery: PatchAgent, drop_off: PatchAgent,
graph: GridWithWeights):
super().__init__(model) super().__init__(model)
self.action_queue: List[Action] = [] self.action_queue: List[Action] = []
self.current_position = Tuple[int, int] self.current_position = Tuple[int, int]
self.current_rotation = Direction.right self.current_rotation = Direction.right
self.orderList = []
self.fulfilled_orders: List[Order] = []
self.client_delivery: PatchAgent = client_delivery
self.drop_off: PatchAgent = drop_off
self.graph = graph
self.game_constants = game_constants
self.current_order: Order = None
self.current_item = None
self.item_station_completed = False
self.provided_items: List[Item] = []
def queue_movement_actions(self, movement_actions: List[Action]): def queue_movement_actions(self, movement_actions: List[Action]):
self.action_queue.extend(movement_actions) self.action_queue.extend(movement_actions)
@ -55,8 +74,88 @@ class ForkliftAgent(AgentBase):
print("move {} --> {}".format(self.current_position, action_type)) print("move {} --> {}".format(self.current_position, action_type))
self.current_position = (self.current_position[0] - 1, self.current_position[1]) self.current_position = (self.current_position[0] - 1, self.current_position[1])
def plan_actions(self):
if len(self.current_order.items) > 0:
i = self.current_order.items.pop(0)
if self.current_item is None:
self.provided_items.clear()
self.current_item = i
print("PLAN MOVEMENT")
# get item
pathFinder = PathFinderOnStates(
self.game_constants,
self.drop_off.location,
PathFinderState(self.current_position,
self.current_rotation,
0,
Action(ActionType.NONE),
[])
)
actions = pathFinder.get_action_list()
self.queue_movement_actions(actions)
elif not self.item_station_completed:
# go through station
packing_station: GridLocation = None
stations = dict(self.graph.packingStations)
if i.real_type == ItemType.SHELF:
packing_station = stations[PatchType.packingA]
elif i.real_type == ItemType.EGG:
packing_station = stations[PatchType.packingB]
elif i.real_type == ItemType.DOOR:
packing_station = stations[PatchType.packingC]
pathFinder = PathFinderOnStates(
self.game_constants,
packing_station,
PathFinderState(self.current_position,
self.current_rotation,
0,
Action(
desired_item=i,
action_type=ActionType.PICK_ITEM
),
[])
)
actions = pathFinder.get_action_list()
self.queue_movement_actions(actions)
self.item_station_completed = True
else:
# go to client delivery area
pathFinder = PathFinderOnStates(
self.game_constants,
self.client_delivery.location,
PathFinderState(self.current_position,
self.current_rotation,
0,
Action(ActionType.NONE),
[])
)
actions = pathFinder.get_action_list()
self.queue_movement_actions(actions)
self.queue_movement_actions(
[Action(ActionType.DROP_ITEM)]
)
self.current_item = None
self.provided_items.append(self.current_item)
self.item_station_completed = False
def step(self) -> None: def step(self) -> None:
self.move() if len(self.action_queue) > 0:
self.move()
elif len(self.orderList) > 0:
if (self.current_order is not None and len(self.current_order.items)) == 0:
self.fulfilled_orders.append(self.current_order)
self.current_order = None
if self.current_order is None:
self.current_order = self.orderList.pop(0)
self.plan_actions()
def creation_log(self): def creation_log(self):
print("Created Forklift Agent [id: {}]".format(self.unique_id)) print("Created Forklift Agent [id: {}]".format(self.unique_id))

View File

@ -10,11 +10,10 @@ from ForkliftAgent import ForkliftAgent
from InitialStateFactory import InitialStateFactory from InitialStateFactory import InitialStateFactory
from PatchAgent import PatchAgent from PatchAgent import PatchAgent
from PatchType import PatchType from PatchType import PatchType
from PictureVisualizationAgent import PictureVisualizationAgent
from data.GameConstants import GameConstants from data.GameConstants import GameConstants
from data.Item import Item from data.Item import Item
from data.Order import Order from data.Order import Order
from data.enum.Direction import Direction
from data.enum.ItemType import ItemType
from decision.Action import Action from decision.Action import Action
from decision.ActionType import ActionType from decision.ActionType import ActionType
from pathfinding.PathfinderOnStates import PathFinderOnStates, PathFinderState from pathfinding.PathfinderOnStates import PathFinderOnStates, PathFinderState
@ -38,14 +37,10 @@ class GameModel(Model):
self.running = True self.running = True
self.grid = MultiGrid(height, width, True) self.grid = MultiGrid(height, width, True)
self.schedule = RandomActivation(self) self.schedule = RandomActivation(self)
self.current_item_recognition = None
self.client_delivery: PatchAgent = None self.client_delivery: PatchAgent = None
self.drop_off: PatchAgent = None self.drop_off: PatchAgent = None
self.agents = [AgentBase]
self.forklift_agent = ForkliftAgent(self)
self.schedule.add(self.forklift_agent)
self.agents.append(self.forklift_agent)
self.graph = graph self.graph = graph
self.game_constants = GameConstants( self.game_constants = GameConstants(
@ -55,11 +50,27 @@ class GameModel(Model):
graph.puddles graph.puddles
) )
self.agents = [AgentBase]
self.forklift_agent = ForkliftAgent(
self,
self.game_constants,
self.client_delivery,
self.drop_off,
self.graph
)
self.schedule.add(self.forklift_agent)
self.agents.append(self.forklift_agent)
# INITIALIZATION # # INITIALIZATION #
print("############## INITIALIZATION ##############") print("############## INITIALIZATION ##############")
self.phase = Phase.INIT self.phase = Phase.INIT
self.initialize_grid(graph) self.initialize_grid(graph)
self.orderList: List[Order] = InitialStateFactory.generate_order_list(3) self.orderList: List[Order] = InitialStateFactory.generate_order_list(3)
self.fulfilled_orders: List[Order] = []
self.forklift_agent.orderList = self.orderList
self.forklift_agent.fulfilled_orders = self.fulfilled_orders
print("############## RECOGNISE ITEMS ##############") print("############## RECOGNISE ITEMS ##############")
self.phase = Phase.ITEM_RECOGNITION self.phase = Phase.ITEM_RECOGNITION
@ -88,22 +99,40 @@ class GameModel(Model):
self.grid.place_agent(self.forklift_agent, (x, y)) self.grid.place_agent(self.forklift_agent, (x, y))
self.forklift_agent.current_position = (x, y) self.forklift_agent.current_position = (x, y)
self.picture_visualization = PictureVisualizationAgent(
self,
(1, 11),
)
self.schedule.add(self.picture_visualization)
self.grid.place_agent(self.picture_visualization, self.picture_visualization.location)
self.agents.append(self.picture_visualization)
self.place_logistics() self.place_logistics()
self.place_dividers()
self.place_walls_agents(graph.walls) self.place_walls_agents(graph.walls)
self.place_puddles(graph.puddles) self.place_puddles(graph.puddles)
self.place_packing_stations(graph.packingStations) self.place_packing_stations(graph.packingStations)
def place_dividers(self):
for i in range(0, 10):
for j in range(10,13):
agent = PatchAgent(self, (i, j), PatchType.divider)
self.agents.append(agent)
self.grid.place_agent(agent, (i, j))
def place_logistics(self): def place_logistics(self):
agent = PatchAgent(self, (self.grid.width - 1, int(self.grid.height / 2)), PatchType.pickUp) agent = PatchAgent(self, (self.grid.width - 1, int(self.grid.height / 2)), PatchType.pickUp)
self.schedule.add(agent) self.schedule.add(agent)
self.grid.place_agent(agent, agent.location) self.grid.place_agent(agent, agent.location)
self.agents.append(agent) self.agents.append(agent)
self.client_delivery = agent self.client_delivery = agent
self.forklift_agent.client_delivery = self.client_delivery
agent = PatchAgent(self, (0, int(self.grid.height / 2)), PatchType.dropOff) agent = PatchAgent(self, (0, int(self.grid.height / 2)), PatchType.dropOff)
self.grid.place_agent(agent, agent.location) self.grid.place_agent(agent, agent.location)
self.agents.append(agent) self.agents.append(agent)
self.drop_off = agent self.drop_off = agent
self.forklift_agent.drop_off = self.drop_off
def place_walls_agents(self, walls: List[GridLocation]): def place_walls_agents(self, walls: List[GridLocation]):
for w in walls: for w in walls:
@ -138,6 +167,7 @@ class GameModel(Model):
else: else:
print("BEGIN ITEM RECOGNITION, left: {}".format(len(self.provided_items))) print("BEGIN ITEM RECOGNITION, left: {}".format(len(self.provided_items)))
item_to_recognise = self.provided_items.pop() item_to_recognise = self.provided_items.pop()
self.picture_visualization.img = "item_images/door/drzwi1.jpg"
recognised = self.recognise_item(item_to_recognise) recognised = self.recognise_item(item_to_recognise)
self.recognised_items.append(recognised) self.recognised_items.append(recognised)
@ -145,93 +175,10 @@ class GameModel(Model):
# TODO GENERICS SORTING # TODO GENERICS SORTING
sorted(self.orderList, key=lambda x: len(x.items)) sorted(self.orderList, key=lambda x: len(x.items))
print("FINISHED CLIENT ORDER SORTING") print("FINISHED CLIENT ORDER SORTING")
self.phase = Phase.PLAN_MOVEMENT self.phase = Phase.EXECUTION
if self.phase == Phase.PLAN_MOVEMENT:
if len(self.orderList) > 0:
self.plan_actions()
self.phase = Phase.EXECUTION
else:
print("NO MORE ORDERS")
if self.phase == Phase.EXECUTION: if self.phase == Phase.EXECUTION:
print("Execution") print("Execution")
if (len(self.forklift_agent.action_queue) == 0):
self.phase = Phase.PLAN_MOVEMENT
def plan_actions(self):
order = self.orderList.pop(0)
print("PLAN MOVEMENT")
for i in order.items:
if self.first:
# get item
pathFinder = PathFinderOnStates(
self.game_constants,
self.drop_off.location,
PathFinderState(self.forklift_agent.current_position,
self.forklift_agent.current_rotation,
0,
Action(ActionType.NONE),
[])
)
actions = pathFinder.get_action_list()
self.forklift_agent.queue_movement_actions(actions)
self.first = False
else:
# get item
pathFinder = PathFinderOnStates(
self.game_constants,
self.drop_off.location,
PathFinderState(self.client_delivery.location,
Direction.right,
0,
Action(ActionType.NONE),
[])
)
actions = pathFinder.get_action_list()
self.forklift_agent.queue_movement_actions(actions)
self.first = False
# go through station
packing_station: GridLocation = None
stations = dict(self.graph.packingStations)
if i.real_type == ItemType.PASTA:
packing_station = stations[PatchType.packingA]
elif i.real_type == ItemType.EGG:
packing_station = stations[PatchType.packingB]
elif i.real_type == ItemType.PIZZA:
packing_station = stations[PatchType.packingC]
pathFinder = PathFinderOnStates(
self.game_constants,
packing_station,
PathFinderState(self.drop_off.location,
Direction.left,
0,
Action(
desired_item=i,
action_type=ActionType.PICK_ITEM
),
[])
)
actions = pathFinder.get_action_list()
self.forklift_agent.queue_movement_actions(actions)
# go to client delivery area
pathFinder = PathFinderOnStates(
self.game_constants,
self.client_delivery.location,
PathFinderState(packing_station,
Direction.right,
0,
Action(ActionType.NONE),
[])
)
actions = pathFinder.get_action_list()
self.forklift_agent.queue_movement_actions(actions)
self.forklift_agent.queue_movement_actions(
[Action(ActionType.DROP_ITEM)]
)
def recognise_item(self, item: Item): def recognise_item(self, item: Item):
# TODO IMAGE PROCESSING # TODO IMAGE PROCESSING

View File

@ -10,3 +10,4 @@ class PatchType(enum.Enum):
packingA = 6 packingA = 6
packingB = 7 packingB = 7
packingC = 8 packingC = 8
divider = 9

View File

@ -0,0 +1,13 @@
from AgentBase import AgentBase
from util.PathDefinitions import GridLocation
class PictureVisualizationAgent(AgentBase):
def __init__(self, model, location: GridLocation):
self.location = location
self.img = ""
super().__init__(model)
def creation_log(self):
print("Created Patch Agent [id: {} ,img: {}]".format(self.unique_id, self.img))

View File

@ -2,6 +2,6 @@ from enum import Enum
class ItemType(Enum): class ItemType(Enum):
PIZZA = 1 DOOR = 1
PASTA = 2 SHELF = 2
EGG = 3 EGG = 3

BIN
item_images/door/drzwi1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
item_images/door/drzwi2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

29
main.py
View File

@ -7,9 +7,13 @@ from ForkliftAgent import ForkliftAgent
from GameModel import GameModel from GameModel import GameModel
from PatchAgent import PatchAgent from PatchAgent import PatchAgent
from PatchType import PatchType from PatchType import PatchType
from PictureVisualizationAgent import PictureVisualizationAgent
from data.enum.Direction import Direction from data.enum.Direction import Direction
from util.PathDefinitions import GridWithWeights from util.PathDefinitions import GridWithWeights
from visualization.DisplayAttributeElement import DisplayAttributeElement from visualization.DisplayAttributeElement import DisplayAttributeElement
from visualization.DisplayItemListAttribute import DisplayItemListAttributeElement
from visualization.DisplayOrderList import DisplayOrderList
from visualization.DisplayPictureElement import DisplayPictureElement
colors = [ colors = [
'blue', 'cyan', 'orange', 'yellow', 'magenta', 'purple', '#103d3e', '#9fc86c', 'blue', 'cyan', 'orange', 'yellow', 'magenta', 'purple', '#103d3e', '#9fc86c',
@ -41,6 +45,14 @@ def agent_portrayal(agent):
portrayal = {"Shape": "img/okB00mer.png", "scale": 1.0, "Layer": 0} portrayal = {"Shape": "img/okB00mer.png", "scale": 1.0, "Layer": 0}
elif agent.patch_type == PatchType.diffTerrain: elif agent.patch_type == PatchType.diffTerrain:
portrayal = {"Shape": "img/puddle.png", "scale": 1.0, "Layer": 0} portrayal = {"Shape": "img/puddle.png", "scale": 1.0, "Layer": 0}
elif agent.patch_type == PatchType.divider:
portrayal = \
{"Shape": "rect",
"Filled": "true",
"Layer": 0,
"Color": "black",
"w": 1,
"h": 1}
else: else:
color = colors[random.randrange(13) + 3] color = colors[random.randrange(13) + 3]
portrayal = {"Shape": "rect", portrayal = {"Shape": "rect",
@ -49,13 +61,17 @@ def agent_portrayal(agent):
"Color": color, "Color": color,
"w": 1, "w": 1,
"h": 1} "h": 1}
if isinstance(agent, PictureVisualizationAgent):
portrayal = {"Shape": f"{agent.img}", "scale": 3.0, "Layer": 0}
return portrayal return portrayal
if __name__ == '__main__': if __name__ == '__main__':
base = 512 base = 512
gridWidth = 10 gridWidth = 10
gridHeight = 10 gridHeight = 13
scale = base / gridWidth scale = base / gridWidth
diagram = GridWithWeights(gridWidth, gridHeight) diagram = GridWithWeights(gridWidth, gridHeight)
@ -66,12 +82,15 @@ if __name__ == '__main__':
grid = CanvasGrid(agent_portrayal, gridWidth, gridHeight, scale * gridWidth, scale * gridHeight) grid = CanvasGrid(agent_portrayal, gridWidth, gridHeight, scale * gridWidth, scale * gridHeight)
readyText = DisplayAttributeElement("phase") readyText = DisplayAttributeElement("phase")
provided_itesm = DisplayAttributeElement("provided_items") # current_item = DisplayPictureElement("current_item_recognition")
recognised_items = DisplayAttributeElement("recognised_items") provided_itesm = DisplayItemListAttributeElement("provided_items")
ordersText = DisplayAttributeElement("orderList") recognised_items = DisplayItemListAttributeElement("recognised_items")
ordersText = DisplayOrderList("orderList")
fulfilled_orders = DisplayOrderList("fulfilled_orders")
server = ModularServer(GameModel, server = ModularServer(GameModel,
[grid, readyText, provided_itesm, recognised_items], [grid, readyText, provided_itesm, recognised_items, ordersText,
fulfilled_orders],
"Automatyczny Wózek Widłowy", "Automatyczny Wózek Widłowy",
{"width": gridHeight, "height": gridWidth, "graph": diagram}, ) {"width": gridHeight, "height": gridWidth, "graph": diagram}, )

View File

@ -0,0 +1,48 @@
from collections import Counter
from typing import List
from mesa.visualization.modules import TextElement
from data.Item import Item
from data.enum.ItemType import ItemType
class DisplayItemListAttributeElement(TextElement):
def __init__(self, attr_name):
'''
Create a new text attribute element.
Args:
attr_name: The name of the attribute to extract from the model.
Example return: "happy: 10"
'''
self.attr_name = attr_name
def render(self, model):
val = getattr(model, self.attr_name)
itemList: List[Item] = val
itemList = map(lambda x: x.real_type, itemList)
itemCounter = Counter(itemList)
# return self.attr_name + ":" + pprint.pformat(itemCounter)
res = self.attr_name + ":" + "<ul>"
for e in itemCounter:
key = e
val = itemCounter[key]
key_str = ""
if key == ItemType.DOOR:
key_str = "Door"
elif key == ItemType.SHELF:
key_str = "Shelf"
res += "<li>{}:{}</li>".format(key_str, val)
res += "</ul>"
return res

View File

@ -0,0 +1,55 @@
from collections import Counter
from typing import List
from mesa.visualization.modules import TextElement
from data.Order import Order
from data.enum.ItemType import ItemType
class DisplayOrderList(TextElement):
def __init__(self, attr_name):
'''
Create a new text attribute element.
Args:
attr_name: The name of the attribute to extract from the model.
Example return: "happy: 10"
'''
self.attr_name = attr_name
def render(self, model):
val = getattr(model, self.attr_name)
orderList: List[Order] = val
res = self.attr_name + ": <ol>"
for o in orderList:
if o is None:
continue
itemList = map(lambda x: x.real_type, o.items)
itemCounter = Counter(itemList)
item_str = "<ul>"
for e in itemCounter:
key = e
val = itemCounter[key]
key_str = ""
if key == ItemType.DOOR:
key_str = "Door"
elif key == ItemType.SHELF:
key_str = "Shelf"
item_str += f"<li>{key_str}:{val}</li>"
item_str += "</ul>"
res += f"<li> items: {item_str} priority: {o.priority} <br> Client: {vars(o.client_params)} </li>"
res += "</ol>"
return res

View File

@ -0,0 +1,21 @@
from mesa.visualization.modules import TextElement
class DisplayPictureElement(TextElement):
def __init__(self, attr_name):
'''
Create a new text attribute element.
Args:
attr_name: The name of the attribute to extract from the model.
Example return: "happy: 10"
'''
self.attr_name = attr_name
def render(self, model):
val = getattr(model, self.attr_name)
if val is not None:
return self.attr_name + ': <img src="{}" alt="{}" style="width:148px; hei ght:148px;" >'.format(val, self.attr_name)
else:
return ""