世界包含不同位置的代理,任何位置都只有一个代理。每个特工都知道他在哪里,但我还需要快速检查给定位置是否有特工。因此,我还维护了一张从位置到代理的 map 。我无法确定这张 map 属于哪里:class World
、class Agent
(作为类属性)或其他地方。
在下面,我将查找表 agent_locations
放在 class World
中。但是现在代理每次移动时都必须调用 world.update_agent_location
。这很烦人;如果我稍后决定跟踪关于代理的其他事情,除了他们的位置之外,我是否需要在整个 Agent
代码中添加对 world 对象的调用?
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
对象内部使用,但我不知道这种情况是否会永远如此。
好吧,我想我可以提供我的答案,这可能更像是一种意见,而不是明确的“这样做”(我没有接受过任何正式的编程培训)。
我认为您 agent_locations
应该是每个 World
实例的成员。
我尝试主要从界面的角度来思考。在我看来,世界级应该负责管理你的世界的资源,在这种情况下是空间。由于 World
是空间的管理者,Agent 应该询问他们的 world 空间是否可用(即未被占用),而不是互相询问。因此,我认为您的 self.location_is_good
调用更合适的是 self.world.is_location_available(x, y)
[1]
这使得世界很自然地负责查找给定空间的可用性。 World 类可能还有其他变量来决定空间是否可用。如果那里有灌木丛怎么办?或者其他的东西。您可能已经为每个世界的 (x, y)
坐标创建了某种表格。被“占用”可以是这些对象的属性。
此外:您的世界已经知道每个代理的状态(通过 [(agent.x, agent.y) for agent in self.agents]
[2])。 agent_locations
字典本质上是这些属性的索引或缓存,因此属于 World
。
关于将状态发送回 World
的痛苦……好吧,您不会通过让 Agent
来解决这个问题。但是执行 update_agent_location(self, agent, x, y)
是完全多余的,因为 x == agent.x; y == agent.y
(如果你反转你调用它的行)。您可以在 World 中简单地使用一种方法,update_agent_state(self, agent)
,World 可以使用它来更新其索引。您甚至可以提交一个额外的参数来描述状态更改的类型(如果您不想每次都更新所有属性)。
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] 当然,除非空间的“好”取决于其他变量,而不是空间是否空闲。例如。如果您只应在 1) 位置可用且 2) 代理商有 1000 美元支付机票时移动到 (x, y),那么您应该有一个 Agent.can_move_to(x, y)
依次调用 world 的方法,并检查其钱包。
[2] 我假设您的 self.agents = {}
是一个拼写错误,因为您不能在 dict 上append
。您是说列表 ([]
) 对吗?