engine_improvements #3

Merged
s464919 merged 2 commits from engine_improvements into master 2022-05-25 23:54:39 +02:00
11 changed files with 303 additions and 100 deletions

View File

@ -1,18 +1,37 @@
from typing import Tuple, List
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.ItemType import ItemType
from decision.Action import Action
from decision.ActionType import ActionType
from pathfinding.PathFinderState import PathFinderState
from pathfinding.PathfinderOnStates import PathFinderOnStates
from util.PathDefinitions import GridLocation, GridWithWeights
class ForkliftAgent(AgentBase):
def __init__(self, model):
def __init__(self, model, game_constants, client_delivery: PatchAgent, drop_off: PatchAgent,
graph: GridWithWeights):
super().__init__(model)
self.action_queue: List[Action] = []
self.current_position = Tuple[int, int]
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]):
self.action_queue.extend(movement_actions)
@ -55,8 +74,88 @@ class ForkliftAgent(AgentBase):
print("move {} --> {}".format(self.current_position, action_type))
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:
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):
print("Created Forklift Agent [id: {}]".format(self.unique_id))

View File

@ -10,11 +10,10 @@ from ForkliftAgent import ForkliftAgent
from InitialStateFactory import InitialStateFactory
from PatchAgent import PatchAgent
from PatchType import PatchType
from PictureVisualizationAgent import PictureVisualizationAgent
from data.GameConstants import GameConstants
from data.Item import Item
from data.Order import Order
from data.enum.Direction import Direction
from data.enum.ItemType import ItemType
from decision.Action import Action
from decision.ActionType import ActionType
from pathfinding.PathfinderOnStates import PathFinderOnStates, PathFinderState
@ -38,14 +37,10 @@ class GameModel(Model):
self.running = True
self.grid = MultiGrid(height, width, True)
self.schedule = RandomActivation(self)
self.current_item_recognition = None
self.client_delivery: 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.game_constants = GameConstants(
@ -55,11 +50,27 @@ class GameModel(Model):
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 #
print("############## INITIALIZATION ##############")
self.phase = Phase.INIT
self.initialize_grid(graph)
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 ##############")
self.phase = Phase.ITEM_RECOGNITION
@ -88,22 +99,40 @@ class GameModel(Model):
self.grid.place_agent(self.forklift_agent, (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_dividers()
self.place_walls_agents(graph.walls)
self.place_puddles(graph.puddles)
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):
agent = PatchAgent(self, (self.grid.width - 1, int(self.grid.height / 2)), PatchType.pickUp)
self.schedule.add(agent)
self.grid.place_agent(agent, agent.location)
self.agents.append(agent)
self.client_delivery = agent
self.forklift_agent.client_delivery = self.client_delivery
agent = PatchAgent(self, (0, int(self.grid.height / 2)), PatchType.dropOff)
self.grid.place_agent(agent, agent.location)
self.agents.append(agent)
self.drop_off = agent
self.forklift_agent.drop_off = self.drop_off
def place_walls_agents(self, walls: List[GridLocation]):
for w in walls:
@ -138,6 +167,7 @@ class GameModel(Model):
else:
print("BEGIN ITEM RECOGNITION, left: {}".format(len(self.provided_items)))
item_to_recognise = self.provided_items.pop()
self.picture_visualization.img = "item_images/door/drzwi1.jpg"
recognised = self.recognise_item(item_to_recognise)
self.recognised_items.append(recognised)
@ -145,93 +175,10 @@ class GameModel(Model):
# TODO GENERICS SORTING
sorted(self.orderList, key=lambda x: len(x.items))
print("FINISHED CLIENT ORDER SORTING")
self.phase = Phase.PLAN_MOVEMENT
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:
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):
# TODO IMAGE PROCESSING

View File

@ -10,3 +10,4 @@ class PatchType(enum.Enum):
packingA = 6
packingB = 7
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):
PIZZA = 1
PASTA = 2
DOOR = 1
SHELF = 2
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 PatchAgent import PatchAgent
from PatchType import PatchType
from PictureVisualizationAgent import PictureVisualizationAgent
from data.enum.Direction import Direction
from util.PathDefinitions import GridWithWeights
from visualization.DisplayAttributeElement import DisplayAttributeElement
from visualization.DisplayItemListAttribute import DisplayItemListAttributeElement
from visualization.DisplayOrderList import DisplayOrderList
from visualization.DisplayPictureElement import DisplayPictureElement
colors = [
'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}
elif agent.patch_type == PatchType.diffTerrain:
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:
color = colors[random.randrange(13) + 3]
portrayal = {"Shape": "rect",
@ -49,13 +61,17 @@ def agent_portrayal(agent):
"Color": color,
"w": 1,
"h": 1}
if isinstance(agent, PictureVisualizationAgent):
portrayal = {"Shape": f"{agent.img}", "scale": 3.0, "Layer": 0}
return portrayal
if __name__ == '__main__':
base = 512
gridWidth = 10
gridHeight = 10
gridHeight = 13
scale = base / gridWidth
diagram = GridWithWeights(gridWidth, gridHeight)
@ -66,12 +82,15 @@ if __name__ == '__main__':
grid = CanvasGrid(agent_portrayal, gridWidth, gridHeight, scale * gridWidth, scale * gridHeight)
readyText = DisplayAttributeElement("phase")
provided_itesm = DisplayAttributeElement("provided_items")
recognised_items = DisplayAttributeElement("recognised_items")
ordersText = DisplayAttributeElement("orderList")
# current_item = DisplayPictureElement("current_item_recognition")
provided_itesm = DisplayItemListAttributeElement("provided_items")
recognised_items = DisplayItemListAttributeElement("recognised_items")
ordersText = DisplayOrderList("orderList")
fulfilled_orders = DisplayOrderList("fulfilled_orders")
server = ModularServer(GameModel,
[grid, readyText, provided_itesm, recognised_items],
[grid, readyText, provided_itesm, recognised_items, ordersText,
fulfilled_orders],
"Automatyczny Wózek Widłowy",
{"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 ""