Tic Tac Toe
Designing the Program
Tic Tac Toe is a very easy and short game to play on paper. In our Tic Tac Toe computer game, we'll let the player choose if they want to be X or O, randomly choose who goes first, and then let the player and computer take turns making moves on the board. Here is what a flow chart of this game could look like:
You can see a lot of the boxes on the left side of the chart are what happens during the player's turn. The right side of the chart shows what happens on the computer's turn. The player has an extra box for drawing the board because the computer doesn't need the board printed on the screen. After the player or computer makes a move, we check if they won or caused a tie, and then the game switches turns. If either the computer or player ties or wins the game, we ask the player if they want to play again.
Representing the Board as Data
First, we need to figure out how we are going to represent the board as a variable. On paper, the Tic Tac Toe board is drawn as a pair of horizontal lines and a pair of vertical lines, with either an X, O, or empty space in each of the nine spaces.
In our program, we are going to represent the Tic Tac Toe board as a list of strings. Each string will represent one of the nine positions on the board. We will give a number to each of the spaces on the board. To make it easier to remember which index in the list is for which piece, we will mirror the numbers on the keypad of our keyboard. See Figure 10-2.
The strings will either be 'X' for the X player, 'O' for the O player, or a space string ' ' to mark a spot on the board where no one has marked yet. The index of the string in the list will also be the number of the space on the board.
So if we had a list with ten strings named board, then board[7] would be the top-left square on the board (either an X, O, or blank space). board[5] would be the very center. When the player types in which place they want to move, they will type a number from 1 to 9. (Because there is no 0 on the keypad, we will just ignore the string at index 0 in our list.)
Game AI
When we talk about how our AI behaves, we will be talking about which types of spaces on the board it will move on. Just to be clear, we will label three types of spaces on the Tic Tac Toe board: corners, sides, and the center. Figure 10-3 is a chart of what each space is:
The AI for this game will follow a simple algorithm. An algorithm is a series of instructions to compute something. This is a very loose In the case of our Tic Tac Toe AI's algorithm, the series of steps will determine which is the best place to move. There is nothing in the code that says, "These lines are an algorithm." like there is with a function's def-block. We just consider the AI algorithm as all the code that is used in our program that determines the AI's next move.
Our algorithm will have the following steps:
- First, see if there is a move the computer can make that will win the game. If there is, take that move. Otherwise, go to step 2.
- See if there is a move the player can make that will cause the computer to lose the game. If there is, we should move there to block the player. Otherwise, go to step 3.
- Check if any of the corner spaces (spaces 1, 3, 7, or 9) are free. (We always want to take a corner piece instead of the center or a side piece.) If no corner piece is free, then go to step 4.
- Check if the center is free. If so, move there. If it isn't, then go to step 5.
- Move on any of the side pieces (spaces 2, 4, 6, or 8). There are no more steps, because if we have reached step 5 the side spaces are the only spaces left.
This all takes place in the "Get computer's move." box on our flow chart. We could add this information to our flow chart like this:
Рис. 10.4. The five steps of the "Get computer's move" algorithm. The arrows leaving go to the "Check if computer won" box.
We will implement this algorithm as code in our getComputerMove() function, and the other functions that getComputerMove() calls.
How the Code Works: Lines 1 to 81
Now that we know about how we want the program to work, let's look at what each line does.
The Start of the Program
1. # Tic Tac Toe 2. 3. import random
The first couple of lines are a comment and importing the random module so we can use the randint() function in our game.
Printing the Board on the Screen
5. def drawBoard(board): 6. # This function prints out the board that it was passed. 7. 8. # "board" is a list of 10 strings representing the board (ignore index 0) 9. print(' | |') 10. print(' ' + board[7] + ' | ' + board[8] + ' | ' + board[9]) 11. print(' | |') 12. print ( '-----------') 13. print ( ' | | ' ) 14. print(' ' + board[4] + ' | ' + board [5] + ' | ' + board[6]) 15. print(' | |') 16. print ( '-----------') 17. print(' | | ' ) 18. print(' ' + board[1] + ' | ' + board[2] + ' | ' + board[3]) 19. print(' | |')
This function will print out the game board, marked as directed by the board parameter. Remember that our board is represented as a list of ten strings, where the string at index 1 is the mark on space 1 on the Tic Tac Toe board. (And remember that we ignore the string at index 0, because the spaces are labeled with numbers 1 to 9.) Many of our functions will work by passing the board as a list of ten strings to our functions. Be sure to get the spacing right in the strings that are printed, otherwise the board will look funny when it is printed on the screen.
Just as an example, here are some values that the board parameter could have (on the left) and what the drawBoard() function would print out:
The second to last board filled with X's could not possibly have happened (unless the X player skipped all of the O player's turns!) And the last board has strings of digits instead of X and O, which are invalid strings for the board. But the drawBoard() function doesn't care. It just prints the board parameter that it was passed. Computer programs only do exactly what you tell them, even if you tell them the wrong things to do. We will just make sure these invalid strings are not put into the passed list in the first place.
Letting the Player be X or O
21. def inputPlayerLetter(): 22. # Let's the player type which letter they want to 23. # Returns a list with the player's letter as the first item, and the computer's letter as the second. 24. letter = ' ' 25. while not (letter == 'X' or letter == 'O') : 26. print('Do you want to be X or O?') 27. letter = input().upper() be.
The inputPlayerLetter() is a simple function. It asks if the player wants to be X or O, and will keep asking the player (with the while loop) until the player types in an X or O. Notice on line 26 that we automatically change the string returned by the call to input() to uppercase letters with the upper() string method.
The while loop's condition contains parentheses, which means the expression inside the parentheses is evaluated first. If the letter variable was set to 'X', the expression would evaluate like this:
while not (letter == 'X' or letter == 'O'):
while not ('X' == 'X' or 'X' == 'O'):
while not (True or False):
while not True:
while False:
As you can see, if letter has the value 'X' or 'O', then the loop's condition will be False and lets the program execution continue.
29. # the first element in the tuple is the player's letter, the second is the computer's letter. 30. if letter == 'X': 31. return ['X', 'O'] 32. else: 33. return ['O', 'X']
This function returns a list with two items. The first item (that is, the string at index 0) will be the player's letter, and the second item (that is, the string at index 1) will be the computer's letter. This if-else statement chooses the appropriate list to return.