Practice Python

Beginner Python exercises

11 September 2016

Tic Tac Toe Game Solutions

Exercise 29

This exercise is Part 4 of 4 of the Tic Tac Toe exercise series. The other exercises are: Part 1, Part 2, and Part 3.

In 3 previous exercises, we built up a few components needed to build a Tic Tac Toe game in Python:

  1. Draw the Tic Tac Toe game board
  2. Checking whether a game board has a winner
  3. Handle a player move from user input

The next step is to put all these three components together to make a two-player Tic Tac Toe game!

Sample solution

This exercise is unique because it relies on the output of the other exercises that need to be put together to make the final solution. The goal is to get practice with functions and how they work together in larger programs.

The 3 exercises above suggest breaking your Tic Tac Toe game into (at least) 4 functions:

  1. A function for drawing the game board (and the location of pieces)
  2. A function for checking whether there is a winner in the game
  3. A function for adding user input into the game state
  4. A main function that calls the others and plays the game

The way to solve this problem is to look back at all 3 solutions to the previous exercises, copy them into one file, and modify what you had before. This is a different way of coding than coding an entire program from scratch, and can often save a lot of time.

For my solution, I decided to copy all the functions from the older exercises into one file, and work from the main game logic from Part 3. Part 3 almost made you write the entire game - the main loop asking users for positions and input is already there, so starting from that point and modifying will let you finish this exercise in 30 minutes!

Here is what my code looks like after copying in my solutions to Part 1, Part 2, and Part 3 of this exercise:

def draw_line(width, edge, filling):
print(filling.join([edge] * (width + 1)))
def draw_board(width, height):
draw_line(width, " ", "__")
for i in range(height):
draw_line(width, "|", "__")
print("\n")
def display_winner(player):
if player == 0:
print("Tie")
else:
print("Player " + str(player) + " wins!")
def check_row_winner(row):
"""
Return the player number that wins for that row.
If there is no winner, return 0.
"""
if row[0] == row[1] and row[1] == row[2]:
return row[0]
return 0
def get_col(game, col_number):
return [game[x][col_number] for x in range(3)]
def get_row(game, row_number):
return game[row_number]
def check_winner(game):
game_slices = []
for index in range(3):
game_slices.append(get_row(game, index))
game_slices.append(get_col(game, index))
# check diagonals
down_diagonal = [game[x][x] for x in range(3)]
up_diagonal = [game[0][2], game[1][1], game[2][0]]
game_slices.append(down_diagonal)
game_slices.append(up_diagonal)
for game_slice in game_slices:
winner = check_row_winner(game_slice)
if winner != 0:
display_winner(winner)
return winner
display_winner(winner)
return winner
def start_game():
return [[0, 0, 0] for x in range(3)]
def display_game(game):
d = {2: "O", 1: "X", 0: " "}
game_string = []
for row_num in range(3):
new_row = []
for col_num in range(3):
new_row.append(d[game[row_num][col_num]])
game_string.append(new_row)
print(game_string)
def add_piece(game, player, row, column):
"""
game: game state
player: player number
row: 0-index row
column: 0-index column
"""
game[row][column] = player
return game
def convert_input_to_coordinate(user_input):
return user_input - 1
def switch_player(player):
if player == 1:
return 2
else:
return 1
if __name__ == '__main__':
game = start_game()
display_game(game)
player = 1
# go on forever
while True:
print("Currently player: " + str(player))
row = convert_input_to_coordinate(int(input("Which row? (start with 1) ")))
column = convert_input_to_coordinate(int(input("Which column? (start with 1) ")))
game = add_piece(game, player, row, column)
display_game(game)
player = switch_player(player)

After some modifications:

The final product is here:

def draw_line(width, edge, filling):
print(filling.join([edge] * (width + 1)))
def display_winner(player):
if player == 0:
print("Tie")
else:
print("Player " + str(player) + " wins!")
def check_row_winner(row):
"""
Return the player number that wins for that row.
If there is no winner, return 0.
"""
if row[0] == row[1] and row[1] == row[2]:
return row[0]
return 0
def get_col(game, col_number):
return [game[x][col_number] for x in range(3)]
def get_row(game, row_number):
return game[row_number]
def check_winner(game):
game_slices = []
for index in range(3):
game_slices.append(get_row(game, index))
game_slices.append(get_col(game, index))
# check diagonals
down_diagonal = [game[x][x] for x in range(3)]
up_diagonal = [game[0][2], game[1][1], game[2][0]]
game_slices.append(down_diagonal)
game_slices.append(up_diagonal)
for game_slice in game_slices:
winner = check_row_winner(game_slice)
if winner != 0:
return winner
return winner
def start_game():
return [[0, 0, 0] for x in range(3)]
def display_game(game):
d = {2: "O", 1: "X", 0: "_"}
draw_line(3, " ", "_")
for row_num in range(3):
new_row = []
for col_num in range(3):
new_row.append(d[game[row_num][col_num]])
print("|" + "|".join(new_row) + "|")
def add_piece(game, player, row, column):
"""
game: game state
player: player number
row: 0-index row
column: 0-index column
"""
game[row][column] = player
return game
def check_space_empty(game, row, column):
return game[row][column] == 0
def convert_input_to_coordinate(user_input):
return user_input - 1
def switch_player(player):
if player == 1:
return 2
else:
return 1
def moves_exist(game):
for row_num in range(3):
for col_num in range(3):
if game[row_num][col_num] == 0:
return True
return False
if __name__ == '__main__':
game = start_game()
display_game(game)
player = 1
winner = 0 # the winner is not yet defined
# go on forever
while winner == 0 and moves_exist(game):
print("Currently player: " + str(player))
available = False
while not available:
row = convert_input_to_coordinate(int(input("Which row? (start with 1) ")))
column = convert_input_to_coordinate(int(input("Which column? (start with 1) ")))
available = check_space_empty(game, row, column)
game = add_piece(game, player, row, column)
display_game(game)
player = switch_player(player)
winner = check_winner(game)
display_winner(winner)

Happy hacking!

Enjoying Practice Python?


Explore Yubico
Explore Yubico