From 37b32665b2cc745e4975559bb4a4fd0be6e5e73e Mon Sep 17 00:00:00 2001 From: AngelVI13 Date: Sun, 12 May 2019 17:38:03 +0300 Subject: [PATCH] - Removed unnecessary prints - Added better game over indication - Refactored check_for_game_over method - Added generic draw_color_box method --- gui/constants.py | 14 ++++++++- gui/gui_app.py | 80 ++++++++++++++++++++++++++++-------------------- gui/gui_board.py | 17 +++++++++- 3 files changed, 75 insertions(+), 36 deletions(-) diff --git a/gui/constants.py b/gui/constants.py index 9f24e1a..080c7ea 100644 --- a/gui/constants.py +++ b/gui/constants.py @@ -50,8 +50,9 @@ class GameType(Enum): # Menu buttons BUTTON_WIDTH, BUTTON_HEIGHT = 300, 50 BUTTON_Y_SPACING = 1.5 +BUTTON_X_SPACING = 0.5 -MENU_BUTTON_PROPERTIES = { +MENU_BUTTON_PROPERTIES = { # todo add names instead of integers as keys 0: {'x': (DISPLAY_WIDTH-BUTTON_WIDTH) / 2, 'y': (DISPLAY_HEIGHT / 3) + 1*BUTTON_HEIGHT*BUTTON_Y_SPACING, 'w': BUTTON_WIDTH, 'h': BUTTON_HEIGHT, 'ic': PURPLE, 'ac': PURPLE_HIGHLIGHT}, 1: {'x': (DISPLAY_WIDTH-BUTTON_WIDTH) / 2, 'y': (DISPLAY_HEIGHT / 3) + 2*BUTTON_HEIGHT*BUTTON_Y_SPACING, @@ -109,3 +110,14 @@ class GameType(Enum): # after entering game loop pause for some time before allowing the user to click # fixes issues with accidental clicks PAUSE_BEFORE_USER_INPUT = 1 + +COLOR_BOX_SIZE = 20 +COLOR_BOX_BORDER_THICKNESS = 2 + +OVERLAY_W, OVERLAY_H = 140, 80 +RESULT_OVERLAY = { + 'x': DISPLAY_WIDTH / 2 - OVERLAY_W / 2, + 'y': DISPLAY_HEIGHT / 2 - OVERLAY_H / 2, + 'w': OVERLAY_W, + 'h': OVERLAY_H +} diff --git a/gui/gui_app.py b/gui/gui_app.py index 4889b1e..90957ad 100644 --- a/gui/gui_app.py +++ b/gui/gui_app.py @@ -32,12 +32,7 @@ def subcell_clicked(self, cell): move, board = cell.cell_idx, cell.board_idx self.board.make_move(board, move) - # print(board, move) - # print(self.board) - # print(self.board.playerJustMoved, self.board.nextBoard) self.allowed_cells = self.find_allowed_cells() - # print(self.allowed_cells) - # print() result = self.board.pos[board].get_result() if result is not None: @@ -75,37 +70,53 @@ def draw_results(self): # todo this is the same as draw_all moves? parameterize def check_for_game_over(self): result = self.board.get_result(player_jm=PLAYER_X) - if result is not None: - self.message_display(text=RESULT_TEXT[result]) - self.message_display(text='Click anywhere to continue...', - pos=(DISPLAY_WIDTH / 2, (BOARD_HEIGHT + OFFSET_Y + 30)), font='comicsansms', size=20) - - # Wait until a mouse click before going back to main menu - clicked = False - while not clicked: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - self.quit_game() - elif event.type == pygame.MOUSEBUTTONUP: - clicked = True - return True # game is over - return False # game not over + if result is None: + return False # game not over + + self.message_display(text='Click anywhere to continue...', + pos=(DISPLAY_WIDTH / 2, (BOARD_HEIGHT + OFFSET_Y + 30)), + size=25, update=False) + + # draw transparent overlay + s = pygame.Surface((RESULT_OVERLAY['w'], RESULT_OVERLAY['h']), pygame.SRCALPHA) # per-pixel alpha + s.fill((0x7b, 0x81, 0x89, 200)) # notice the alpha value in the color + self.gameDisplay.blit(s, (RESULT_OVERLAY['x'], RESULT_OVERLAY['y'])) + + if self.winner_mark[result] is not None: + self.draw_color_box(border_color=BLACK, border_thickness=COLOR_BOX_BORDER_THICKNESS, + inner_color=self.winner_mark[result], + coords=(DISPLAY_WIDTH / 2 - OVERLAY_W / 2 + COLOR_BOX_SIZE, + DISPLAY_HEIGHT / 2 - COLOR_BOX_SIZE / 2), + size=(COLOR_BOX_SIZE, COLOR_BOX_SIZE)) + self.message_display(text='Wins!', pos=(DISPLAY_WIDTH / 2 + 0.5 * COLOR_BOX_SIZE, DISPLAY_HEIGHT / 2), + size=40, update=False) + else: + self.message_display(text='Tie!', size=40, update=False) + + pygame.display.update() + + # Wait until a mouse click before going back to main menu + clicked = False + while not clicked: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.quit_game() + elif event.type == pygame.MOUSEBUTTONUP: + clicked = True + return True # game is over def click_random_cell(self): random_cell = random.choice(list(self.allowed_cells)) self.subcell_clicked(random_cell) time.sleep(0.2) # sleep 1s so output can be checked - def get_best_engine_move(self): - return uct_multi(self.board, itermax=1000, verbose=False) - def get_game_input(self, game_type, mouse_pos): if game_type == GameType.SINGLE_PLAYER: if self.board.playerJustMoved == PLAYER_O: # X's turn todo allow user to select side to play if mouse_pos is not None: self.click_cell_under_mouse(mouse_pos) else: - board, move = self.get_best_engine_move() + board, move = uct_multi(self.board, itermax=1000, verbose=False) for cell in self.allowed_cells: if cell.board_idx == board and cell.cell_idx == move: self.subcell_clicked(cell) @@ -118,16 +129,17 @@ def get_game_input(self, game_type, mouse_pos): self.click_cell_under_mouse(mouse_pos) elif game_type == GameType.DEMO_MODE: - if self.board.playerJustMoved == PLAYER_O: - self.click_random_cell() - else: - board, move = self.get_best_engine_move() - for cell in self.allowed_cells: - if cell.board_idx == board and cell.cell_idx == move: - self.subcell_clicked(cell) - break - else: - raise Exception('Wrong engine move (move not in allowed moves) ({}{})'.format(board, move)) + self.click_random_cell() + # if self.board.playerJustMoved == PLAYER_O: + # self.click_random_cell() + # else: + # board, move = uct_multi(self.board, itermax=400, verbose=False) + # for cell in self.allowed_cells: + # if cell.board_idx == board and cell.cell_idx == move: + # self.subcell_clicked(cell) + # break + # else: + # raise Exception('Wrong engine move (move not in allowed moves) ({}{})'.format(board, move)) def game_loop(self, game_type): pygame.event.clear(pygame.MOUSEBUTTONUP) # clear all mouse clicks diff --git a/gui/gui_board.py b/gui/gui_board.py index c283c22..2db2b6e 100644 --- a/gui/gui_board.py +++ b/gui/gui_board.py @@ -39,6 +39,12 @@ class GuiBoard: PLAYER_X: RED, PLAYER_O: BLUE, } + # from the viewpoint of PLAYER_X + winner_mark = { + WIN: colors[PLAYER_X], + DRAW: None, + LOSS: colors[PLAYER_O], + } clicked_cells = set() # a set of all clicked cells all_cells = set() # a set of all created cells @@ -166,7 +172,16 @@ def draw_side_to_move(self, player_to_move): # todo remove magic numbers pygame.draw.rect(self.gameDisplay, BLACK, (OFFSET_X+8, OFFSET_Y-22, 24, 14)) pygame.draw.rect(self.gameDisplay, self.colors[player_to_move], (OFFSET_X+10, OFFSET_Y-20, 20, 10)) - self.message_display(text=' to move', pos=(OFFSET_X+60, OFFSET_Y-15), font='comicsansms', size=14) + self.message_display(text=' to move', pos=(OFFSET_X+55, OFFSET_Y-15), font='comicsansms', size=16) def draw_menu_animation(self): self.background.update() + + def draw_color_box(self, border_color, border_thickness, inner_color, coords, size): + """Coords: (x, y); Size (w, h)""" + x, y = coords # todo pass these as named tuples + w, h = size + # (OFFSET_X + 8, OFFSET_Y - 22, 24, 14) + pygame.draw.rect(self.gameDisplay, border_color, (x, y, w, h)) + pygame.draw.rect(self.gameDisplay, inner_color, + (x+border_thickness, y+border_thickness, w-2*border_thickness, h-2*border_thickness))