Я пытаюсь создать простую игру «Connect 4». В этой игре я бы хотел, чтобы меню с радиокнопками отображалось пользователю на каждом шагу, чтобы он / она мог выбрать следующий ход.
Я пытался поместить меню в какое-то время "l" 1008 *, но он просто не выполняет никаких действий. Я не знаю, как это исправить, потому что я точно не понимаю, как работает tkinter. Я видел несколько других вопросов, касающихся этой темы, но я все еще не могу понять, как это исправить.
Ниже приведен код, а также два класса, которые я использовал вместе с ним. Меню, которое я пытаюсь представить в al oop, находится в 'present_columns_choice', которое используется в al oop в 'handle_two_humans'
Буду признателен за любую помощь. Спасибо!
from game import *
from tkinter import *
HUMAN = 0
COMPUTER = 1
GRID_SIZE = 50
NUM_ROWS = 6
NUM_COLUMNS = 7
COLOR_A = "red"
COLOR_B = "blue"
class GameGUI:
def __init__(self, root):
self.__root = root
self.__player_A = None
self.__player_B = None
def assign_player(self, player, identity):
if player == "player A":
self.__player_A = identity
elif player == "player B":
self.__player_B = identity
print("Player A is: " + str(self.__player_A))
print("Player B is: " + str(self.__player_B))
def present_player_choice(self):
self.ask_choose_player("player A")
self.ask_choose_player("player B")
Button(self.__root, text="OK", command=quit).pack(anchor=W)
def ask_choose_player(self, player):
Label(self.__root, text="Who would you like to play " + player + "?").pack(anchor=W)
var = IntVar()
Radiobutton(self.__root, text="human", variable=var,
command=lambda:self.assign_player(player, HUMAN), value=1).pack(anchor=W)
Radiobutton(self.__root, text="computer", variable=var,
command=lambda:self.assign_player(player, COMPUTER), value=2).pack(anchor=W)
def get_playerA(self):
return self.__player_A
def get_playerB(self):
return self.__player_B
def handle_two_humans(self):
game = Game()
canvas_width = GRID_SIZE*NUM_COLUMNS
canvas_height = GRID_SIZE*NUM_ROWS
canvas = Canvas(self.__root, width=canvas_width, height=canvas_height)
canvas.pack()
for row_ind in range(NUM_ROWS):
for column_ind in range(NUM_COLUMNS):
canvas.create_rectangle(column_ind*GRID_SIZE, row_ind*GRID_SIZE,
(column_ind+1)*GRID_SIZE, (row_ind+1)*GRID_SIZE)
while not IS_GAME_WON:
self.present_columns_choice(game, canvas)
def add_disc(self, game, column, canvas):
current_player = game.get_current_player()
if current_player == PLAYER_A:
self.fill_square(game, canvas, COLOR_A, column)
elif current_player == PLAYER_B:
self.fill_square(game, canvas, COLOR_B, column)
game.make_move(column)
def present_columns_choice(self, game, canvas):
columns = game.get_board().get_available_columns()
var = IntVar()
Label(self.__root, text="The following columns are still available. "
"Where would you like to place your disc?").pack(anchor=W)
for ind, column in enumerate(columns):
shown_column = column+1
Radiobutton(self.__root, text=shown_column, padx=20, variable=var, value=ind,
command=lambda column=column: self.add_disc(game, column, canvas)).pack(anchor=W)
Button(self.__root, text="OK", command=quit).pack(anchor=W)
def fill_square(self, game, canvas, color, column):
""" Fills square of column chosen by player. """
row = game.get_board().get_available_row(column)
canvas.create_rectangle(column*GRID_SIZE, row*GRID_SIZE, (column+1)*GRID_SIZE,
(row+1)*GRID_SIZE, fill = color)
if __name__ == '__main__':
root = Tk()
gui = GameGUI(root)
gui.handle_two_humans()
mainloop()
Here's the Game class, which was used here:
from board import *
PLAYER_A = 1
PLAYER_B = 2
INITIAL_ROW = 0
INITIAL_COLUMN = 0
FINAL_ROW = 5
FINAL_COLUMN = 6
ILLEGAL_LOCATION_MSG = "Illegal location."
ILLEGAL_MOVE_MSG = "Illegal move."
IS_GAME_WON = False
WINNER = None
class Game:
def __init__(self):
self.__current_player = PLAYER_A
self.__board = Board()
self.__is_game_won = False
self.__winner = None
def make_move(self, column):
""" Makes move and updates board and current player, if column is a valid choice and game is ongoing. """
possible_winner = self.__current_player
if self.__board.is_col_illegal(column) or self.__is_game_won:
raise Exception(ILLEGAL_MOVE_MSG)
self.do_move(column)
if self.__board.is_win(column):
self.__is_game_won = True
self.__winner = possible_winner
def do_move(self, column):
""" Actual implementation of the move. """
if self.__current_player == PLAYER_A:
self.__board.update_board(column, PLAYER_A)
self.__current_player = PLAYER_B
elif self.__current_player == PLAYER_B:
self.__board.update_board(column, PLAYER_B)
self.__current_player = PLAYER_A
def get_winner(self):
""" Returns winner, or None if there is none. """
return self.__winner
def get_player_at(self, row, col):
""" Returns the player whose disc is at the given position in the game. """
if row < INITIAL_ROW or row > FINAL_ROW or col < INITIAL_COLUMN or col > FINAL_COLUMN:
raise Exception(ILLEGAL_LOCATION_MSG)
return self.__board.get_board()[row][col]
def get_current_player(self):
""" Returns current_player. """
return self.__current_player
def get_board(self):
""" Returns board."""
return self.__board
And here's Board, which is used in Game:
NUM_ROWS = 6
NUM_COLUMNS = 7
INITIAL_VALUE = None
WIN_COUNT = 4
FIRST_ROW = 5
LAST_ROW = 0
class Board:
def __init__(self):
self.__playboard = []
self.__available_rows_list = NUM_COLUMNS*[NUM_ROWS-1]
initial_row = NUM_COLUMNS * [INITIAL_VALUE]
for i in range(NUM_ROWS):
self.__playboard.append(initial_row.copy())
def get_available_columns(self):
""" Returns all columns that still have empty space in them. """
available_columns = []
for col in range(len(self.__available_rows_list)):
if self.__available_rows_list[col] >= 0:
available_columns.append(col)
return available_columns
def get_playboard(self):
""" Returns board. """
return self.__playboard
def update_board(self, col, val):
""" Updates current status of board. """
row = self.__available_rows_list[col]
self.__playboard[row][col] = val
self.__update_row(col)
def __update_row(self, col):
""" Updates available_row_list. """
self.__available_rows_list[col] = self.__available_rows_list[col] - 1
def __is_col_available(self, col):
""" Checks if given col has empty spaces left on the playboard. """
if self.__available_rows_list[col] < 0:
return False
return True
def __is_col_exist(self, col):
""" Checks if given column is within the capacity of the playboard. """
if col < 0 or col >= NUM_COLUMNS:
return False
return True
def is_col_illegal(self, col):
""" Checks if given column is an illegal option. """
if not self.__is_col_available(col) or not self.__is_col_exist(col):
return True
return False
def print_playboard(self):
for row in self.__playboard:
print(row)
def is_win(self, col):
""" Checks if current state of board resulted in a win. """
row = self.__available_rows_list[col]+1
if self.__check_vertical_win(row, col) or self.__check_horizontal_win(row, col) or \
self.__check_decreasing_diagonal_win(row, col) or self.__check_increasing_diagonal_win(row, col):
return True
return False
def __check_increasing_diagonal_win(self, original_row, original_col):
""" Checks if player has won in the increasing diagonal direction. """
count = 1
player = self.__playboard[original_row][original_col]
col = original_col + 1
row = original_row - 1
while self.__is_col_exist(col) and row >= LAST_ROW and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col + 1
row = row - 1
# Then: undergo same process, this time in the opposite direction.
col = original_col - 1
row = original_row + 1
while self.__is_col_exist(col) and row <= FIRST_ROW and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col - 1
row = row + 1
def __check_decreasing_diagonal_win(self, original_row, original_col):
""" Checks if player has won in the decreasing diagonal direction. """
count = 1
player = self.__playboard[original_row][original_col]
col = original_col + 1
row = original_row + 1
while self.__is_col_exist(col) and row <= FIRST_ROW and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col + 1
row = row + 1
# Then: undergo same process, this time in the opposite direction.
col = original_col - 1
row = original_row - 1
while self.__is_col_exist(col) and row >= LAST_ROW and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col - 1
row = row - 1
def __check_vertical_win(self, original_row, col):
""" Checks if player has won in the horizontal direction. """
count = 1
player = self.__playboard[original_row][col]
row = original_row + 1
while row <= FIRST_ROW and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
row = row + 1
def __check_horizontal_win(self, row, original_col):
""" Checks if player has won in the horizontal direction. """
count = 1
player = self.__playboard[row][original_col]
col = original_col + 1
while self.__is_col_exist(col) and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col + 1
# Then: undergo same process, this time in the opposite direction (the left).
col = original_col - 1
while self.__is_col_exist(col) and self.__playboard[row][col] == player:
count = count + 1
if count == WIN_COUNT:
return True
col = col - 1
def get_available_row(self, column):
""" Returns the row which will be filled if you choose this column. """
return self.__available_rows_list[column]