Skip to content

Commit

Permalink
- Changed handling of mouse press. Now it is monitored in mainloop on…
Browse files Browse the repository at this point in the history
… MOUSE_UP and not during drawing of subcells

- Added highlighting of grid when a result is present
- Added handling of game over and automatic restart afterwards.
- Moved some magic numbers to constants
- Removed highlighting of cell on mouse hover
  • Loading branch information
AngelVI13 committed May 1, 2019
1 parent cd11c26 commit ab0c799
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 34 deletions.
2 changes: 2 additions & 0 deletions gui/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
RED_HIGHLIGHT = (255, 219, 212)
GREEN = (0, 200, 0)
BLUE = (59, 214, 255)
BLUE_HIGHLIGHT = (164, 217, 221)
GREY = (170, 191, 193)
YELLOW = (0, 250, 250)

BRIGHT_RED = (255, 0, 0)
Expand Down
20 changes: 10 additions & 10 deletions gui/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from itertools import count

from gui.colors import *
from board.constants import PLAYER_X, PLAYER_O, DRAW


DISPLAY_WIDTH = 600
Expand Down Expand Up @@ -40,48 +41,47 @@
# offset for main grid from main window
OFFSET_X, OFFSET_Y = (DISPLAY_WIDTH - BOARD_WIDTH) / 2, (DISPLAY_HEIGHT - BOARD_HEIGHT) / 2

HIGHLIGHT_COLOR = GREEN
GRID_RESULT_COLORS = {
PLAYER_X: RED_HIGHLIGHT,
PLAYER_O: BLUE_HIGHLIGHT,
DRAW: GREY
}

BORDER_COLOR = BLACK
BOX_COLOR = WHITE

# In these parameters the values for x & y will the added to the current position computed for each grid cell
MAIN_GRID_DRAW_PARAMETERS = [
{'border': Grid.TOP_LEFT, 'border_colour': BORDER_COLOR, 'box_colour': BOX_COLOR,
'highlight_colour': HIGHLIGHT_COLOR,
'x': OFFSET_X, 'y': OFFSET_Y,
'w': MAIN_BOX_WIDTH, 'h': MAIN_BOX_HEIGHT},
{'border': Grid.TOP_MIDDLE, 'border_colour': BORDER_COLOR, 'box_colour': BOX_COLOR,
'highlight_colour': HIGHLIGHT_COLOR,
'x': OFFSET_X + BOARD_WIDTH / 3, 'y': OFFSET_Y,
'w': MAIN_BOX_WIDTH, 'h': MAIN_BOX_HEIGHT},
{'border': Grid.TOP_RIGHT, 'border_colour': BORDER_COLOR, 'box_colour': BOX_COLOR,
'highlight_colour': HIGHLIGHT_COLOR,
'x': OFFSET_X + BOARD_WIDTH * (2 / 3), 'y': OFFSET_Y,
'w': MAIN_BOX_WIDTH, 'h': MAIN_BOX_HEIGHT},
# middle row
{'border': Grid.MIDDLE_LEFT, 'border_colour': BORDER_COLOR, 'box_colour': BOX_COLOR,
'highlight_colour': HIGHLIGHT_COLOR,
'x': OFFSET_X, 'y': OFFSET_Y + BOARD_HEIGHT / 3,
'w': MAIN_BOX_WIDTH, 'h': MAIN_BOX_HEIGHT},
{'border': Grid.MIDDLE_MIDDLE, 'border_colour': BORDER_COLOR, 'box_colour': BOX_COLOR,
'highlight_colour': HIGHLIGHT_COLOR,
'x': OFFSET_X + BOARD_WIDTH / 3, 'y': OFFSET_Y + BOARD_HEIGHT / 3,
'w': MAIN_BOX_WIDTH, 'h': MAIN_BOX_HEIGHT},
{'border': Grid.MIDDLE_RIGHT, 'border_colour': BORDER_COLOR, 'box_colour': BOX_COLOR,
'highlight_colour': HIGHLIGHT_COLOR,
'x': OFFSET_X + BOARD_WIDTH * (2 / 3), 'y': OFFSET_Y + BOARD_HEIGHT / 3,
'w': MAIN_BOX_WIDTH, 'h': MAIN_BOX_HEIGHT},
# bottom row
{'border': Grid.BOTTOM_LEFT, 'border_colour': BORDER_COLOR, 'box_colour': BOX_COLOR,
'highlight_colour': HIGHLIGHT_COLOR,
'x': OFFSET_X, 'y': OFFSET_Y + BOARD_HEIGHT * (2 / 3),
'w': MAIN_BOX_WIDTH, 'h': MAIN_BOX_HEIGHT},
{'border': Grid.BOTTOM_MIDDLE, 'border_colour': BORDER_COLOR, 'box_colour': BOX_COLOR,
'highlight_colour': HIGHLIGHT_COLOR,
'x': OFFSET_X + BOARD_WIDTH / 3, 'y': OFFSET_Y + BOARD_HEIGHT * (2 / 3),
'w': MAIN_BOX_WIDTH, 'h': MAIN_BOX_HEIGHT},
{'border': Grid.BOTTOM_RIGHT, 'border_colour': BORDER_COLOR, 'box_colour': BOX_COLOR,
'highlight_colour': HIGHLIGHT_COLOR,
'x': OFFSET_X + BOARD_WIDTH * (2 / 3), 'y': OFFSET_Y + BOARD_HEIGHT * (2 / 3),
'w': MAIN_BOX_WIDTH, 'h': MAIN_BOX_HEIGHT},
]

