Python challenge - Tic-Tac-Toe Game
Author : Hamza EL YAAQOUBI
Introduction
The task is to write a program which pretends to play tic-tac-toe with the user.
To make it all easier for you, I’ve decided to simplify the game. Here are our assumptions:
-
The computer (i.e., your program) should play the game using ‘X’s
-
The user (e.g., you) should play the game using ‘O’s
-
The first move belongs to the computer - it always puts its first ‘X’ in the middle of the board
-
All the squares are numbered row by row starting with 1 (see the example session below for reference)
-
The user inputs their move by entering the number of the square they choose - the number must be valid, i.e., it must be an integer, it must be greater than 0 and less than 10, and it cannot point to a field which is already occupied
-
The program checks if the game is over - there are four possible verdicts: the game should continue, or the game ends with a tie, your win, or the computer’s win
-
The computer responds with its move and the check is repeated
-
I won’t implement any form of artificial intelligence - a random field choice made by the computer is good enough for the game
Requirement
-
We have to implement the following features :
-
The board should be stored as a three-element list, while each element is another three-element list (the inner lists represent rows) so that all of the squares may be accessed using the following syntax: board[row][column]
-
Each of the inner list’s elements can contain ‘O’, ‘X’, or a digit representing the square’s number (such a square is considered free)
-
The board’s appearance should be exactly the same as the one presented in the example bellow :
Solution
Step 1 : init the board
The following function init the Tic Tac Toe board :
def init_borad():
global current_player
board = [['' for x in range(3)] for i in range(3)]
pos = 1
for row in range(3):
for column in range(3):
board[row][column] = pos
pos += 1
board[1][1] = 'X'
current_player = 'O'
return board
Step 2 : display the board
To display the board as required, I will use the power of the print function by using its arguments sep and end.
def display_board(board):
print('+-------' * 3, '+', sep='')
for row in range(3):
print('| ' * 3, '|', sep='')
for col in range(3):
print('| ', str(board[row][col])+ ' ', end='')
print('|')
print('| ' * 3, '|', sep='')
print('+-------' * 3, '+', sep='')
Step 3 : Enter a move
The next function accepts the board current status, asks the user about their move, checks the input and updates the board according to the user’s decision
def enter_move(board):
turn_ok = False
while not turn_ok:
move = input('Enter a move (1 to 9) : ')
if len(move) != 1 or move <= '0' or move > '9':
print("Your move isn't correct, retry please ")
continue
move = int(move) - 10
row = move // 3
col = move % 3
if board[row][col] in ['O', 'X']:
print("Your move isn't correct, this square is occupied, please retry again !")
continue
turn_ok = not turn_ok
board[row][col] = 'O'
Step 4 : Draw a move
The function draws the computer’s move and updates the board.
Firstly, we have to build a list of all the free squares on the board. This list consists of tuples , while each tuple is a pair of row and column numbers.
def free_fileds(board):
free_squares = []
for row in range(3):
for column in range(3):
if board[row][column] not in ['O', 'X']:
free_squares.append((row, column))
return free_squares
We can now implement our function draw_move, it’s very easy :
def draw_move(board):
free_squares = free_fileds(board)
free_squares_length = len(free_squares)
if free_squares_length > 0:
random = randrange(free_squares_length)
row, col = free_squares[random]
board[row][col] = 'X'
Step 5 : Victory for
This function analyzes the board status in order to check if the player using ‘O’s or ‘X’s has won the game
To know if we have a winner or not, we must check three options :
- check if we have a winner in each row
- check if we have a winner in each column
- check ii we have a winner through diagonals
def victory_for(board, sign):
# check rows
for row in range(3):
if board[row][0] == sign and board[row][0] == board[row][1] and board[row][1]==board[row][2]:
return sign
# check columns
for column in range(3):
if board[0][column] == sign and board[0][column] == board[1][column] and board[0][column]==board[2][column]:
return sign
# check diagonals
if board[0][0] == sign and board[0][0] == board[1][1] and board[1][1] == board[2][2] or \
board[0][2] == sign and board[0][2] == board[1][1] and board[1][1] == board[2][0]:
return sign
return None
Step 6 : Run the game
I have added two functions to start and play the game.
Here’s the code :
def start_the_game():
game_status = '0'
while game_status != '-1':
print('*-----------------------------*')
print('* Welcome to TicTacToe game!', ' *')
print('* Enter 0 to start the game.', ' *')
print('* Enter -1 to end the game.', ' *')
print('*-----------------------------*')
game_status = input('Enter your choice : ')
if type(game_status) != "<class 'str'>" and game_status not in ['0', '-1']:
print('Please enter 0 or -1')
continue
if game_status == '-1':
break
# main program
board = init_borad()
play(board)
display_board(board)
if winner != None :
print()
print('Yohoo ! The player', winner, 'won the game !')
print()
else:
print('Tie game !')
def play(board):
free_squares = len(free_fileds(board))
global winner
global current_player
while free_squares != 0:
display_board(board)
if current_player == 'O':
# player turn
enter_move(board)
else:
# computer turn
draw_move(board)
game_winner = victory_for(board, current_player)
if game_winner != None:
winner = game_winner
break
else:
if current_player == 'O':
current_player = 'X'
else:
current_player = 'O'
free_squares = len(free_fileds(board))
Finally, run the game :
start_the_game()