【问题标题】:algorithm to check a connect four field检查连接四个字段的算法
【发布时间】:2011-08-11 21:35:09
【问题描述】:

我想知道在连接四字段中检查获胜者的最佳方法是什么。

我对你们的想法很感兴趣,是否有一些“众所周知”的算法可以解决这类问题?

解决方案:

我用 Python 实现了 Ardavan 的哈希表解决方案。

我让算法在每个字段上运行一次。在我的 Intel(R) Core(TM)2 Duo CPU T9600 @ 2.80GHz 上,我实现的最佳检查时间为 0.047 毫秒,最差为 0.154 毫秒,平均为 0.114 毫秒。这对我的需求来说已经足够快了,而且算法对我来说似乎很简洁。

【问题讨论】:

  • 您是要在多次播放后检查,还是逐次检查?
  • 我对你的问题有点不确定,但我认为既然它是连接四个,你必须在每转一圈后检查,不是吗?也许不是在前 6 轮,但至少在第 7 轮。
  • 是的,但是在玩棋子时检查比在游戏结束后检查整个棋盘更受限制。
  • 看了第一个答案,我明白你的意思了。我想更好的方法是轮流进行,而不是一遍又一遍地整个领域。
  • 在这种情况下,算法很大程度上取决于您使用的语言。如果您的语言支持它,您将使用:模式匹配、列表推导、旋转、指针等。

标签: algorithm


【解决方案1】:

来自 John Tromp 的 Fhourstones Benchmark 的源代码使用了一种引人入胜的算法来测试四人连线游戏以获得胜利。该算法使用以下bitboard 表示游戏:

.  .  .  .  .  .  .  TOP
5 12 19 26 33 40 47
4 11 18 25 32 39 46
3 10 17 24 31 38 45
2  9 16 23 30 37 44
1  8 15 22 29 36 43
0  7 14 21 28 35 42  BOTTOM

红色玩家有一个位板,黄色玩家有一个。 0 代表一个空单元格,1 代表一个填充单元格。位板存储在一个无符号的 64 位整数变量中。第 6、13、20、27、34、41、>=48 位必须是 0

算法是:

// return whether 'board' includes a win
bool haswon(unsigned __int64 board)
{
    unsigned __int64 y = board & (board >> 6);
    if (y & (y >> 2 * 6))     // check \ diagonal
        return true;
    y = board & (board >> 7);
    if (y & (y >> 2 * 7))     // check horizontal
        return true;
    y = board & (board >> 8);
    if (y & (y >> 2 * 8))     // check / diagonal
        return true;
    y = board & (board >> 1);
    if (y & (y >> 2))         // check vertical
        return true;
    return false;
}

您必须调用执行最后一步的玩家的位板的函数。 我尝试在answer to the question "How to determine game end, in tic-tac-toe?" 中解释算法。

【讨论】:

  • 该算法很棒,但由于我将使用 Python,而且我现在不想使用 Cython 或类似的东西,所以这不是我要走的路。无论如何 +1,它非常有效!
  • 我还没有编写 Python 代码,但是该算法应该适用于任何具有位操作能力的语言。我做了一个谷歌搜索:运营商>>, *, &same meaning in Python。当然你没有内置的 64 位整数数据类型,但是具有无限精度的类型 long 应该可以工作。
  • 没错,我在编写 Python 时从不使用/不需要位操作。但是该算法在 Python 中的性能很可能远低于在 C 或汇编中的性能。目前,我倾向于使用哈希表解决方案,因为它对我来说更 Pythonic 和清晰。
  • 这……简直太棒了! :D
  • @ChristianAmmer 你能确定一行中有多少个“连接”吗?
【解决方案2】:

每个单元格只能归属于最多 12 个获胜组合。 (4 个水平,4 个垂直和 4 个对角线)。每个组合将有 4 个单元格,包括正在考虑的单元格。对于靠近两侧的细胞,这些数字会低得多。因此,预编译这些组合并存储相关单元格的哈希值是有意义的,这可以使单个游戏成为赢家。这样,在每个单元格成为玩家之后,您只需拉出相关的组合/单元格来检查它是否是赢家。

【讨论】:

  • 如果我算对了,总共有 69 个中奖组合。每行有 4 种可能的组合,有 6 行 => 24。每列有 3 种可能的组合,有 7 列 => 21。对于每个对角线和对角线,你有 12 种组合 => 24。结果总共 69 个。不确定将所有这些存储在哈希表中是否比手动检查更高效?我猜哈希表更快,但我想我必须尝试一下。
  • 实现了你的算法,它真的符合我的需要。
【解决方案3】:

这和这个问题有关:How to find the winner of a tic-tac-toe game of any size?

转折是 7x6 棋盘,连续 4 个获胜,而不是 NxN 棋盘,连续 N 个获胜。但是将解决方案调整为 NxN tic tac toe 连接 4 是微不足道的。

编辑:实际上,将另一种解决方案适应这个解决方案并不是一件容易的事。但是你可以通过一些额外的工作到达那里。

为每个玩家存储每行、列、对角线和反对角线的计数,可能连续有 4 个棋子。当任一玩家的计数达到 4 或更多时,检查该行/列/对角线/对角线是否连续有四个棋子。如果是,则该玩家获胜!

【讨论】:

  • 为了清楚起见,我理解正确:我为每一行、每一列和对角线创建了两个计数器(player1 和 player2)。如果一个玩家的计数器在行/列/对角线上达到 4,他就赢了。这是正确的还是可以更好地实现解决方案?
  • 我看不出这个答案与这个问题有什么关系。
  • @yi_H,这几乎是相关的,但你是对的;我应该添加额外的检查以查看四个是否实际上是连续的。
  • 检查四个连续,最好用我的字符串方法实现?还是有更好的?
  • @naeg,当您可以计算匹配的相邻字段时,为什么还要使用字符串?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-22
  • 2013-12-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多