【问题标题】:Divide grid (2D array) into random shaped parts?将网格(二维阵列)划分为随机形状的部分?
【发布时间】:2010-08-03 15:17:44
【问题描述】:

问题
我想将网格(二维数组)划分为随机形状的部分(想想earth's tectonic plates)。

标准是:

  • 用户输入网格大小(程序应该缩放,因为这可能非常大)。
  • 用户输入网格划分系数(多少部分)。
  • 网格是一个矩形六角网格,顶部和底部都加盖,左右环绕。
  • 部件没有碎片。
  • 其他部件中没有部件。
  • 没有微小或超大的部件。
  • 形状随机的零件,不是完美的圆形,也不是串成的蛇形。

我的解决方案:

  • 创建一个可以访问/操作相邻单元格的方法。
  • 随机确定每个部分的大小(所有部分的总和等于整个二维数组的大小)。
  • 用最后一部分的 id 号填充整个二维数组。
  • 对于除最后一个以外的每个部分:
  • 在二维数组的随机单元格中播种当前零件 ID 号。
  • 遍历整个数组并存储每个单元格的地址,这些单元格与已使用当前部件 ID 号播种的任何单元格相邻。
  • 提取其中一个存储的地址并用当前的车牌 ID 号填充该单元格(因此该部分开始形成)。
  • 重复直到达到零件尺寸。

请注意,为了避免零件内部带有长“臂”或大孔,我创建了两个存储阵列:一个用于相邻的单元格 到只有一个具有当前零件 ID 号的单元格,另一个用于与多个相邻的单元格,然后我在前者之前耗尽后者。

运行我的解决方案会得到以下结果:
网格大小:200
宽度:20
身高:10
零件:7

66633333111114444466
00033331111114444466
00003331111114444466
00003331111144444660
00000333111164444660
00000336111664422600
00000336615522222200
00006655555522222200
00006655555552222220
00066655555552222220

部件号:0
零件尺寸:47

部件号:1
零件尺寸:30

部件号:2
零件尺寸:26

部件号:3
零件尺寸:22

部件号:4
零件尺寸:26

部件号:5
零件尺寸:22

部件号:6
零件尺寸:27

我的解决方案存在问题:

  • 最后一部分总是零散的——在上面的例子中,有三个不同的六组。
  • 当零件在死胡同中形成并且没有空间增长到完整尺寸时,该算法将停止(该算法不允许在其他零件上形成零件,除非它是最后一个零件,已放下在开始时覆盖整个二维数组)。
  • 如果我在形成 2d 数组之前没有指定零件尺寸,而只是指定零件数量并动态随机生成零件尺寸,这就留下了形成微小零件的可能性,即还不如根本不存在,尤其是当二维数组非常大时。我当前的零件尺寸方法将零件尺寸限制在二维数组总尺寸的 10% 到 40% 之间。如果有一些超级优雅的方法可以做到这一点,我可以不指定零件尺寸 - 用户将拥有的唯一控制是二维数组大小和零件数量。

其他想法:

  • 将零件形成完美对齐的正方形,然后在 2D 阵列上运行并随机让每个零件侵占其他零件,将它们扭曲成随机形状。
  • 在网格上绘制蛇形线并填充创建的空间,可能使用如下数学运算:http://mathworld.wolfram.com/PlaneDivisionbyLines.html

结论:
所以问题来了:我是一个初学者程序员,不确定我是否以正确的方式解决了这个问题。我可以创建一些更多的“修补”方法,将零散的部分转移到一起,并允许成型部分在卡在死胡同的情况下“跳出”,但感觉很混乱。

您将如何解决这个问题?有没有一些我可以用来简化事情的性感数学?

谢谢

【问题讨论】:

  • 为什么不从axb大小为1的部分开始,随机加入相邻的部分呢?是否有一些标准零件必须满足?
  • 我没有想到这一点,最近几天一直在试验你的方法。它自然避免了零件的碎片化,但不会像我的那样在其他零件内部形成零件。你的方法最简单的形式总是会产生一个超大的部分,其余的会很小。按摩以获得你想要的东西似乎并不比我的解决方案更容易。我在我的问题帖子中添加了对我的标准的更清晰的解释。

标签: algorithm language-agnostic grid computational-geometry multidimensional-array


【解决方案1】:

几个月前我为一个游戏做了类似的事情,虽然它是一个矩形网格而不是一个六角网格。尽管如此,理论是相同的,它提出了大小大致相同的漂亮连续区域——有些更大,有些更小,但都不是太小或太大。 YMMV。

  1. 创建一个指向网格中所有空间的指针数组。随机排列数组。
  2. 分配其中的前 N ​​个 ID - 1、2、3 等。
  3. 直到数组指向没有没有ID的空格,
  4. 遍历数组寻找没有 ID 的空格
  5. 如果该空间在网格中有具有 ID 的邻居,则分配该空间 来自其邻居 ID 的加权随机选择的 ID。
  6. 如果没有具有 ID 的邻居,请跳到下一个。
  7. 一旦没有非空白区域,您的地图就会有足够的斑点区域。

【讨论】:

  • 换句话说: 1. 用每个零件 ID 号的单个实例填充二维数组,随机分布, 2. 遍历二维数组并根据内容在空单元格中插入零件 ID 号他们周围的细胞。与我原来的解决方案相比,这种方法显着提高了速度。它通过在一次迭代中形成更多部分并同时形成它们来最大限度地减少迭代数组的次数。它也不会在形成零件之前形成零件尺寸 - 事后看来,这可能是一种限制性的不必要的方法。也没有孔或碎片 Thx
  • "迭代二维数组",小心,这可能会导致你迭代方向的线条。这就是布伦达先洗牌的原因。第6步让算法重复,绝对不是一次迭代。
【解决方案2】:

这就是我要做的:使用 Voronoi 算法。首先放置一些随机点,然后让 Voronoi 算法生成零件。要了解它的外观,请咨询:this applet

【讨论】:

  • 我对此进行了非常简短的了解。我的第一个想法是,它会产生形状过于统一的零件,不适合我的目的——我的一些零件我不介意偶尔被钩住。我很想知道是否会有任何显着的速度改进。只是出于兴趣,我尝试在一个单独的程序中运行这个数学,这足以让我着迷。我学到了一个新术语:计算几何。谢谢你的建议。
  • 经过进一步调查,事实证明这种方法在很长一段时间内是最快的——它只需要一次网格迭代。它也不需要复杂的数学知识来暗示。在伪代码中: 1. 用每个部件 id 号的单个实例(种子)填充 2D 数组,随机分布,2. 对于每个单元格,找到最接近的种子部件 id 号(使用距离方法)并将其插入当前单元格。结果是一个 Voronoi 图。然而,它看起来确实过于线性 - 它可能会以某种方式扭曲,但仍然比其他解决方案更快。
【解决方案3】:

正如 Rekin 所建议的,Voronoi 图加上一些随机扰动通常会做得很好,并且在像你这样的离散空间上,相对容易实现。

我只是想提供一些关于如何进行随机扰动的想法。如果您以最终解决方案执行此操作,那么它要么需要很长时间,要么非常少。您可以尝试进行多分辨率扰动。因此,从一个相当小的网格开始,随机播种,计算 Voronoi 图。然后随机扰动边界 - 例如,对于具有不同区域的每一对相邻单元格,以一种或另一种方式推动该区域。您可能需要运行后期处理以确保没有小岛......一个简单的填充就可以了。

然后创建一个两倍大小的网格(在每个方向上),然后复制您的区域。您可能可以使用最近的邻居。然后再次扰动边界,并重复直到达到所需的分辨率。

【讨论】:

    猜你喜欢
    • 2015-09-02
    • 2018-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多