所有可能的Tic Tac Toe获胜组合

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了所有可能的Tic Tac Toe获胜组合相关的知识,希望对你有一定的参考价值。

我接受了一次采访,我被问到一个看似简单的算法问题:“编写一个算法,将所有可能的获胜组合归还给我。”我仍然无法找到一种有效的方法来处理这个问题。是否有一个标准算法或常见的应用于我不知道的类似问题?

答案

这是一个对蛮力来说实际上很简单的问题之一,虽然你可以使用组合学,图论或其他许多复杂的工具来解决它,但实际上我会对申请人留下深刻的印象,他们认识到这是一种更简单的方法(至少对于这个问题)。

在网格中放置xo<blank>的组合只有39种或19,683种,并非所有这些组合都是有效的。

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

另外,不可能有一个双方都连续三个的州,所以也可以打折。如果两者都有三个连续,那么其中一个将在前一个移动中获胜。

实际上还存在另一个限制,即如果没有共同的单元格,一方可能以两种不同的方式获胜(同样,他们会在之前的一次移动中获胜),这意味着:

XXX
OOO
XXX

无法实现,同时:

XXX
OOX
OOX

可。但是我们实际上可以忽略这一点,因为如果没有违反“一个最大差异”规则,就没有办法在没有共同单元格的情况下赢得两种方式,因为你需要六个单元格,而对手只有三个单元格。

所以我只是使用蛮力,并且对于每个位置,其中差值为零或计数之间的一个,检查双方的八个获胜可能性。假设他们中只有一人获胜,这是一场合法的胜利游戏。


下面是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

正如一位评论者指出的那样,还有一个限制因素。一个特定董事会的赢家不能拥有比失败者更少的细胞,因为这意味着失败者只是移动了,尽管胜利者已经在最后一步获胜。

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

另一答案

另一种方式可能是从八个获胜位置开始,

xxx ---
--- xxx
--- --- ... etc.,

并递归填写所有合法组合(从插入2个o开始,然后为每个x添加一个o;避免o获胜位置):

xxx xxx xxx
oo- oox oox
--- o-- oox ... etc.,
另一答案

这是一个java等效代码示例

包装测试;

公共课TicTacToe {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    // 0 1 2
    // 3 4 5
    // 6 7 8
    char[] pc = {' ' ,'o', 'x' };

    char[] c = new char[9];

    // initialize c

    for (int i = 0; i < 9; i++)
        c[i] = pc[0];

    for (int i = 0; i < 3; i++) {
        c[0] = pc[i];
        for (int j = 0; j < 3; j++) {
            c[1] = pc[j];
            for (int k = 0; k < 3; k++) {
                c[2] = pc[k];
                for (int l = 0; l < 3; l++) {
                    c[3] = pc[l];
                    for (int m = 0; m < 3; m++) {
                        c[4] = pc[m];
                        for (int n = 0; n < 3; n++) {
                            c[5] = pc[n];
                            for (int o = 0; o < 3; o++) {
                                c[6] = pc[o];
                                for (int p = 0; p < 3; p++) {
                                    c[7] = pc[p];
                                    for (int q = 0; q < 3; q++) {
                                        c[8] = pc[q];

                                        int countx = 0;
                                        int county = 0;

                                        for(int r = 0 ; r<9 ; r++){
                                            if(c[r] == 'x'){

                                                countx = countx + 1;
                                            }
                                            else if(c[r] == 'o'){

                                                county = county + 1;

                                            }


                                        }

                                        if(Math.abs(countx - county) < 2){

                                            if(won(c, pc[2])+won(c, pc[1]) == 1 ){
                                                System.out.println(c[0] + " " + c[1] + " " + c[2]);
                                                System.out.println(c[3] + " " + c[4] + " " + c[5]);
                                                System.out.println(c[6] + " " + c[7] + " " + c[8]);

                                                System.out.println("*******************************************");


                                            }


                                        }









                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

public static int won(char[] c, char n) {

    if ((c[0] == n) && (c[1] == n) && (c[2] == n))
        return 1;
    else if ((c[3] == n) && (c[4] == n) && (c[5] == n))
        return 1;
    else if ((c[6] == n) && (c[7] == n) && (c[8] == n))
        return 1;
    else if ((c[0] == n) && (c[3] == n) && (c[6] == n))
        return 1;
    else if ((c[1] == n) && (c[4] == n) && (c[7] == n))
        return 1;
    else if ((c[2] == n) && (c[5] == n) && (c[8] == n))
        return 1;
    else if ((c[0] == n) && (c[4] == n) && (c[8] == n))
        return 1;
    else if ((c[2] == n) && (c[4] == n) && (c[6] == n))
        return 1;
    else
        return 0;

}

} `

另一答案

今天我接受了Apple的采访,我有同样的问题。那一刻我想不通。后来在开会前我在15分钟内为组合编写了函数,当我从会议中回来时,我在15分钟内再次编写了验证函数。我在采访中感到紧张,Apple不相信我的简历,他们只相信他们在采访中看到的内容,我不怪他们,很多公司都是一样的,我只是说这个招聘过程中看起来不太聪明。

无论如何,这是我在Swift 4中的解决方案,组合功能有8行代码,17行代码检查有效板。

干杯!!!

// Not used yet: 0
// Used with x : 1
// Used with 0 : 2
// 8 lines code to get the next combination
func increment ( _ list: inout [Int], _ base: Int ) -> Bool {
    for digit in 0..<list.count {
        list[digit] += 1
        if list[digit] < base { return true }
        list[digit] = 0
    }
    return false
}
let incrementTicTacToe = { increment(&$0, 3) }

let win0_ = [0,1,2] // [1,1,1,0,0,0,0,0,0]
let win1_ = [3,4,5] // [0,0,0,1,1,1,0,0,0]
let win2_ = [6,7,8] // [0,0,0,0,0,0,1,1,1]
let win_0 = [0,3,6] // [1,0,0,1,0,0,1,0,0]
let win_1 = [1,4,7] // [0,1,0,0,1,0,0,1,0]
let win_2 = [2,5,8] // [0,0,1,0,0,1,0,0,1]
let win00 = [0,4,8] // [1,0,0,0,1,0,0,0,1]
let win11 = [2,4,6] // [0,0,1,0,1,0,1,0,0]
let winList = [ win0_, win1_, win2_, win_0, win_1, win_2, win00, win11]
// 16 lines to check a valid board, wihtout countin lines of comment.
func winCombination (_ tictactoe: [Int]) -> Bool {
    var count = 0
    for win in winList {
        if tictactoe[win[0]] == tictactoe[win[1]],
            tictactoe[win[1]] == tictactoe[win[2]],
            tictactoe[win[2]] != 0 {
            // If the combination exist increment count by 1.
            count += 1
        }
        if count == 2 {
            return false
        }
    }
    var indexes = Array(repeating:0, count:3)
    for num in tictactoe { indexes[num] += 1 }
    // '0' and 'X' must be used the same times or with a diference of one.
    // Must one and only one valid combination
    return abs(indexes[1] - index

以上是关于所有可能的Tic Tac Toe获胜组合的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 5275. 找出井字棋的获胜者 Find Winner on a Tic Tac Toe Game

[leetcode]Design Tic-Tac-Toe

我如何为Tic Tac Toe游戏创建HashMap

Codeforces3C. Tic-tac-toe 题解 状态压缩+搜索

python tic tac toe记分牌没有更新[关闭]

bfs codeforces 754B Ilya and tic-tac-toe game