13

我已经在 Python 中实现了一种用于解决游戏“扫雷”的算法。该程序的工作原理如下:

假设求解器单击了一个名为“a”的正方形。举例来说,让这样显示的数字等于 2。正方形的尚未点击的邻居(再次作为示例)命名为“b”和“c”。然后程序将正方形与表达式 [2, {'b', 'c'}] 相关联,并从所有其他表达式中删除 'a'。通过在两种情况下对这些表达式进行成对简化来推断哪些正方形是地雷,哪些不是地雷。

  • 如果一个表达式中的平方是另一个表达式的平方的子集:

    [2, {'a', 'b', 'c'}], [1, {'a', 'b'}] -> [1, {'c'}], [1, {'a', 'b'}]
    
  • 如果一个表达式中的所有方格都被确定为地雷:

    [2, {'a', 'b'}], [1, {'b', 'c'}] -> [2, {'a', 'b'}], [0, {'c'}]
    

然后,对于某个表达式X,如果X[0] == 0,我们可以自由点击所有在 中命名的方格X[1],如果X[0] == len(X[1]),那么我们可以标记它们。

然而,我正在努力确定要简化表达式对。我目前的做法是维护一堆方格;每当单击正方形或成功简化其表达式时,都会将其添加到堆栈中(如果尚未存在)。当从堆栈中弹出一个正方形时,会尝试在其表达式 ( X) 和任何其他表达式之间进行简化,Y例如X[1] & Y[1] != set(). 当堆栈耗尽时,算法终止。然而,目前,虽然这工作得很好,但它不能正确解决所有明确的配置,并且如果我用队列替换堆栈或使用某种算法来确定要弹出哪个方块,它在给定板上的性能会发生显着变化!

对于我的方法的任何先例或潜在探索途径,我将非常感激。

4

2 回答 2

6

几年前我写了一个扫雷求解器,但可惜我似乎从那以后丢失了代码。我记得的是,这是一种蛮力方法,它编译了一组潜在的地雷,而不是像你正在做的那样把组合打包。

我相信你正在使用的算法更有能力。如果它完全充满或没有地雷,或者它是另一个条件的子集,您的方法可以“解决”一个条件。但是,有一些扣除是无法处理的。例如,考虑这个小的 7x2 板,其中a通过h瓷砖是未知的:

a 2 1 2 1 2 i
b c d e f g h 

您的条件将是:

[2, {a, b, c, d}],
[1, {c, d, e}],
[2, {d, e, f}],
[1, {e, f, g}],
[2, {f, g, h, i}]

如果我理解正确,您的算法无法对此做出任何推论。但是,如果您是一位经验丰富的扫雷玩家,您会发现1 2 1中心的图案只有一个解决方案,地雷低于1s:

a 2 1 2 1 2 i
b 2 * 2 * 2 h

仍然有一些未知数,在 or 下有一个地雷,在orab还有另一个,但如果这是一个更大的谜题的一部分,您以后可能会弄清楚(或者您可能不得不猜测)。hi

我相信我的一套地雷方法是这样工作的:

对于已扩展的每个图块,收集一组其所有未扩展的邻居(“区域”),以及包含该区域中可能出现的所有地雷组的列表。因此,例如,上面示例中的 5 个已知图块将生成(从左到右):

 ({a, b, c, d}, [{a, b}, {a, c}, {a, d}, {b, c}, {b, d}, {c, d}])
 ({c, d, e}, [{c}, {d}, {e}])
 ({d, e, f}, [{d, e}, {d, f}, {e, f}])
 ({e, f, g}, [{e}, {f}, {g}])
 ({f, g, h, i}, [{f, g}, {f, h}, {f, i}, {g, h}, {g, i}, {h, i}])

无论如何,要结合两个条件,我首先通过与区域集相交来检查它们是否重叠。如果没有重叠,则不能有效地组合条件。

但是,如果存在重叠,则新条件将跨越其区域的联合。至于地雷的集合,我会做外部集合的笛卡尔积以获得内部集合对,然后检查是否存在矛盾。如果在这些区域的交叉点内,这两组没有完全相同的地雷,就会产生矛盾。如果没有矛盾,一个新的组合集合将由矿山位置的联合组成。以下是上面前两行的组合方式:

 Intersection of areas: {a, b, c, d} & {c, d, e} = {c, d}
 New combined area: {a, b, c, d} | {c, d, e} = {a, b, c, d, e}
 Cartesian product of mine sets (with X marking contradictions):
    |   {a, b}  {a, c}  {a, d}  {b, c}  {b, d}  {c, d}
 ---+-------------------------------------------------
 {c}|     X     {a, c}    X     {b, c}    X       X
 {d}|     X       X     {a, d}    X     {b, d}    X
 {e}| {a, b, e}   X       X       X       X       X

 New condition: ({a, b, c, d, e}, [{a, b, e}, {a, c}, {b, c}, {a, d}, {b, d}])

您可以通过简单地计算它属于多少组(相对于总共有多少组)来计算条件区域内的任何图块成为地雷的几率。因此,鉴于上述综合条件,您可以a计算出 3/5 的时间是地雷,而e只有 1/5 的时间。当程序需要在没有任何保证安全的图块时猜测要扩展的位置时,此信息很重要。我想我还做了一些复杂的组合来说明使用的地雷数量(因此上面的 {a, b, e} 案例的权重与其他案例略有不同,因为它使用三个地雷而不是两个),但恐怕我不记得细节了。

扫雷是一款非常具有挑战性的游戏。我相信我的程序能够在大约 50-60% 的时间内解决相当于“困难”难度的棋盘,大部分损失发生在开始时(当您必须猜测几乎没有信息可以工作时)或就在结束(当经常有一些无法解决的领域需要猜测时)。它通常非常快,尽管偶尔会出现一种瓷砖图案,导致它在下一步行动之前停滞 10 或 15 秒。(Minesweeper 是 NP-complete 的,所以有些输入不能快速求解也就不足为奇了!)

于 2012-10-29T07:48:38.567 回答
0

这就是我想到的,我无法完全想象你的方法到底是什么。
我希望以图形形式呈现我的内容将有助于节省您的精力。

图像按“阅读顺序”进行。

它似乎与我在发布此内容后所做的工作相吻合,将赋予未知瓷砖的值添加到它从中获得其临时值的已知瓷砖的数量可能会进一步增加正确建模风险的可能性。
(使用这个,临时值 16(或第一种方法为 8)很重要,因为它是一个矿可以自己实现的数字)


没有早点看到这个,我觉得有点盲目。

在我能找到的所有情况下,任何具有标准化为 100% 的值的东西都是我的。

于 2012-10-29T04:04:39.470 回答