在二维平面上放置N个代理。

4
抱歉,如果我的英语不好(我是法国学生)。
我正在为学校项目工作,想在模拟场景中创建人群移动,包括一些墙壁、喷泉和路灯。我已经完成了几乎所有的工作:创建了AI,可以在2D平面上移动,我的地方已经建模,使用Reynolds' Boid规则(对齐,凝聚,分离)来模拟人类在人群运动中的互动。但我还需要编写一个函数来模拟当人们碰到墙或其他结构物时的物理效应。
但我现在正在初始化(创建)人群,而它并没有正常工作:人群由N个人(代理)组成,其中N的值介于1至5518之间(由于空间限制而设定的最大人数)。以下是代码:
self.agents = []
x = 50
y = 55
X = 0
while X < N:
    if x <= 100 and x >= 50 and y <= 165 and y >= 55:
        k = 0
        while k < 50 and X < N:
            for a in range(11):
                for b in range(13):
                    if (x, y) != ((70 + a),(104 + b)):
                        x += k
                        agent = UnAgent(x, y)
                        self.agents.append(agent)
                        X += 1
                        k += 1
        x = 50
        y += 1

我认为出现了无限循环,但是我无法解决它。为了更好地理解我的代码,这里有一张我在画图中的计划图片,然后第二张图片是我的程序,其中所有代理都在一个独特的地块(x,y)上生成在场所的中心(这不是我想要的,我希望每个人都在独特的地块上,同时通过X坐标移动,然后在Y坐标上加1,然后再通过X坐标移动等等,而且人们不能出现在红色的区域内所以喷泉)。

我的计划图的第一张图片及说明

没有生成功能的实际程序的第二张图片

编辑:

嗨@PatrickArtner,感谢您关注我的问题并帮助我!您的回答非常有用,所以我尝试调整您的代码(与我的代码相比真的易懂!),这就是我拥有的内容:

def addMonumentCentral():
    '''Bloque la place de (70,104) à (80,116) avec des "briques" '''
    L=[]
    for a in range(70,81):
        for b in range(104,117):
            L.append((a,b)) # List of every unique tuple occupied by water
class Foule:
def __init__(self, count, largeur = 150, hauteur = 220):
    self.largeur = largeur
    self.hauteur = hauteur
    self.agents = []
    numAg = 0
    MonumentCentral = addMonumentCentral()
    for y in range(55,166):permise
        for x in range(55,101):
            if (x,y) not in MonumentCentral:
                agent = UnAgent(x, y)
                agent.largeur = largeur
                agent.hauteur = hauteur
                self.agents.append(agent)
                numAg += 1ajoutes
            if numAg == count:
                break
        if numAg == count:
            break

我不太熟悉字典,所以我将您的第一个函数改为返回每个水块的列表,其结果类似于:[(...,...),(...,...),...,(...,...)],其中每对括号代表二维平面上的水块。
然后,我在我的Foule类中应用了您的第二个函数,但唯一不起作用的是这行代码:if (x,y) not in MonumentCentral:。在Python中,好像我不能测试包含元组的列表:我是Python的初学者,看起来似乎不起作用,但我不知道如何做与先前相同的事情。
当我执行代码时,我会得到这个错误行:TypeError: argument of type 'NoneType' is not iterable。您知道如何用一个类似的方法替换测试元组与元组列表的语句吗?
您真诚的, Axel JOLY
编辑2:
我的代码现在可以工作了,这是结果:
class Foule:
def __init__(self, count, largeur = 150, hauteur = 220):
    self.largeur = largeur
    self.hauteur = hauteur
    self.agents = []
    numAg = 0 # Nombre d'agents ajoutes
    MonumentCentral = []
    for a in range(70,81):
        for b in range(104,117):
            MonumentCentral.append((a,b))
    for y in range(55,166): # On parcourt selon les y la zone de spawn permise
        for x in range(55,101): # On parcourt selon les x la zone de spawn permise
            if (x,y) not in MonumentCentral: # On check si c'est bloqué ou non
                agent = UnAgent(x, y) # Position de depart
                agent.largeur = largeur
                agent.hauteur = hauteur
                self.agents.append(agent)
                numAg += 1 # Iteration pour compter le nombre d'agents ajoutes
            if numAg == count: # On casse si on atteint le nombre d'agents voulu
                break
        if numAg == count: # On casse si on atteint le nombre d'agents voulu
            break

