我在做一个小动作。所以我有一个代表游戏状态的类TicTacToe
,这个类显示了在游戏中操作的方法(网格,谁拥有哪些单元,谁是下一个要玩的玩家)。这是合乎逻辑的部分。在
我想用Tkinter(作为tk
导入)将其放入GUI中。我在几个方面犹豫不决:
创建一个TicTacToeUI
类,该类继承tk.Frame
和{
创建一个继承TicTacToeUI
并具有TicTacToe
属性的TicTacToeUI
类;
创建一个继承TicTacToeUI
的类,它只定义图形元素,TicTacToeBindingUI
将{
这是用Tkinter分离逻辑和GUI的惯用方法吗?在
下面是我编写的代码;它是用法语注释的,但是变量的名称似乎足够清楚,可以理解这个过程。如你所见,我选择第二种解决方案。欢迎评论。在
from tkinter import *
class AlreadyTaken(Exception):
pass
class GameOver(Exception):
pass
class TicTacToe:
def __init__(self):
""" Built an object representing the state of the TicTacToe.
An instance of TicTacToe has two attributes:
self.next_player_to_play : indicate who is the next player (coding by 1 or 2).
self.grid (list of list): the grid 3x3 of the game; 0 is for
empty cells, 1 (resp. 2) is for the first (resp. second player).
"""
self.grid = [[0] * 3 for i in range(3)]
self.next_player_to_play = 1
self.game_over = False
def is_cell_free(self, i, j):
""" Return True if the cell (i, j) is empty, False orthewise.
Raises IndexError if i and j are not in [0,2]."""
if not ( 0 <= i <= 2 and 0 <= j <= 2):
raise IndexError('cell (%d, %d) index out of range'%(i, j))
return not self.grid[i][j]
def play(self, i, j):
""" The player self.next_player_to_play capture the cell (i, j),
if this cell is free. Raises AlreadyTaken exception if (i, j)
is not empty, or GameOver if the game is over.
Return 0 if the current player doesn't win, or the number of
the winning player."""
if self.game_over:
raise GameOver('the game is over, the winner is the player %d'
%self.next_player_to_play)
if not self.is_cell_free( i, j):
raise AlreadyTaken('cell (%d, %d) already taken by player %d'
%(i, j, self.grid[i][j]))
p = self.next_player_to_play
self.grid[i][j] = p
if self._is_victorious(p):
self.game_over = True
return p
# switch les deux joueurs
self.next_player_to_play = 3 - p
return 0
def _is_victorious(self, player):
""" Return True if the player `player` wins, i.e. if he succeed making a row, a column or a diagonal."""
g = self.grid
return (
# fill a column?
any(all(g[i][j] == player for i in range(3)) for j in range(3)) or
# fill a row ?
any(all(g[i][j] == player for j in range(3)) for i in range(3)) or
# fill a diagonal ?
all(g[i][i] == player for i in range(3)) or
# l'anti-diagonale ?
all(g[i][2-i] == player for i in range(3))
)
class TicTacToeUI(Frame):
def __init__(self,
master=None,
void_symb=' ',
player1_symb='X',
player2_symb='O',
tictactoe=None):
""" Build a frame drawing a TicTacToe game with 9 cells.
* `<situation>_symb`: indicates what symbol to use for a void cell, or owned by a player (1 or 2).
* `tictactoe`: by default (if `tictactoe` is None),a new game is created,
but we can use an existing TicTacToe instance instead."""
super().__init__(master, width=150, height=150)
if tictactoe is None:
tictactoe = TicTacToe()
self.tictactoe = tictactoe
symbols = [void_symb, player1_symb, player2_symb]
self._symbols = symbols
buttons_grid = []
self.buttons_grid = buttons_grid
Label(self, text='Super tictactoe!').grid(row=0, column=0, columnspan=3)
label_player_playing = Label(self, text='Player 1 is playing')
label_player_playing.grid(row=1, column=0, columnspan=3)
self.label_player_playing = label_player_playing
for i in range(3):
buttons_line = []
for j in range(3):
player = tictactoe.grid[i][j]
button = Button(
self,
text=symbols[player],
command=lambda i=i, j=j: self.play(i, j),
bg="green"
)
button.grid(row=i+2, column=j)
buttons_line.append(button)
buttons_grid.append(buttons_line)
Button(
self,
text='Start a new game',
command=self.reinit_game
).grid(column=0, row=5, columnspan=3)
def play(self, i, j):
try:
player = self.tictactoe.next_player_to_play
victorious_player = self.tictactoe.play(i, j)
self.buttons_grid[i][j]['text'] = self._symbols[player]
if victorious_player:
self.label_player_playing['text'] = 'Player %d wins!' % player
else:
self._update_label_player_playing()
except (AlreadyTaken, GameOver) as e:
pass
def _update_label_player_playing(self):
player = self.tictactoe.next_player_to_play
self.label_player_playing['text'] = 'Player %d is playing' % player
def _all_buttons_to_void(self):
for line in self.buttons_grid:
for b in line:
b['text'] = self._symbols[0]
def reinit_game(self):
self.tictactoe = TicTacToe()
self._all_buttons_to_void()
self._update_label_player_playing()
m = TicTacToeUI()
m.pack()
m.mainloop()
目前没有回答
相关问题 更多 >
编程相关推荐