在2D阵列中使用N个图块生成实体形状

时间:2019-06-08 02:32:18

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

我正在制作一个小行星生成器,该生成器将创建bool s的2D数组。 生成器采用int参数size,该参数应确定2D数组中将有多少True个像元。

如何保证输出数组中没有孔并且True的单元格数量正确?

我看到了问题Randomly Generating Clusters in a 2d Array,但是我想不出一种将其应用于用例的方法,因为我需要知道必须生成的切片数量。

在下面的代码中,我随机放置了图块,然后使用细胞自动机进行平滑处理并确保没有孔,但是问题是要保留正确数量的True个单元,尤其是因为取出随机的{{ 1}}大小正确的单元可能会产生孔。

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 会产生整个范围的不同剩余质量,例如,使print处于“债务”状态或多于-14。如果该功能正常运行,我希望输出为42

例如,这样的输出...

0

...很坚固,但是设置的磁贴太多。

2 个答案:

答案 0 :(得分:2)

对于您的问题,没有一个唯一的肯定答案,特别是因为基本任务(“生成2D小行星形状”)的规格不足且从根本上讲是主观的。当然,原则上您总是可以生成 N 瓷砖实体形状,例如通过从左上角开始并从左到右并自上而下添加磁贴,直到其中有 N 个,但所得形状可能不是一个非常逼真的或“漂亮”的小行星。

因此,除了详细描述单个算法之外,我只建议一些可行的方法,让您选择最合适的方法:

  • 从单个中心磁贴开始,并随机添加与现有磁贴相邻的新磁贴。在添加每个磁贴之前,请检查添加是否没有在小行星内部留下任何孔;如果可以的话,请选择另一个图块。 (连接检查可能是该算法最昂贵的部分,尽管有多种方法可以对其进行优化。特别是,您可以首先检查新图块的现有直接邻居;如果它们都是连续的,则新的图块无法桥接边缘的两个独立部分。)

  • 与上述相同,但是将连接检查延迟到最后。如果发现任何孔,请将小行星边缘的瓷砖移到内部以填充它们。

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

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

答案 1 :(得分:0)

自上而下的技术是:

  • 从在位图中随机绘制的填充椭圆开始,一直玩到获得理想结果为止,单元格现在是像素,例如:Kubernetes deployer properties
  • 将位图栅格化到单元格中,如果像素为空则转换为0,如果填充为空则转换为1
  • 使用邻居检测技术填充孔