很抱歉,这个内容大部分是用法语写的,但现在它已经完美地运作了,从1个代理到5518个代理都没有问题!


1
xykXN是什么?这些神奇的数字5055100501655550111370104又是什么意思? - Reblochon Masque
x和y是平面坐标变量。N是人数(代理数量)的数量。如果X = N,则每个代理都放置在平面上。K通过X轴移动以在每个坐标上放置一个代理:51个代理被放置在(50,55)和(100,55)之间。如果k = 50,则放置了51个人,y + = 1以在X轴上放置51个更多代理。当放置N个代理(X = N)时,不再放置代理。 - Axel JOLY
1个回答

2
我很难理解您使用的while循环,所以我将它们重写为更简单的for..in range(..)循环,以遍历所需的x/y范围。如果要检查代理是否可以放置,则可以使用一组坐标(称为blocked),我选择使用dict来存储阻止块的信息(主要用于显示目的)。在放置任何代理之前,您需要阻止所有不可用的图块(将它们放入集合中)。然后开始放置代理,通过检查图块是否已被阻止,否则就放置并计数。重复此过程直到放置所有代理。
def addFountain(place):
   """Blocks the places (70,104) to (80,116) with water tiles"""
    for a in range(70,81):
        for b in range(104,117):
            place[(a,b)] = "~"  # water    


occupied = dict()               # dict as "playground" - it remembers which places are 
                                # already occupied. You can simply use a set of coords.

addFountain(occupied)           # add all water tiles to the dict (block the spaces)

maxNum = 74                     # place 74 agents
numAg = 0                       # placed 0 agents so far

for y in range(55,166):         # go over all tiles vertically
    for x in range(55,101):         # go over all tiles horizontally
        if (x,y) not in occupied:    # check if blocked, if not 
            occupied[(x,y)] = "A"                    # add UnAgent(x, y), I am adding "A"
            numAg += 1                               # count added agent
        if numAg == maxNum:                          # break if max reached
            break
    if numAg == maxNum:                       # break outer if max reached
        break

# visualizing the dictionary:
print("-" * (101-55+2))       # print plaza

for y in range(166,54,-1):     # print plaza (reversed so 55 is at bottom)
    print("|", end="")
    for x in range(55,101):
        print(occupied.get( (x,y), " "), end="") # print if in dict, else print space
    print("|")

print("-" * (101-55+2))

输出:

------------------------------------------------
|                                              |
|                                              |
      ... removed lots of empty lines ...
|                                              |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|               ~~~~~~~~~~~                    |
|                                              |
      ... removed lots of empty lines ...
|                                              |
|AAAAAAAAAAAAAAAAAAAAAAAAAAAA                  |
|AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|
------------------------------------------------

您可以像这样从字典中获取代理列表:

agents = [occupied[coord] for coord in occupied if occupied[coord] == "A"] (isinstance of your agent class)

你可能需要根据你的类结构来调整这段代码。


如果地图大部分为空,只有少量障碍物,您可以使用稀疏矩阵来节省内存并提高性能。 - user2261062
@SembeiNorimaki 我的字典也大多为空 - 它只有在需要时才为 A~ 赋值 - 如果键不在字典中,空格将被填充 - 这仅用于演示目的 - OP 仅需要一个集合来记住放置位置以检查新代理是否可以到达那里...如果你对代理进行了长度编码,可能会节省一些内存,但我猜它们将会移动,所以这一点在这里无关紧要... - Patrick Artner
感谢 @PatrickArtner,多亏了你的帮助,我的代码终于能够正常运行了! - Axel JOLY

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接