【问题标题】:Generating a solid shape with N tiles in a 2D array在二维数组中生成具有 N 个图块的实体形状
【发布时间】:2019-10-23 11:19:05
【问题描述】:

我正在制作一个小行星生成器,它可以创建一个bools 的二维数组。 生成器采用int 参数size,它应该确定二维数组中有多少True 单元格。

如何保证输出数组中没有空洞,并且单元格数量正确为True

我看到了Randomly Generating Clusters in a 2d Array 的问题,但我想不出办法将它应用到我的用例中,因为我需要知道必须生成的图块数量。

在下面的代码中,我随机放置瓦片,然后使用元胞自动机进行平滑并确保没有孔,但保持正确数量的True 单元是问题,特别是因为取出随机的True 单元满足正确的尺寸可能会产生孔。

def create_shape(size, seed):
    # init rng with seed
    rng = random.Random(seed)
    # initial grid values empty and full mass left
    # make the grid size by size so any shape could fit
    grid = [[False for x in range(size)] for y in range(size)]
    mass_remaining = size
    # guarantee the center is something
    center = size // 2
    grid[center][center] = True
    mass_remaining -= 1 # remember to reduce available mass
    # generate random values
    for x in range(size):
        for y in range(size):
            # skip the already filled in center
            if x == y == center:
                continue
            # assign random value
            value = bool(rng.randint(0, 1))
            grid[y][x] = value
            # remember to reduce mass
            if value: 
                mass_remaining -= 1
    # smoothen things out with cellular automata neighbor checking
    for x in range(size):
        for y in range(size):
            # skip the center
            if x == y == center:
                continue
            # get neighbors
            # set neighbors is the count of neighbors set to True
            set_neighbors = 0
            for i in range(-1, 2):
                for j in range(-1, 2):
                    # skip counting self
                    if i == j == 0:
                        continue
                    nx, ny = x + i, y + j
                    if 0 <= nx < size and 0 <= ny < size:
                        # only get in-range cells
                        if grid[ny][nx]:
                            set_neighbors += 1
            # more than 3 -> become True, less than 3 -> become False
            if set_neighbors > 3:
                grid[y][x] = True
                mass_remaining -= 1
            elif set_neighbors < 3:
                grid[y][x] = False
                mass_remaining += 1
            else:
                # otherwise leave it the same
                pass
    # find out how well the mass is staying "in-budget"
    print(mass_remaining)
    return grid

该函数经常prints 输出一系列不同的剩余质量数量,例如,在“债务”中具有-14 或具有额外的42。如果函数正常工作,我希望输出为0

比如这样的输出……

create_shape(8) ->

[ 0, 0, 0, 0, 0, 0,
  0, 1, 1, 0, 0, 0,
  0, 1, 1, 1, 0, 0,
  0, 1, 1, 1, 1, 0,
  0, 1, 1, 1, 1, 0 ]

... 是实心的,但有太多设置的图块。

【问题讨论】:

    标签: python multidimensional-array procedural-generation cellular-automata


    【解决方案1】:

    对于您的问题,没有一个明确的答案,尤其是在基本任务(“生成 2D 小行星形状”)未充分说明且从根本上讲是主观的情况下。当然,原则上你总是可以生成一个 N 瓦片实体形状,例如从左上角开始,从左到右、自上而下添加图块,直到拥有 N 个图块,但生成的形状可能不是非常逼真或“好看”的小行星。

    因此,我不会详细描述单个算法,而是建议一些应该可行的方法,并让您选择最适合您的方法:

    • 从单个中心图块开始,随机添加与现有图块相邻的新图块。在添加每个瓷砖之前,请检查添加它不会在小行星内部留下一个洞;如果可以,请选择另一个瓷砖。 (连接性检查可能是该算法中最昂贵的部分,尽管有多种优化方法。特别是,您可以从仅检查新图块的现有直接邻居开始;如果它们都是连续的,则新瓷砖无法桥接边缘的两个独立部分。)

    • 同上,但延迟连接检查直到结束。如果发现任何洞,请将瓷砖从小行星边缘移到内部以填充它们。

    • midpoint displacement 算法应用于圆。也就是说,使用该算法生成一个随机的半径数组(每端具有相同的半径),然后将这些半径用作从任意选择的中心点到小行星表面的距离,就好像你在绘制一个radar graph。这不会为您提供 N 个图块的确切区域,但您始终可以放大或缩小半径,直到获得所需的大小。生成的形状将始终为star-convex,因此没有孔。 (这可能对相当大的 N 最有效。这个方案的一个优点是它可以以一种相当直接和有效的方式推广到 3D 形状:只需从随机多面体开始并应用面的中点位移。)

    • 使用通常生成无孔小行星的任何算法。然后检查是否有漏洞,如果有,请重新启动。只要重启的概率足够低,这个rejection sampling的方法会相当高效。

    【讨论】:

      【解决方案2】:

      一种自上而下的技术是:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-04
        • 2013-02-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-30
        • 1970-01-01
        相关资源
        最近更新 更多