algorithm - 所有可能的井字游戏获胜组合

标签 algorithm combinations graph-theory tic-tac-toe

我参加了一次面试,被问到一个看似简单的算法问题:“编写一个算法,返回井字游戏所有可能的获胜组合。”我仍然想不出一种有效的方法来处理这个问题。是否有一种标准算法或通用算法应该应用于我不知道的类似问题?

最佳答案

这是实际上对于蛮力来说足够简单的问题之一,虽然您可以使用组合数学、图论或许多其他复杂的工具来解决它,但我实际上对申请人认识到存在更简单的方法(至少对于这个问题而言)。

只有 39,即 19,683 种可能的放置组合 x , o<blank>在网格中,但并非所有这些都有效。

首先,有效的游戏位置是 x 之间的差值。和 o计数不超过 1,因为它们必须交替移动。

另外,不可能出现双方三连的状态,所以也可以打折扣。如果两人连成三局,那么他们中的一人将在步中获胜。

实际上还有另一个限制,即一方不可能在没有共同单元的情况下以两种不同的方式获胜(同样,他们本可以在前一步中获胜),这意味着:

XXX
OOO
XXX

无法实现,而:

XXX
OOX
OOX

可以。但我们实际上可以忽略这一点,因为如果没有公共(public)单元格就无法在不违反“最大差一”规则的情况下以两种方式获胜,因为为此你需要六个单元格,而对手只有三个。

所以我会简单地使用蛮力,对于计数之间差异为零或一的每个位置,检查双方的八种获胜可能性。假设他们中只有一个获胜,那就是合法的获胜游戏。


下面是 Python 中的概念证明,但首先是 time 的输出在进程上运行时将输出发送到 /dev/null显示它有多快:

real    0m0.169s
user    0m0.109s
sys     0m0.030s

代码:

def won(c, n):
  if c[0] == n and c[1] == n and c[2] == n: return 1
  if c[3] == n and c[4] == n and c[5] == n: return 1
  if c[6] == n and c[7] == n and c[8] == n: return 1

  if c[0] == n and c[3] == n and c[6] == n: return 1
  if c[1] == n and c[4] == n and c[7] == n: return 1
  if c[2] == n and c[5] == n and c[8] == n: return 1

  if c[0] == n and c[4] == n and c[8] == n: return 1
  if c[2] == n and c[4] == n and c[6] == n: return 1

  return 0

pc = [' ', 'x', 'o']
c = [0] * 9
for c[0] in range (3):
  for c[1] in range (3):
    for c[2] in range (3):
      for c[3] in range (3):
        for c[4] in range (3):
          for c[5] in range (3):
            for c[6] in range (3):
              for c[7] in range (3):
                for c[8] in range (3):
                  countx = sum([1 for x in c if x == 1])
                  county = sum([1 for x in c if x == 2])
                  if abs(countx-county) < 2:
                    if won(c,1) + won(c,2) == 1:
                      print " %s | %s | %s" % (pc[c[0]],pc[c[1]],pc[c[2]])
                      print "---+---+---"
                      print " %s | %s | %s" % (pc[c[3]],pc[c[4]],pc[c[5]])
                      print "---+---+---"
                      print " %s | %s | %s" % (pc[c[6]],pc[c[7]],pc[c[8]])
                      print

正如一位评论者所指出的,还有一个限制。给定棋盘的获胜者的单元格不能少于失败者,因为这意味着失败者刚刚移动,尽管事实上获胜者已经在最后一步中获胜。

我不会更改代码以考虑到这一点,但检查谁拥有最多单元格(最后移动的人)并确保获胜线属于他们是一件简单的事情。

关于algorithm - 所有可能的井字游戏获胜组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28712279/

相关文章:

algorithm - 如何判断 A* 算法何时是一个好的选择,以及如何选择一个好的启发式算法?

CDN分发的PHP算法

python - 在python中获取所有可能的订单组合

algorithm - 计算节点数 - 有向图中任意两个节点之间的不相交路径,使得距离 <= K

python - Eratosthenes 筛法返回大的合数(这是一个错误)

java - Coin change : get the combinations recursively,如何将它们保存到数组中

python - 列出表中存在数据或 NULL 的所有组合的算法

图的 Prolog 连接边

algorithm - 测试给定的 DAG 是否是格

python - 缺少项算术级数 - 清理我的代码