Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Tic Tac Toe with Pygame
import pygame
import sys
import os
# SDL is the library which Pygame uses
# We use SDL to put the game window at the screen's centre
os.environ['SDL_VIDEO_CENTERED'] = '1'
SCREEN_SIZE = (800, 640)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (50, 255, 50)
BLUE = (50, 50, 255)
RED = (255, 50, 50)
REPLAY_MESSAGE = 'Press space to play again'
pygame.init()
board_font = pygame.font.SysFont('arial', 80)
game_over_font = pygame.font.SysFont('monospace', 80, bold=True)
replay_font = pygame.font.SysFont('monospace', 50)
screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.set_caption('Tic Tac Toe')
clock = pygame.time.Clock()
def draw_lines(screen, screen_size):
# Draw vertical lines
# Lines go from top of screen to bottom of screen
vertical_line_1 = int(screen_size[0] / 3) # lines mark 1/3 of the board
pygame.draw.line(screen, BLACK, (vertical_line_1, 0), (vertical_line_1, screen_size[0]), 4)
vertical_line_2 = vertical_line_1 * 2
pygame.draw.line(screen, BLACK, (vertical_line_2, 0), (vertical_line_2, screen_size[0]), 4)
# Draw horizontal lines
horizontal_line_1 = int(screen_size[1] / 3)
pygame.draw.line(screen, BLACK, (0, horizontal_line_1), (screen_size[0], horizontal_line_1), 4)
horizontal_line_2 = horizontal_line_1 * 2
pygame.draw.line(screen, BLACK, (0, horizontal_line_2), (screen_size[0], horizontal_line_2), 4)
def draw_letter(screen, letter, colour, position_rect):
player_choice = board_font.render(letter, False, colour)
# Fonts are draw to the top left of a Pygame rectangle
# This game would look better if they're drawn to the centre
# So after we generate a font image, create a special rectangle
# that's the center of the cell's rectangle. So the image will
# appear in the centre
choice_rect = player_choice.get_rect(center=position_rect.center)
# Blit is Pygame's way of drawing an image to a rectangle
screen.blit(player_choice, choice_rect)
def initialise_board(screen_size):
board = []
counter = 1
# First add 3 lists
for i in range(3):
board.append([])
# Then we calculate the width and height of each cell
# We want each cell to have an even amount of space
rect_width = int(screen_size[0] / 3)
rect_height = int(screen_size[1] / 3)
# Now we have a list of lists, each list item will have a place to play
# Outer list with contains each row
top = 0
for i in range(3):
left = 0
# Inner list which has 3 cells per row
for j in range(3):
board[i].append({
'played': False,
'player': str(counter), # Could be X or O, shows numbers by default
'rect': pygame.Rect(left, top, rect_width, rect_height)
})
# Add more to the left values so cells don't overlap
left += rect_width
# Increment counter so that it goes up to 9
counter += 1
# Ensure that the top values are increased for every row
top += rect_height
return board
def winner(board, player):
# Check win by row
for row in board:
if (row[0]['player'] == player and row[1]['player'] == player and
row[2]['player'] == player):
return True
# Check win by column
for i in range(3):
if (board[0][i]['player'] == player and board[1][i]['player'] == player and
board[2][i]['player'] == player):
return True
# Check diagonals
if (board[0][0]['player'] == player and board[1][1]['player'] == player and
board[2][2]['player'] == player):
return True
if (board[0][2]['player'] == player and board[1][1]['player'] == player and
board[2][0]['player'] == player):
return True
return False
def is_stalemate(board):
return all([all([r['played'] for r in row]) for row in board])
def update(game, keys_pressed):
someone_played = False
if ((keys_pressed[pygame.K_1] or keys_pressed[pygame.K_KP1])
and not game['board'][0][0]['played']):
game['board'][0][0]['played'] = True
game['board'][0][0]['player'] = game['player']
someone_played = True
elif ((keys_pressed[pygame.K_2] or keys_pressed[pygame.K_KP2])
and not game['board'][0][1]['played']):
game['board'][0][1]['played'] = True
game['board'][0][1]['player'] = game['player']
someone_played = True
elif ((keys_pressed[pygame.K_3] or keys_pressed[pygame.K_KP3])
and not game['board'][0][2]['played']):
game['board'][0][2]['played'] = True
game['board'][0][2]['player'] = game['player']
someone_played = True
elif ((keys_pressed[pygame.K_4] or keys_pressed[pygame.K_KP4])
and not game['board'][1][0]['played']):
game['board'][1][0]['played'] = True
game['board'][1][0]['player'] = game['player']
someone_played = True
elif ((keys_pressed[pygame.K_5] or keys_pressed[pygame.K_KP5])
and not game['board'][1][1]['played']):
game['board'][1][1]['played'] = True
game['board'][1][1]['player'] = game['player']
someone_played = True
elif ((keys_pressed[pygame.K_6] or keys_pressed[pygame.K_KP6])
and not game['board'][1][2]['played']):
game['board'][1][2]['played'] = True
game['board'][1][2]['player'] = game['player']
someone_played = True
elif ((keys_pressed[pygame.K_7] or keys_pressed[pygame.K_KP7])
and not game['board'][2][0]['played']):
game['board'][2][0]['played'] = True
game['board'][2][0]['player'] = game['player']
someone_played = True
elif ((keys_pressed[pygame.K_8] or keys_pressed[pygame.K_KP8])
and not game['board'][2][1]['played']):
game['board'][2][1]['played'] = True
game['board'][2][1]['player'] = game['player']
someone_played = True
elif ((keys_pressed[pygame.K_9] or keys_pressed[pygame.K_KP9])
and not game['board'][2][2]['played']):
game['board'][2][2]['played'] = True
game['board'][2][2]['player'] = game['player']
someone_played = True
return someone_played
def end_game_message(screen, screen_size, main_message, main_font,
replay_message, replay_font, colour):
main_text = main_font.render(main_message, False, colour)
main_rect = main_text.get_rect(center=(screen_size[0]/2, screen_size[1]/2))
screen.blit(main_text, main_rect)
replay_text = replay_font.render(replay_message, False, colour)
replay_rect = replay_text.get_rect(center=(screen_size[0]/2,
main_rect.bottom + 30))
screen.blit(replay_text, replay_rect)
def render(screen, screen_size, game, clock):
screen.fill(WHITE)
draw_lines(screen, screen_size)
# Draw the letters if they're played
for row in game['board']:
for cell in row:
if cell['player'] == 'X':
draw_letter(screen, 'X', BLUE, cell['rect'])
elif cell['player'] == 'O':
draw_letter(screen, 'O', GREEN, cell['rect'])
else:
draw_letter(screen, cell['player'], BLACK, cell['rect'])
if game['win']:
win_message = 'Player ' + game['player'] + ' won!'
end_game_message(screen, SCREEN_SIZE, win_message, game_over_font,
REPLAY_MESSAGE, replay_font, RED)
elif not game['win'] and game['stalemate']:
stale_message = 'Stalemate!'
end_game_message(screen, SCREEN_SIZE, stale_message, game_over_font,
REPLAY_MESSAGE, replay_font, RED)
pygame.display.update()
clock.tick(60)
def main():
def initialise():
return {
'board': initialise_board(SCREEN_SIZE),
'player': 'X',
'win': False,
'stalemate': False,
'change_player': False
}
game = initialise()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
keys_pressed = pygame.key.get_pressed()
if not (game['win'] or game['stalemate']):
game['change_player'] = update(game, keys_pressed)
else:
# Reset the game by pressing space bar
if keys_pressed[pygame.K_SPACE]:
game = initialise()
game['win'] = winner(game['board'], game['player'])
game['stalemate'] = is_stalemate(game['board'])
render(screen, SCREEN_SIZE, game, clock)
# Well if the last move didn't win/end the game, switch to the other player
if game['change_player'] and not (game['win'] or game['stalemate']):
if game['player'] == 'X':
game['player'] = 'O'
else:
game['player'] = 'X'
if __name__ == '__main__':
main()
cx-Freeze==5.0.2
pygame==1.9.3
import cx_Freeze
executables = [cx_Freeze.Executable('tictactoe.py')]
cx_Freeze.setup(
name='Tic Tac Toe',
version='1.0.0',
description='Tic Tac Toe for the masses',
options={'build_exe': {
'packages': ['pygame']
}},
executables=executables
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment