The game of Tic Tac Toe in Python

The last time I wrote an article we talked about the properties of a list. Many of you have pointed out some improvements that we incorporated in a later post addressing the issues some have you had with the code. This time, I would like to take on a larger program that utilizes some techniques we talked about as well as some new ones. In this article we are going to program the game of Tic Tac Toe in Python. I trust most people, if not everyone, have heard of the game and played it as children. Like always, I will be using Python 2.7.3 to test run my code. Some modification might be required for newer versions of Python.

The game of Tic Tac Toe is a perfect assignment for any programmers. You will be surprised how many times we go back to this game from a different angle. From this game you can learn turn based gaming programming, artificial intelligence , user interaction and many others topics. For now we are going to limit the game to non computer players. Here is a brief description of our assignment:

You are to implement the two player game of Tic Tac Toe. The program should display the board and prompt each user a move. The program should validate each move and handle any incorrect input. The entire user interaction should be command line based. Upon winning or a draw of the game, an appropriate message should be displayed acknowledging such condition.

The specs for this game are intentionally vague for the purpose of this article. We are going to tackle this problem one thing at a time. Let’s start by breaking down the program into some smaller blocks. Here is some rough pseudocode for us to work with:

  1. Setup Game
  2. Ask for user input on each turn
  3. Check if win condition met or no more moves
  4. Display the appropriate message and quit the game.

Let’s get started. First, let us think about how we can represent the board. A Tic Tac Toe board is a 3 X 3 grid. We could use a 2 dimensional list, or we can use one list with 9 elements that correspond to our 3 X 3 grid. So we are going to end up representing the board in Python in 1 list. Further more, we will set a value, -1, for an unclaimed cell, 0, for ‘O’ and 1 for ‘X’. This means that at any point in the game the list, board, will contain all the information we need for the game. Let’s take a look at the initial setup for the game:


board = []
	for i in range(9):
		board.append(-1)

That is it. This alone gives us a board with 9 cells all empty. Now let us tackle the display part. Although it is nice that we can represent the whole game in 1 variable, it is not very practical for the user. We want to display the game just like we would if we were to be playing on a pice of paper. To do so we will need to to print out a 3 X 3 grid from a 1 dimensional list. Let us first look at a quick example.

Let us consider that we have the list of numbers 1 to 9, and we want to print them out like this:

tic_tac_toe_map

To do so we can use this code:


a_list = [1,2,3,4,5,6,7,8,9]

for i in range(3):
	for j in range(3):
		print a_list[i*3+j],
	print 

The output would be:

wpid-3x3matrixpython-2013-11-12-15-13.png

How did this happen? Well, let us think about the values i and j take within the inner loop:

i_and_j_map_python

Now we want the values to be 0 to 8 to correspond to the list indexes of a_list. After playing with the numbers a little bit I found out that the formula i*3 + j gives me the values 0 to 8. Like this:

formulated_i_and_j_map_python

Cool. Let us now use this information to print out our Tic Tac Toe board. We already had the code to generate our board. Now lets see if we can print it. Consider the following function:


def print_board(board):

	print "The board look like this: \n"

	for i in range(3):
		print " ",
		for j in range(3):
			if board[i*3+j] == 1:
				print 'X',
			elif board[i*3+j] == 0:
				print 'O',	
			else:
				print ' ',
			
			if j != 2:
				print " | ",
		print
		
		if i != 2:
			print "-----------------"
		else: 
			print 

What will the function output? This:

wpid-tic_tact_tow_empty_board_python-2013-11-12-15-13.png
It is empty because all I did is generated an empty board using the code above. What would have happened if we sent it another list? Let’s investigate the code. It has a double loop like before, only instead of just printing out a_list[i*3+j] we take a look at it and print the appropriate value. If the list at that index contains the value 1 we print ‘X’ if it is 0, we print ‘O’. Otherwise it is just an empty space. The rest of the print statements are used to generate the lines. Note that we also use the comma (‘,’) to suppress the carriage return. You can read this article to find out more about Strings in Python.