FRAMES_PER_SECOND = 60
PAUSE_BEFORE_GAME_RESTART = 4 # seconds
61 changes: 51 additions & 10 deletions gui/gui_app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import time
from itertools import cycle, chain

from gui.gui_board import *
Expand All @@ -7,13 +8,16 @@ class Gui(GuiBoard):
def __init__(self):
super(Gui, self).__init__()
self.board = UltimateBoard()
self.on_cell_clicked = self.subcell_clicked
self.allowed_cells = set()
self.grids_with_result = set() # all grids that have a result on them

def subcell_clicked(self, x, y, w, h, board, move):
# do not provide player just yet, only do so when we are sure we can click the cell
cell = Cell(x, y, w, h, player=None, board_idx=board, cell_idx=move)
def restart_game(self):
self.board = UltimateBoard()
self.allowed_cells = set()
self.grids_with_result = set()

def subcell_clicked(self, cell):
# do not provide player just yet, only do so when we are sure we can click the cell
if cell in self.clicked_cells: # if cell already clicked -> do nothing
return

Expand All @@ -22,11 +26,18 @@ def subcell_clicked(self, x, y, w, h, board, move):

cell.player = self.board.playerJustMoved * -1
self.clicked_cells.add(cell)

move, board = cell.cell_idx, cell.board_idx
self.board.make_move(move, board)
print(board, move)
print(self.board)
self.allowed_cells = self.find_allowed_cells()

result = self.board.pos[board].get_result()
if result is not None:
for grid in self.all_grids:
if grid.board_idx == board:
grid.player = result # add the player who won to the grid that he won
self.grids_with_result.add(grid)

def find_allowed_cells(self):
allowed_cells = set() # clear currently allowed moves

Expand All @@ -40,8 +51,20 @@ def find_allowed_cells(self):

def draw_allowed_moves(self, color):
for cell in self.allowed_cells:
pygame.draw.rect(self.gameDisplay, color,
(cell.pos_x, cell.pos_y, cell.width, cell.height))
pygame.draw.rect(self.gameDisplay, color, (cell.pos_x, cell.pos_y, cell.width, cell.height))

def click_cell_under_mouse(self, pos):
mouse_x, mouse_y = pos
for cell in self.all_cells:
if cell.pos_x < mouse_x < cell.pos_x + cell.width and cell.pos_y < mouse_y < cell.pos_y + cell.height:
self.subcell_clicked(cell)
break # don't bother finishing up the loop -> break on match

def draw_results(self): # todo this is the same as draw_all moves? parameterize
for grid in self.grids_with_result:
# print(grid.player, GRID_RESULT_COLORS[grid.player])
pygame.draw.rect(self.gameDisplay, GRID_RESULT_COLORS[grid.player],
(grid.pos_x, grid.pos_y, grid.width, grid.height))

def game_loop(self):
# set up an endless cycle of B values (rgB) for highlighting moves
Expand All @@ -53,21 +76,39 @@ def game_loop(self):
# print(event)
if event.type == pygame.QUIT:
self.quit_game()
elif event.type == pygame.MOUSEBUTTONUP:
pos = pygame.mouse.get_pos()
self.click_cell_under_mouse(pos)

brightness = next(brightness_iter)
highlight = (255, 255, brightness) # yellow highlight used to accent available moves

self.gameDisplay.fill(WHITE)
self.draw_main_grid()

# todo check for game end here as well. Mind not have allowed cells because game is over
# todo check for game end here as well. Might not have allowed cells because game is over
if not self.allowed_cells:
self.allowed_cells = self.find_allowed_cells()

