Python - 确定井字游戏赢家
Posted
技术标签:
【中文标题】Python - 确定井字游戏赢家【英文标题】:Python - Determine Tic-Tac-Toe Winner 【发布时间】:2017-02-16 18:59:00 【问题描述】:我正在尝试编写一个代码来确定井字游戏的获胜者。 (这是大学作业)
为此,我编写了以下函数:
这段代码只检查水平线,其余的我没有添加。我觉得这需要一些硬编码。
def iswinner(board, decorator):
win = True
for row in range(len(board)):
for col in range(len(board)):
if board[row][col] == decorator:
win = True
else:
win = False
break
其中“board”是一个大小为 n^2 的二维数组,“decorator”是“X”或“O”值
我希望完成的是函数循环遍历二维数组的行。然后循环遍历每一行中的值。如果该元素与“装饰器”匹配,则它继续并检查下一个,但如果不匹配,则它从第一个循环中断并进入下一行。它会这样做,直到在同一行中找到 n 个元素。然后它会给出一个布尔值 True 否则 False。
代码似乎没有这样做,即使我检查了下面的“板”,它也给了我一个“真”的输出
check_list = [['O', 'X', 'X'], ['O', 'X', 'O'], ['O', 'X', 'X']]
非常感谢!
最好, 赛义德
【问题讨论】:
如果部分代码看不懂,请告诉我 什么时候将win
设置为False
?它总是True
。而且逻辑听起来是错误的……缩进是错误的,你不返回win
!这开始在您的代码中累积。
@Jean-FrançoisFabre 我更新了代码,不知何故该行丢失了
@Jean-FrançoisFabre 很抱歉出现缩进,现在已修复
装饰器是什么?您不需要连续 3 次来赢得井字游戏吗?根据一个单元格的价值,您如何获胜?
【参考方案1】:
您可以只为每一行制作一组,并检查其长度。如果它只包含一个元素,那么游戏就赢了。
def returnWinner(board):
for row in board:
if len(set(row)) == 1:
return row[0]
return -1
如果有整行“O”,则返回“O”,如果有一行“X”,则返回“X”,否则返回-1。
下面是一个完整的井字棋检查器的代码,应该不难理解,但请不要犹豫:
import numpy as np
def checkRows(board):
for row in board:
if len(set(row)) == 1:
return row[0]
return 0
def checkDiagonals(board):
if len(set([board[i][i] for i in range(len(board))])) == 1:
return board[0][0]
if len(set([board[i][len(board)-i-1] for i in range(len(board))])) == 1:
return board[0][len(board)-1]
return 0
def checkWin(board):
#transposition to check rows, then columns
for newBoard in [board, np.transpose(board)]:
result = checkRows(newBoard)
if result:
return result
return checkDiagonals(board)
a = [['X', 'A', 'X'],
['A', 'X', 'A'],
['A', 'X', 'A']]
print(checkWin(a))
请注意,无论您选择在井字游戏中放置什么符号(“O”和“X”与“bloop”和“!”一样好),这都有效,并且对于任何大小的网格,只要是正方形。
【讨论】:
你能解释一下“set”部分是做什么的吗? 它将数组转换为集合。一个集合是一个unordered collection of unique elements。因此set(['X', 'O', 'X'])
只包含'X', 'O'
,而set(['X', 'X', 'X'])
只包含'X'
。如果集合只包含一个元素,那么就只有一种装饰器。【参考方案2】:
执行此操作的一种方法是创建所有可能的索引组合的集合(生成器函数会更好)以检查是否获胜。然后循环遍历这些索引组合并检查它们是否都包含相同的值,如果是,那就是胜利。
def win_indexes(n):
# Rows
for r in range(n):
yield [(r, c) for c in range(n)]
# Columns
for c in range(n):
yield [(r, c) for r in range(n)]
# Diagonal top left to bottom right
yield [(i, i) for i in range(n)]
# Diagonal top right to bottom left
yield [(i, n - 1 - i) for i in range(n)
def is_winner(board, decorator):
n = len(board)
for indexes in win_indexes(n):
if all(board[r][c] == decorator for r, c in indexes):
return True
return False
【讨论】:
有没有办法将其概括为水平、垂直和对角线检查,或者这是不可能的? 是的,这是通用的。它目前检查水平、垂直和对角线。如果您想添加更多获胜条件(例如 4 个角),您只需yield
来自 win_indexes
生成器的附加索引。
你能解释一下你的代码中的产量吗?我自己也在阅读。
它是一个生成器。如果您不想使用生成器,而不是 yield
ing 每个索引列表,您可以将它们 append
到一个列表并返回整个列表。
当我尝试运行代码时,它给了我“NameError: name 'n' is not defined”【参考方案3】:
def check_winner(board,mark):
return((board[1]==mark and board[2]== mark and board[3]==mark )or #for row1
(board[4]==mark and board[5]==mark and board[6]==mark )or #for row2
(board[7]==mark and board[8]==mark and board[9]==mark )or #for row3
(board[1]==mark and board[4]==mark and board[7]== mark )or#for Colm1
(board[2]==mark and board[5]==mark and board[8]==mark )or #for Colm 2
(board[3]==mark and board[6]==mark and board[9]==mark )or #for colm 3
(board[1]==mark and board[5]==mark and board[9]==mark )or #daignole 1
(board[3]==mark and board[5]==mark and board[7]==mark )) #daignole 2
【讨论】:
【参考方案4】:我刚刚想出了这段小代码:
def eval_w(board):
possible = []
#rows
for i in range(3):
possible.append( board[i][0] + board[i][1] + board[i][2] )
#columns
for i in range(3):
possible.append( board[0][i] + board[1][i] + board[2][i] )
#diagonals
possible.append( board[0][0] + board[1][1] + board[2][2] )
possible.append( board[0][2] + board[1][1] + board[2][0] )
if 3 in possible:
ended = True
return 1
elif -3 in possible:
ended = True
return -1
else:
return 0
我这里没看到类似的东西,所以我还是贴吧。
【讨论】:
【参考方案5】:您可以通过创建一个generator、lines()
来生成所有 8 行(3 行、3 列和 2 条对角线),然后检查是否有任何行仅由一个元素和该元素组成不是None
一旦你有类似的东西
board = [
[ 'o', 'x', None],
[None, 'x', None],
[None, 'x', 'o']
]
这样做:
def _lines(board):
yield from board # the rows
yield [board[i][i] for i in range(len(board))] # one of the diagonals
def lines(board):
yield from _lines(board)
# rotate the board 90 degrees to get the columns and the other diagonal
yield from _lines(list(zip(*reversed(board))))
def who_won(board):
for line in lines(board):
if len(set(line)) == 1 and line[0] is not None:
return line[0]
return None # if we got this far, there's no winner
对于我上面给出的板,list(lines(board))
将返回
[['o', 'x', None],
[None, 'x', None],
[None, 'x', 'o'],
['o', 'x', 'o'],
(None, None, 'o'),
('x', 'x', 'x'),
('o', None, None),
[None, 'x', None]]
其中 3 个元素是元组而不是列表,因为 zip
返回元组。您可以使用列表推导来转换它们,请参阅 this question 了解如何执行此操作以及更多有关 zip(*reversed(some_list))
功能的详细信息。
然后只需通过转换为set
和那个唯一元素is not None
来检查每个元素是否只有一个唯一元素。
这适用于任何尺寸的井字游戏,而不仅仅是 3×3。
【讨论】:
【参考方案6】:我有点晚了,但使用 numpy 会是更好的方法,因为它解决了遍历多个列表的麻烦。它基本上使 'x' 为 1 和 'o' 为 0,所以如果 w 将所有元素添加到一行或列中,我们得到 3 或 0,x 或 o 将获胜。如果是平局,我们得到 -1 结果数组
import numpy as np
def check(arr):
if np.sum(arr)==3:
return 'x'
elif np.sum(arr)==0:
return 'o'
else: return -1
if __name__=='__main__':
a=np.array([['X','O','X'],['O','X','O'],['X','X','O']]) #input array
b=np.where(a=='X',1,0)
r1=check(b[:,:1])
r2=check(b[:,1:2])
r3=check(b[:,2:3])
c1=check(b[:1,:])
c2=check(b[1:2,:])
c3=check(b[2:3,:])
d1=check(np.diagonal(b))
d2=check(np.diagonal(np.fliplr(b)))
result=np.array([r1,r2,r3,c1,c2,c3,d1,d2])
if 'x' in result:print('x won')
elif 'o' in result:print('o won')
else:print('draw again')
【讨论】:
【参考方案7】:一个细胞总共可以有3种状态
-
如果还没有填满,则为0(游戏有可能在5步内结束)
如果用'X'填充则为1
-1 如果用'O'填充
我将扩展@EfferLagan 的答案
def checkRows(board):
for row in board:
if (len(set(row)) == 1) and (row[0] != 0):
return row[0]
return 999
def checkDiagonals(board):
if (len(set([board[i][i] for i in range(len(board))])) == 1) and (board[0][0] != 0):
return board[0][0]
if (len(set([board[i][len(board)-i-1] for i in range(len(board))])) == 1) and (board[0][0] !=0):
return board[0][len(board)-1]
return 999
def checkWin(board):
#transposition to check rows, then columns
for newBoard in [board, np.transpose(board)]:
result = checkRows(newBoard)
if result:
return result
return checkDiagonals(board)
randomInput=[
[0,0,1],
[-1,-1,1],
[0,0,0]
]
您有 3 个输出 1、-1 和 999(这意味着两者都没有获胜) checkWin(随机输入)
【讨论】:
【参考方案8】: def check_winer(board):
#used to check the winner in row
for row in range(0,3):
if board[row][0]==board[row][1]==board[row][2] and board[row][0] != 0:
if chance=='o':
print("x is winner")
elif chance=='x':
print("o is winner")
#used to check thw winner in column
for col in range(0,3):
if board[0][col]==board[1][col]==board[2][col] and board[0][col] != 0:
if chance=='o':
print("x is winner")
elif chance=='x':
print("o is winner")
#used to check winner in one diagonal
if board[0][0]==board[1][1]==board[2][2] and board[0][0] !=0:
if chance=='o':
print('x is winner')
elif chance=='x':
print("o is winner")
#used to check winner in another diagonal
if board[0][2]==board[1][1]==board[2][0] and board[0][2]!=0:
if chance=='o':
print("x is winner")
elif chance=='x':
print("o is winner")
在tic-tac-toe中两次检查获胜者您可以使用此功能。 你必须先创建一个像这样的二维数组:
board=[[0,0,0],
[0,0,0],
[0,0,0]]
所以当轮到 x 时单击框并将数组中的值更改为相对于框的 1。 并在每次点击中将机会从 x 更改为 o 并从 o 更改为 x。 如果轮到 o,则将数组中的值相对于坐标更改为 2。 每次单击框以放置 x 或 o 时,都必须调用此函数。
请确保在将机会从 x 更改为 o 或从 o 更改为 x 后调用此函数。 因为如果你不这样做,这个函数会给出错误的输出。
例如,如果这是板:
[[1,2,1],
[2,1,0],
[1,0,0]]
那么这个函数会给出如下输出:
o is the winner
【讨论】:
您需要完整记录此解决方案如何使用 OP 的当前代码。这是一个老问题,你的答案太抽象和复杂,因为向 OP 提问的开发人员不太可能理解你的贡献或从你的贡献中受益。看到 OP 不太可能做出回应,您必须付出更多努力来提供完整的解决方案,并让我们其他人相信您的解决方案优于其他解决方案。以上是关于Python - 确定井字游戏赢家的主要内容,如果未能解决你的问题,请参考以下文章