世界在不同位置包含代理,在任何位置只有一个代理。每个代理都知道他在哪里,但我还需要快速检查给定位置是否有代理。因此,我还保留了从地点到代理商的地图。我在确定此地图所属的位置时遇到问题:class World
,class Agent
(作为类属性)或其他地方。
在下文中,我将查找表agent_locations
放在class World
中。但现在代理商每次搬家时都必须致电world.update_agent_location
。这很烦人;如果我稍后决定跟踪代理商的其他事情,除了他们的位置之外怎么办?我是否需要在Agent
代码中将呼叫添加回世界对象?
class World:
def __init__(self, n_agents):
# ...
self.agents = []
self.agent_locations = {}
for id in range(n_agents):
x, y = self.find_location()
agent = Agent(self,x,y)
self.agents.append(agent)
self.agent_locations[x,y] = agent
def update_agent_location(self, agent, x, y):
del self.agent_locations[agent.x, agent.y]
self.agent_locations[x, y] = agent
def update(self): # next step in the simulation
for agent in self.agents:
agent.update() # next step for this agent
# ...
class Agent:
def __init__(self, world, x, y):
self.world = world
self.x, self.y = x, y
def move(self, x1, y1):
self.world.update_agent_location(self, x1, y1)
self.x, self.y = x1, y1
def update():
# find a good location that is not occupied and move there
for x, y in self.valid_locations():
if not self.location_is_good(x, y):
continue
if self.world.agent_locations[x, y]: # location occupied
continue
self.move(x, y)
我可以将agent_locations
放在class Agent
作为类属性。但这只有在我有一个World
对象时才有效。如果我后来决定实例化多个World
对象,那么查找表将需要特定于世界。
我相信有更好的解决方案......
编辑:我在代码中添加了几行来说明如何使用agent_locations
。请注意,它仅用于Agent
个对象内部,但我不知道是否会永远存在这种情况。
答案 0 :(得分:2)
好的,我想我可以提供我的答案,这可能更像是一种意见,而不是一个明确的“这样做”(我没有任何正式的编程培训)。
我认为您agent_locations
应该是每个World
个实例的成员。
我试着主要考虑界面。在我看来,世界级应该负责管理你的世界的资源,在这种情况下是空间。由于World
是空间的管理者,因此,如果空间可用(即未被占用),则代理应该询问他们的世界,而不是彼此。因此,我认为self.location_is_good
更恰当的呼叫是self.world.is_location_available(x, y)
[1]
这使得世界自然负责查找给定空间的可用性。此外,世界级可能还有其他变量来决定空间是否可用。如果那里有灌木丛怎么办?或者其他的东西。您可能已经在每个世界的(x, y)
坐标上都有某种表格。 “被占领”可以是这些物品的财产。
此外:您的世界已经知道每个代理的状态([(agent.x, agent.y) for agent in self.agents]
[2])。 agent_locations
dict本质上是这些属性的索引或缓存,因此属于World
。
关于将状态发送回World
......的痛苦,您不会通过让Agent
代替它来解决这个问题。但是update_agent_location(self, agent, x, y)
完全是多余的,因为x == agent.x; y == agent.y
(如果你反转你调用它的行)。您可以在World update_agent_state(self, agent)
中使用一种方法,World可以使用它来更新其索引。您甚至可以提交一个额外的参数来描述状态更改的类型(如果您不想更新所有属性eveytime)。
class World(object):
# ...
def update_agent_state(self, agent, state_change=None):
# Update properties based on what changed, or
# drop state_change param and update everything everytime
if state_change == Agent.LOCATION_CHANGE:
self.agent_locations[agent.x, agent.y] = agent
elif state_change == Agent.WHATEVER:
pass
class Agent(object):
LOCATION_CHANGE = 1
def update(self):
for x, y in self.valid_locations():
if not self.can_move_to(x, y)
continue
self.move(x, y)
def can_move_to(self, x, y):
"""Determines if x, y is a location where we can move."""
if not self.world.is_location_available(x, y):
return False
if not self.has_money_to_travel_to(x, y):
return False
return True
def move(self, x, y):
"""Moves to x, y and notifies world of state change."""
self.x = x
self.y = y
self.world.update_agent_state(self, Agent.LOCATION_CHANGE)
类似的东西(阅读我的脚注)。
[1]当然,除非空间是自由的,否则位置的“善”取决于其他变量。例如。如果您只应移动到(x,y),如果1)该位置可用且2)代理商有1000美元来支付票证,那么您应该有一个Agent.can_move_to(x, y)
反过来调用世界的方法,并检查它的钱包。
[2]我假设你的self.agents = {}
是拼写错误,因为你不能在{d}上append
。你的意思是一个列表([]
)对吧?
答案 1 :(得分:1)
有助于OOP根据是而拥有来讨论对象。 World
的列表为Agents
,列表为Locations
。 Location
有一个 Agent
。 Agent
有一个 Location
和一个World
。
class Agent:
def __init__(self, world):
self.location = None
self.world = world
def move(self, new_location):
if self.location is not None:
self.location.agent = None
new_location.agent = self
self.location = new_location
def update(self):
for new_location in self.world.locations:
if self.location_is_good(new_location):
self.move(new_location)
def location_is_good(self, location):
if location.agent is not None:
return False
class Location:
def __init__(self, x, y):
self.x = x
self.y = y
self.agent = None
进行向Location
添加新属性的心理练习,例如地形,并且很容易看到这种封装的好处。同样,向Agent
添加新内容(例如武器)只需要类似于move()
的武器特定功能。请注意,World
根本不需要参与move()
。此移动严格在Agent
和Location
。
答案 2 :(得分:0)
locn = self.where_to_move()
if locn.agent is None:
self.move(locn)
elif locn.agent is self:
raise ConfusedAgentError()
else:
self.execute_plan_B()