改进我的扫雷解决算法

时间:2012-10-28 19:05:16

标签: python artificial-intelligence minesweeper

我在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()。当堆栈耗尽时,算法终止。然而,目前虽然这很有效,但它无法正确解决所有明确的配置,如果我用队列替换堆栈,或者使用某种算法确定要弹出哪个方块,它在给定板上的执行情况会有显着变化!

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

2 个答案:

答案 0 :(得分:6)

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

我相信你正在使用的算法更有能力。如果条件完全填满或没有地雷,或者它是另一个条件的子集,您的方法可以“解决”条件。但是,有一些扣除,这将无法处理。例如,考虑这个小型7x2电路板,ah磁贴未知:

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模式只有一个解决方案,其中的地雷低于1

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

还有一些未知数,我的ab以及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 is NP-complete,所以一些输入无法快速解决就不足为奇了!)

答案 1 :(得分:0)

这就是我想到的,我无法完全想象你的方法究竟是什么 我希望以图形形式呈现我将有助于为您节省这些努力。

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

这似乎符合我自发布以来所做的工作,即增加给未知磁贴的值,它获得它的临时值的已知磁贴的数量可以进一步增加正确建模风险的可能性。登记/> (使用这个,临时值为16(或第一种方法为8)是重要的,因为它是我自己可以实现的第一名)


我觉得因为没有早点看到这一点而感到有些失明

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