所有可能的Tic Tac Toe获胜组合
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了所有可能的Tic Tac Toe获胜组合相关的知识,希望对你有一定的参考价值。
我接受了一次采访,我被问到一个看似简单的算法问题:“编写一个算法,将所有可能的获胜组合归还给我。”我仍然无法找到一种有效的方法来处理这个问题。是否有一个标准算法或常见的应用于我不知道的类似问题?
这是一个对蛮力来说实际上很简单的问题之一,虽然你可以使用组合学,图论或其他许多复杂的工具来解决它,但实际上我会对申请人留下深刻的印象,他们认识到这是一种更简单的方法(至少对于这个问题)。
在网格中放置x
,o
或<blank>
的组合只有39种或19,683种,并非所有这些组合都是有效的。
首先,有效的游戏位置是x
和o
计数之间的差异不超过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