self.draw_clicked_cells()
self.draw_results()
self.draw_allowed_moves(highlight)
pygame.display.update()
self.clock.tick(60)
self.clock.tick(FRAMES_PER_SECOND)

# todo factor out repetitive code below
if self.board.get_result(player_jm=PLAYER_X) == WIN:
self.message_display(text='X won!')
time.sleep(PAUSE_BEFORE_GAME_RESTART)
self.restart_game()
elif self.board.get_result(player_jm=PLAYER_O) == WIN:
self.message_display(text='O won!')
time.sleep(PAUSE_BEFORE_GAME_RESTART)
self.restart_game()
elif self.board.get_result(player_jm=PLAYER_O) == DRAW:
self.message_display(text='Tie!')
time.sleep(PAUSE_BEFORE_GAME_RESTART)
self.restart_game()


if __name__ == '__main__':
Expand Down
26 changes: 12 additions & 14 deletions gui/gui_board.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class GuiBoard:

clicked_cells = set() # a set of all clicked cells
all_cells = set() # a set of all created cells
on_cell_clicked = None # callback method for action on cell clicked
all_grids = set() # a set of all subgrids

def __init__(self):
pygame.init()
Expand Down Expand Up @@ -89,13 +89,11 @@ def quit_game():
pygame.quit()
quit()

def draw_subcell(self, border, border_colour, box_colour, highlight_colour, x, y, w, h, grid_idx, action=None):
def draw_subcell(self, border, border_colour, box_colour, x, y, w, h, grid_idx):
# Draw bounding box of cell
mod_x, mod_y, mod_w, mod_h = BORDERS[border]
pygame.draw.rect(self.gameDisplay, border_colour, (x, y, w, h))

mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
inner_x, inner_y, inner_w, inner_h = x + mod_x, y + mod_y, w + mod_w, h + mod_h

# keep track of all cells on the board
Expand All @@ -104,15 +102,11 @@ def draw_subcell(self, border, border_colour, box_colour, highlight_colour, x, y
if cell not in self.all_cells:
self.all_cells.add(cell)

if x + w > mouse[0] > x and y + h > mouse[1] > y:
pygame.draw.rect(self.gameDisplay, highlight_colour, (inner_x, inner_y, inner_w, inner_h))
# draw inner box of cell (main content)
pygame.draw.rect(self.gameDisplay, box_colour, (inner_x, inner_y, inner_w, inner_h))

if click[0] == 1 and action is not None:
action(inner_x, inner_y, inner_w, inner_h, grid_idx, border)
else:
pygame.draw.rect(self.gameDisplay, box_colour, (inner_x, inner_y, inner_w, inner_h))

def draw_sub_grid(self, border, border_colour, box_colour, highlight_colour, x, y, w, h):
def draw_sub_grid(self, border, border_colour, box_colour, x, y, w, h):
# todo maybe turn this into a method to clean up the logic
# draw bounding box of subgrid
mod_x, mod_y, mod_w, mod_h = BORDERS[border]
pygame.draw.rect(self.gameDisplay, border_colour, (x, y, w, h))
Expand All @@ -121,6 +115,11 @@ def draw_sub_grid(self, border, border_colour, box_colour, highlight_colour, x,
w, h = w + mod_w, h + mod_h
pygame.draw.rect(self.gameDisplay, box_colour, (x, y, w, h))

# keep track of all subgrids. NOTE: here 'border' is the index of the subgrid on the main grid.
grid = Cell(pos_x=x, pos_y=y, width=w, height=h, player=None, board_idx=border, cell_idx=None)
if grid not in self.all_grids:
self.all_grids.add(grid)

# calculate inner box for subgrid
cell_size = min(w, h)
x, y = x + 2 * SUB_GRID_PADDING, y + 2 * SUB_GRID_PADDING
Expand Down Expand Up @@ -148,8 +147,7 @@ def draw_sub_grid(self, border, border_colour, box_colour, highlight_colour, x,
for position in positions:
# here border is the index of which grid all of the cells are part of
self.draw_subcell(**position, border_colour=border_colour, box_colour=box_colour, w=cell_width_,
h=cell_height_, highlight_colour=highlight_colour, grid_idx=border,
action=self.on_cell_clicked)
h=cell_height_, grid_idx=border)

def draw_main_grid(self):
for parameters in MAIN_GRID_DRAW_PARAMETERS:
Expand Down

0 comments on commit ab0c799

Please sign in to comment.