【发布时间】:2019-12-10 20:44:55
【问题描述】:
我正在 Tkinter 中制作一个可扩展的井字游戏(这意味着棋盘大小可以是 2x2 到任何适合屏幕的大小)。我正在使用cget("image") 来查找按钮的标记。出于某种原因,获胜检查会显示非常随机的内容。我已经尝试了很多半随机的东西来修复它,但没有成功修复它。代码如下:
from tkinter import *
class XOGame:
def main_game(self):
self.__game_window = Tk()
self.__grid_size = 3 # User inputted in a different part of the code
self.__game_window.title("Tic Tac Toe (" + str(self.__grid_size) + "x"
+ str(self.__grid_size) + ")")
# this is user inputted in a different part of the program.
self.__players = ["p1", "p2"]
self.__player1 = self.__players[0]
self.__player2 = self.__players[1]
self.build_board(self.__game_window)
self.__game_window.mainloop()
def build_board(self, window):
self.__size = self.__grid_size ** 2
self.__turn_nr = 1
self.__win = False
self.__empty_square = PhotoImage(master=window,
file="rsz_empty.gif")
self.__x = PhotoImage(master=window,
file="rsz_cross.gif")
self.__o = PhotoImage(master=window,
file="rsz_nought.gif")
self.__squares = [None] * self.__size
self.create_win_check_lists()
# Building the buttons and gridding them
for i in range(self.__size):
self.__squares[i] = (Button(window, image=self.__empty_square))
row = 0
column = 0
number = 1
for j in self.__squares:
j.grid(row=row, column=column)
j.config(command=lambda index=self.__squares.index(j):
self.change_mark(index))
column += 1
if number % 3 == 0:
row += 1
column = 0
number += 1
# This is the part where the picture changing happens.
def change_mark(self, i):
"""
Function changes mark of empty button to either X or O depending on the
player in turn. It also checks if the change in mark results in a win.
:param i: The button number, whose mark is being changed
:return: None
"""
if self.__turn_nr % 2 == 1:
self.__player_in_turn = self.__player1
else:
self.__player_in_turn = self.__player2
if self.__player_in_turn == self.__player1:
self.__mark = self.__x
else:
self.__mark = self.__o
self.__squares[i].configure(image=self.__mark, state=DISABLED)
self.__turn_nr += 1
self.check_win(i)
if self.__win is True:
print("this is thought to be a win")
else:
print("the game thinks this is not a win")
# Checking if the game tied.
if self.__turn_nr == self.__size + 1 and not self.__win:
print("the game thinks it tied.")
def check_win(self, i):
"""
Checks if mark placement leads to a win.
:param i: i is the button location.
:return: None
"""
# checks row
if self.__win == False:
for row in self.__rows:
if i + 1 in row:
self.__win = self.checksameimage(row)
if self.__win == True:
break
# checks column
if self.__win == False:
for column in self.__columns:
if i + 1 in column:
self.__win = self.checksameimage(column)
if self.__win == True:
break
# if i is in a diagonal, checks one/both diagonals
if self.__win == False:
for diag in self.__diagonals:
if i + 1 in diag:
self.__win = self.checksameimage(diag)
if self.__win == True:
break
return self.__win
# checking if all the images are same
# This is likely where the issue is. Either this part or checkEqual.
def checksameimage(self, lst):
images = []
for nr in lst:
try:
images.append(self.__squares[nr].cget("image"))
except IndexError:
pass
return self.checkEqual(images)
def checkEqual(self, lst):
"""
Function checks if all elements in a list are equal. Used for checking
if the dice throws are the same.
:param lst: The list the check is performed on
:return: True/False, True if all elements are equal.
"""
if all(x == lst[0] for x in lst):
return True
else:
return False
def create_win_check_lists(self):
"""
Creates lists whose elements are lists of the locations of each spot
of the game board that belongs to a row/column/diagonal
:return:
"""
self.__rows = [[] for _ in range(self.__grid_size)]
for i in range(self.__grid_size):
self.__rows[i].append(i + 1)
for k in range(1, self.__grid_size):
self.__rows[i].append(i + 1 + self.__grid_size * k)
self.__columns = [[] for _ in range(self.__grid_size)]
for i in range(self.__grid_size):
for j in range(1, self.__grid_size + 1):
self.__columns[i].append(i * self.__grid_size + j)
self.getDiagonals(self.__columns)
def getDiagonals(self, lst):
self.__diagonals = [[], []]
self.__diagonals[0] = [lst[i][i] for i in range(len(lst))]
self.__diagonals[1] = [lst[i][len(lst) - i - 1] for i in
range(len(lst))]
def start(self):
# Function starts the first window of the game.
self.main_game()
def main():
ui = XOGame()
ui.start()
main()
代码中使用的图像为 125x125。这是一个 24 小时有效的链接:https://picresize.com/b5df006025f0d8
【问题讨论】:
-
if self.__win == True: break不会阻止它在下一个循环中将self.__win覆盖为 false。生成获胜行和列的代码也很不可读,我怀疑这可能是错误的。 -
@TadhgMcDonald-Jensen 抱歉,修复了 self.__win 最重要的问题。行、列和对角线的生成效果很好,我已经对其进行了广泛的测试。我认为问题特别在于函数 checksameimage 或 checkEqual。
-
您说“相信”,但肯定有一些打印语句会很快证明您的
checksameimage最终会得到一个包含"pyimage1"的2-3 个元素的列表,它对应于空白空间图像。 -
@TadhgMcDonald-Jensen 是的,我知道,我在调试器中看到过。作为初学者,我很难看到按钮中的信息,这让我有时感到有些困惑。问题是,即使 checksameimage 有 pyimage1 的实例,程序仍认为游戏赢了。我真的不明白为什么,因为这是我第一次做一个更大的程序,老实说,我有点难以理解这一切。任何帮助将不胜感激。也感谢您抽出宝贵的时间 :)
标签: python tkinter tic-tac-toe