Skip to content

Commit

Permalink
- Tidied up make move logic (moved legality check into a separate met…
Browse files Browse the repository at this point in the history
…hod)

- Tidied up definitions from app.py -> constants.py (such as display size etc)
- Tidied up grid drawing by moving all parameters to constants.py and just iterating over parameters and drawing them
- Added new colors for blue and red marker
  • Loading branch information
AngelVI13 committed Apr 27, 2019
1 parent 71ea0af commit bae089b
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 154 deletions.
60 changes: 31 additions & 29 deletions board/ultimate_board.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,35 +36,26 @@ def __copy__(self):
_b.history = self.history.copy()
return _b

def make_move(self, move: int, board: int = None): # todo split in handlers depending on nextBoard and board values
"""Make a move to the specified board, if no board is specified
the move is done on the board indicated by nextBoard i.e forced
by the last played move.
@param move: move to play (i.e. index on the board)
@param board: index indicating which board to play the move on
# todo potentially only needed for console play, otherwise this will be handled inside gui
def _is_board_valid(self, board: int):
"""Determines if the provided (or not) board is valid, or in instances
where the next board is forced (from last player's move).
"""
self.playerJustMoved = -self.playerJustMoved

if self.nextBoard is None and board is None:
print('Need to provide a board idx at start of game')
return
return False, None

if self.nextBoard is not None:
# handle case when you can play on any board
if self.nextBoard == ANY_BOARD and board is None:
print('You need to provide a board to your move on since no forced board exists')
return
return False, None
elif self.nextBoard == ANY_BOARD and board is not None:
if self.pos[board].get_result() is not None:
print('You need to provide a board that does not yet have a result.')
return
return False, None
else:
self.pos[board].make_move(move, self.playerJustMoved)
self.history.append(Move(board_idx=board, move_idx=move))
# the move on the board represents the next board
self.nextBoard = move if self.pos[move].get_result() is None else ANY_BOARD
return
return True, board

# if we are forced to play on a board (due to opponents move)
# check if nextBoard has a winner. If it does => player should
Expand All @@ -73,28 +64,39 @@ def make_move(self, move: int, board: int = None): # todo split in handlers dep
if board is None:
print('The forced board already has a result on it.'
'Please choose a different board.')
return
return False, None
else:
if self.pos[board].get_result() is not None:
print('The chosen board has a result on it.'
'Please chose a different board.')
return
return False, None

self.pos[board].make_move(move, self.playerJustMoved)
self.history.append(Move(board_idx=board, move_idx=move))
# the move on the board represents the next board
self.nextBoard = move if self.pos[move].get_result() is None else ANY_BOARD
return
return True, board

# otherwise the forced board, doesn't have a result and the new move
# must be played on it
self.pos[self.nextBoard].make_move(move, self.playerJustMoved)
self.history.append(Move(board_idx=self.nextBoard, move_idx=move))
# the move on the board represents the next board
self.nextBoard = move if self.pos[move].get_result() is None else ANY_BOARD
return
return True, self.nextBoard

# if board is not None but nextBoard is None (i.e. start of game)
return True, board

def make_move(self, move: int, board: int = None):
"""Make a move to the specified board, if no board is specified
the move is done on the board indicated by nextBoard i.e forced
by the last played move.
@param move: move to play (i.e. index on the board)
@param board: index indicating which board to play the move on
"""
self.playerJustMoved = -self.playerJustMoved

valid, forced_board = self._is_board_valid(board)
if valid:
self._make_move(move=move, board=forced_board)

def _make_move(self, move: int, board: int):
"""Actually perform move when the validity of the move has already been determined."""

self.pos[board].make_move(move, self.playerJustMoved)
self.history.append(Move(board_idx=board, move_idx=move))
# the move on the board represents the next board
Expand Down
170 changes: 53 additions & 117 deletions gui/app.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,19 @@
# tutorial from https://pythonprogramming.net/drawing-objects-pygame-tutorial/?completed=/displaying-text-pygame-screen/
import pygame
from gui.colors import *
from gui.constants import *
from board.ultimate_board import *


class GuiBoard:
display_width = 600
display_height = 600
board_width = 480
board_height = 480
colors = {
PLAYER_X: RED,
PLAYER_O: BLUE,
}

border_thickness = 2
borders = {
'top_left': (border_thickness, border_thickness, -border_thickness, -border_thickness),
'top_right': (0, border_thickness, -border_thickness, -border_thickness),
'bottom_left': (border_thickness, 0, -border_thickness, -border_thickness),
'bottom_right': (0, 0, -border_thickness, -border_thickness),
'u_shape': (border_thickness, 0, -2 * border_thickness, -border_thickness),
'n_shape': (border_thickness, border_thickness, -2 * border_thickness, -border_thickness),
'o_shape': (border_thickness, border_thickness, -2 * border_thickness, -2 * border_thickness),
']_shape': (0, border_thickness, -border_thickness, -2 * border_thickness),
'[_shape': (border_thickness, border_thickness, -border_thickness, -2 * border_thickness),
}

clicked_cells = []
sub_grid_padding = 11
main_box_width = board_width / 3
main_box_height = board_height / 3
cell_width = main_box_width / 3
cell_height = main_box_height / 3
# offset for main grid from main window
offset_x, offset_y = (display_width - board_width) / 2, (display_height - board_height) / 2

def __init__(self):
pygame.init()
self.gameDisplay = pygame.display.set_mode((self.display_width, self.display_height))
self.gameDisplay = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
pygame.display.set_caption('Ultimate Tic Tac Toe')
self.clock = pygame.time.Clock()

Expand All @@ -52,7 +27,7 @@ def get_text_objects(text, font):
def message_display(self, text):
large_text = pygame.font.Font('freesansbold.ttf', 115)
text_surf, text_rect = self.get_text_objects(text, large_text)
text_rect.center = ((self.display_width / 2), (self.display_height / 2))
text_rect.center = ((DISPLAY_WIDTH / 2), (DISPLAY_HEIGHT / 2))
self.gameDisplay.blit(text_surf, text_rect)
pygame.display.update()

Expand All @@ -79,103 +54,64 @@ def quit_game():
quit()

def draw_subcell(self, border, border_colour, box_colour, highlight_colour, x, y, w, h, action=None):
try:
mod_x, mod_y, mod_w, mod_h = self.borders[border]
except KeyError:
raise
else:
pygame.draw.rect(self.gameDisplay, border_colour, (x, y, w, h))
# pygame.draw.rect(self.gameDisplay, box_colour, (x+mod_x, y+mod_y, w+mod_w, h+mod_h))
# 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()
# print(click)
# print(mouse, x, y, w, h)
if x + w > mouse[0] > x and y + h > mouse[1] > y:
pygame.draw.rect(self.gameDisplay, highlight_colour, (x + mod_x, y + mod_y, w + mod_w, h + mod_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

if click[0] == 1 and action is not None:
action(x + mod_x, y + mod_y, w + mod_w, h + mod_h)
else:
pygame.draw.rect(self.gameDisplay, box_colour, (x + mod_x, y + mod_y, w + mod_w, h + mod_h))
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))

def draw_sub_grid(self, border, border_colour, box_colour, highlight_colour, x, y, w, h):
try:
mod_x, mod_y, mod_w, mod_h = self.borders[border]
except KeyError:
raise
if click[0] == 1 and action is not None:
action(inner_x, inner_y, inner_w, inner_h)
else:
pygame.draw.rect(self.gameDisplay, border_colour, (x, y, w, h))
# update position and size values for inner rectangle
x, y = x + mod_x, y + mod_y
w, h = w + mod_w, h + mod_h
pygame.draw.rect(self.gameDisplay, box_colour, (x, y, w, h))
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):
# 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))
# update position and size values for inner rectangle
x, y = x + mod_x, y + mod_y
w, h = w + mod_w, h + mod_h
pygame.draw.rect(self.gameDisplay, box_colour, (x, y, w, h))

# calculate inner box for subgrid
cell_size = min(w, h)
x, y = x + 2 * self.sub_grid_padding, y + 2 * self.sub_grid_padding
w = h = cell_size - 4 * self.sub_grid_padding
x, y = x + 2 * SUB_GRID_PADDING, y + 2 * SUB_GRID_PADDING
w = h = cell_size - 4 * SUB_GRID_PADDING
cell_width_ = w / 3
cell_height_ = h / 3

self.draw_subcell('bottom_right', border_colour, box_colour, highlight_colour, x, y, cell_width_, cell_height_,
self.subcell_clicked)
self.draw_subcell('u_shape', border_colour, box_colour, highlight_colour, x + (w / 3), y, cell_width_,
cell_height_,
self.subcell_clicked)
self.draw_subcell('bottom_left', border_colour, box_colour, highlight_colour, x + w * (2 / 3), y, cell_width_,
cell_height_,
self.subcell_clicked)
# middle row
self.draw_subcell(']_shape', border_colour, box_colour, highlight_colour, x, y + (h / 3), cell_width_,
cell_height_,
self.subcell_clicked)
self.draw_subcell('o_shape', border_colour, box_colour, highlight_colour, x + w / 3, y + h / 3, cell_width_,
cell_height_,
self.subcell_clicked)
self.draw_subcell('[_shape', border_colour, box_colour, highlight_colour, x + w * (2 / 3), y + h / 3,
cell_width_,
cell_height_, self.subcell_clicked)
# bottom row
self.draw_subcell('top_right', border_colour, box_colour, highlight_colour, x, y + h * (2 / 3), cell_width_,
cell_height_,
self.subcell_clicked)
self.draw_subcell('n_shape', border_colour, box_colour, highlight_colour, x + w / 3, y + h * (2 / 3),
cell_width_,
cell_height_, self.subcell_clicked)
self.draw_subcell('top_left', border_colour, box_colour, highlight_colour, x + w * (2 / 3), y + h * (2 / 3),
cell_width_,
cell_height_, self.subcell_clicked)

def draw_main_grid(self, pos_x, pos_y):
# top row
self.draw_sub_grid(border='bottom_right', border_colour=BLACK, box_colour=WHITE, highlight_colour=GREEN,
x=pos_x, y=pos_y, w=self.main_box_width, h=self.main_box_height)
self.draw_sub_grid(border='u_shape', border_colour=BLACK, box_colour=WHITE, highlight_colour=GREEN,
x=pos_x + self.board_width / 3, y=pos_y, w=self.main_box_width, h=self.main_box_height)
self.draw_sub_grid(border='bottom_left', border_colour=BLACK, box_colour=WHITE, highlight_colour=GREEN,
x=pos_x + self.board_width * (2 / 3), y=pos_y, w=self.main_box_width, h=self.main_box_height)
# middle row
self.draw_sub_grid(border=']_shape', border_colour=BLACK, box_colour=WHITE, highlight_colour=GREEN,
x=pos_x, y=pos_y + self.board_height / 3, w=self.main_box_width, h=self.main_box_height)
self.draw_sub_grid(border='o_shape', border_colour=BLACK, box_colour=WHITE, highlight_colour=GREEN,
x=pos_x + self.board_width / 3, y=pos_y + self.board_height / 3, w=self.main_box_width,
h=self.main_box_height)
self.draw_sub_grid(border='[_shape', border_colour=BLACK, box_colour=WHITE, highlight_colour=GREEN,
x=pos_x + self.board_width * (2 / 3), y=pos_y + self.board_height / 3, w=self.main_box_width,
h=self.main_box_height)
# bottom row
self.draw_sub_grid(border='top_right', border_colour=BLACK, box_colour=WHITE, highlight_colour=GREEN,
x=pos_x, y=pos_y + self.board_height * (2 / 3), w=self.main_box_width,
h=self.main_box_height)
self.draw_sub_grid(border='n_shape', border_colour=BLACK, box_colour=WHITE, highlight_colour=GREEN,
x=pos_x + self.board_width / 3, y=pos_y + self.board_height * (2 / 3), w=self.main_box_width,
h=self.main_box_height)
self.draw_sub_grid(border='top_left', border_colour=BLACK, box_colour=WHITE, highlight_colour=GREEN,
x=pos_x + self.board_width * (2 / 3), y=pos_y + self.board_height * (2 / 3),
w=self.main_box_width,
h=self.main_box_height)

def subcell_clicked(self, x, y, w, h): # todo this should take value from ultimate board
positions = [
# top row
{'border': 'bottom_right', 'x': x, 'y': y},
{'border': 'u_shape', 'x': x + w * (1 / 3), 'y': y},
{'border': 'bottom_left', 'x': x + w * (2 / 3), 'y': y},

# middle row
{'border': ']_shape', 'x': x, 'y': y + (h / 3)},
{'border': 'o_shape', 'x': x + w * (1 / 3), 'y': y + (h / 3)},
{'border': '[_shape', 'x': x + w * (2 / 3), 'y': y + (h / 3)},

# bottom row
{'border': 'top_right', 'x': x, 'y': y + h * (2 / 3)},
{'border': 'n_shape', 'x': x + w * (1 / 3), 'y': y + h * (2 / 3)},
{'border': 'top_left', 'x': x + w * (2 / 3), 'y': y + h * (2 / 3)},
]

for position in positions:
self.draw_subcell(**position, border_colour=border_colour, box_colour=box_colour, w=cell_width_,
h=cell_height_, highlight_colour=highlight_colour, action=self.subcell_clicked)

def draw_main_grid(self):
for parameters in MAIN_GRID_DRAW_PARAMETERS:
self.draw_sub_grid(**parameters)

def subcell_clicked(self, x, y, w, h): # todo this should taken value from ultimate board
self.clicked_cells.append((x, y, w, h, self.player))
self.player *= -1

Expand All @@ -191,7 +127,7 @@ def game_loop(self):
self.quit_game()

self.gameDisplay.fill(WHITE)
self.draw_main_grid(self.offset_x, self.offset_y)
self.draw_main_grid()
self.draw_clicked_cells()
pygame.display.update()
self.clock.tick(60)
Expand Down
12 changes: 4 additions & 8 deletions gui/colors.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (250, 0, 0)
RED = (255, 94, 88) # (250, 0, 0)
RED_HIGHLIGHT = (255, 219, 212)
AVAILABLE_MOVE = (255, 255, 203) # Yellow
GREEN = (0, 200, 0)
BLUE = (0, 0, 250)
BLUE = (59, 214, 255) # (0, 0, 250)
YELLOW = (0, 250, 250)

BRIGHT_RED = (255, 0, 0)
BRIGHT_GREEN = (0, 255, 0)


# RED_RECT = 'ff5e58'
# RED_RECT_HIGHLIGHT = 'ffdbd4'
# BLUE_RECT = '3bd6ff'
# FORCED_BOARD = 'ffffcb'
Loading

0 comments on commit bae089b

Please sign in to comment.