So we completed our first part. We have a method to display the board and we have a setup for the game. Now let us see what is asking a user for input. Remember that we need to validate that the move is legal, i.e. the spot is not taken, and that the move is numeric between 1-9. Recall we are using a list to store the board. That means that will little effort we can ask the user which cell he would like to place a move in. Before we take user input, we will need to let the user know about this mapping of his/her moves. To do so let’s print out some instructions regarding the cell enumeration. Since we already have a function to print the board, with a little modification to it we can add an elif and write a small function to print the instructions, like this:


def print_instruction():
	print "Please use the following cell numbers to make your move"
	print_board([2,3,4,5,6,7,8,9,10])

If called, this function will print out:

wpid-tic_tac_toe_board_map_python_w_instructions-2013-11-12-15-13.png

Now, consider the following function that takes a player’s move and validates that it is a number between 1 to 9 and of numeric type:


def get_input(turn):

	valid = False
	while not valid:
		try:
			user = raw_input("Where would you like to place " + turn + " (1-9)? ")
			user = int(user)
			if user >= 1 and user <= 9:
				return user-1
			else:
				print "That is not a valid move! Please try again.\n"
				print_instruction()
		except Exception as e:
			print user + " is not a valid move! Please try again.\n"
			print_instruction()

This function will keep asking the user for a spot to place their move. If it is not numeric, we use a try-except block to catch the exception. If not between 1-9, we use a simple if-statement. Either way we notify the user of their error with an appropriate message. This is pretty straight forward. You always want to make sure the any user input is indeed valid. You should except the user to err. In this case, we accept user input as a sting and we try to convert it to an integer. Any input that is not between the numbers 1 to 9 will be considered invalid input and an appropriate message will be displayed.

wpid-python_err_input_ttt-2013-11-12-15-13.png

Great. We are actually almost done. The next part is how to check if a someone the Tic Tac Toe game. The function is not pretty, in fact it is hard coded for all possible board situations. It simply works. If there is a winner, the winners symbol will be returned, namely ‘X’ or ‘O’. If there is no winner, the function will return -1. Let us take a look:


def check_win(board):
	win_cond = ((1,2,3),(4,5,6),(7,8,9),(1,4,7),(2,5,8),(3,6,9),(1,5,9),(3,5,7))
	for each in win_cond:
		try:
			if board[each[0]-1] == board[each[1]-1] and board[each[1]-1] == board[each[2]-1]:
				return board[each[0]-1]
		except:
			pass
	return -1

So far we have talked about all the parts we need to make the game. Now it is time to put it all together. We will use all the functions we talked about and add some more logic. For example, we will have the game login in a while-loop. The loop will keep going while we do not have a winner. We will also keep track of the number of moves made. If less than 4 move were made, there is no sense to check for a win condition. If there were 9 moves made and no winner, the game is a tie. Other than that, the code should be fairly simple by now.


def main():
	
	# setup game
	# alternate turns
	# check if win or end
	# quit and show the board
	
	print_instruction()

	board = []
	for i in range(9):
		board.append(-1)

	win = False
	move = 0
	while not win:

		# print board
		print_board(board)
		print “Turn number “ + str(move+1)
		if move % 2 == 0:
			turn = ‘X’
		else:
			turn = ‘O’

		# get user input
		user = get_input(turn)
		while board[user] != -1:
			print “Invalid move! Cell already taken. Please try again.\n”
			user = get_input(turn)
		board[user] = 1 if turn == ‘X’ else 0

		# advance move and check for end game
		move += 1
		if move > 4:
			winner = check_win(board)
			if winner != -1:
				out = “The winner is “ 
				out += “X” if winner == 1 else “O” 
				out += “ ☺”
				quit_game(board,out)
			elif move == 9:
				quit_game(board,”No winner :(”)

Since the output of this will be a little long, I will let you have fun and download it yourself, download Command Line Tic Tac Toe for Python If I have time in the future, I will try to record my screen and add the output.

Have fun playing!

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.