如何生成正方形的多米诺骨牌?

时间:2019-04-25 09:13:24

标签: generated tiling

简短说明:

我正在尝试生成具有多米诺骨牌或换句话说具有2x1和1x2瓦片的正方形拼贴。

有时我的算法会以某种方式放置垂直图块,从而无法填充最后一行。

我的当前方法是用0初始化一个网格(例如8x8网格)。 我在网格中用1表示水平图块的左半部分,在网格中用2表示右半部分。

相应地,垂直图块的上半部分为3,下半部分为4。

然后我从左到右浏览网格的每一行,在其中放置0的图块是我所在的位置:

  • 无论何时我在网格的右边或右边的空间不为0时,我都会放置一个垂直图块(3)。
  • 当我在底部边缘时,我(只能)放水平瓷砖。
  • 当上述方法均未设置值时,我会放置一个随机值(1或3)。

每当我放置一个图块(1或3)时,我也会相应地将相应的一半放置到网格的相邻空间中。假设我在(i,j)处放置1,然后在(i,j + 1)处放置2。

StoneMatrix = int[8][8];

for (int i = 0; i < StoneMatrix.length; i++) {
    for (int j = 0; j < StoneMatrix.length; j++) {
        if (StoneMatrix[i][j] != 0){
            //field already set as a tile
            continue;
        }

        if (i == StoneMatrix.length - 1) {
            //bottom row
            StoneMatrix[i][j] = 1;
            StoneMatrix[i][j + 1] = 2;
            continue;
        }

        if (j == StoneMatrix.length - 1) {
            //right edge
            StoneMatrix[i][j] = 3;
            StoneMatrix[i + 1][j] = 4;
            continue;
        }

        if (StoneMatrix[i][j + 1] != 0) {
            //field to the right taken.
            StoneMatrix[i][j] = 3;
            StoneMatrix[i + 1][j] = 4;
            continue;
        }

        StoneMatrix[i][j] = putOneOrThreeRandomly();
        putCorrespondingAdjacentTile();
    }
}

我觉得必须有一种简单的方法来生成这种平铺,但是我还找不到。 我正在寻找的要么是描述了这种生成算法的某个来源,要么是解决了我的错误的简单解决方案。

2 个答案:

答案 0 :(得分:1)

最佳 Domino 平铺

使用 n 多米诺骨牌通过 m 棋盘创建任意 2x1 的随机最大平铺。当 n*m 为偶数时,平铺将是完美的。

理论

考虑棋盘的白色和黑色方块。多米诺骨牌必须同时覆盖白色和黑色方块。因此,如果存在一些完美的拼贴,那么解决方案可以转化为如下图:每个棋格成为一个顶点,如果多米诺牌覆盖了两个相邻的拼贴,则这两个顶点是连接的。这将导致二部图(所有边都有一个白色和一个黑色顶点)和(最大)匹配图。

因此,给定任何大小的网格(或任何形状),如果我们能够解决二部图中的最大基数匹配问题,我们就可以将解决方案转换为多米诺平铺。

实施(概念证明)

为了解决上述图形问题,将其转换为最大流问题,并与 Ford Fulkerson 一起解决。将源节点连接到所有白色瓷砖,将汇节点连接到所有黑色瓷砖。只有当它们是国际象棋网格上的邻居时,白色瓷砖才指向黑色瓷砖。用容量为 1 的所有边求解。节点之间利用的边表示将在那里放置多米诺骨牌。

示例

考虑一个 2 行深、4 列宽的棋盘。白色方块是{0, 1, 2, 3},黑色方块是{4, 5, 6, 7}

+---+---+---+---+
| 0 | 4 | 1 | 5 |
+---+---+---+---+
| 6 | 2 | 7 | 3 |
+---+---+---+---+

现在假设我们有两个额外的节点,8 源节点和 9 接收器节点。然后找到最大流量的图表如下所示。请注意,所有边的容量为 1。

0: 4, 6
1: 4, 5, 7
2: 4, 6, 7
3: 5, 7
4: 9
5: 9
6: 9
7: 9
8: 0, 1, 2, 3

在运行 Ford-fulkerson 之后(使用随机 DFS 获得有趣的解决方案——如果您每次都想要无聊的逐行解决方案,请使用 BFS),我们可能会发现使用了以下边缘。请注意,涉及源/汇节点的边已被省略,因为它们对重建平铺没有用。

0-4
2-6
1-7
3-5

最后,这对应于下面的平铺

+-----+---+---+
| 0 4 | 1 | 5 |
+-----+   |   |
| 6 2 | 7 | 3 |
+-----+---+---+

我还在此处用 Java 创建了一个概念证明:https://github.com/forsythe/domino_tiling。如果你想看到它的实际效果,这里有一个 16x16 的输出:

sample of 16x16 output generated by below method

答案 1 :(得分:0)

每当我进入无法再正确填充网格的状态时,我通过将布尔值设置为true来“解决”该问题。

然后在生成方法的末尾,如果布尔值为false,则网格有效,或者如果布尔值为true,则重新启动该方法。我认为基本上是一个肮脏的“尝试和错误”。

那不是我想要的解决方案,但是它可行。所以我将这个问题保留。