Tic-Tac-Toe

Tac-tac-toe (see above) is a simple game that we can use to try to play against a smart computer opponent. In the example above X moves first and ends up winning by getting three in a row. Tic-tac-toe has been implemented in various ways, including using Tinkertoys (original copy on WayBackMachine).

We will develop this program in stages:

  1. Represent the board as a list and display the board

  2. Allow playing the game, where the computer randomly chooses an open square for its move

  3. After each move check for a win

  4. Incrementally make the computer "smart".

See a sample run below along with some ideas on how to make the program "smart".

What Running the Program Looks Like

Welcome to Tic-tac-toe!

Computer starts with "X" and human plays "O"


0. Board:

_ _ _ 1 2 3

_ _ _ 4 5 6

_ _ _ 7 8 9

Computer places X in square 7


1. Board:

_ _ _ 1 2 3

_ _ _ 4 5 6

X _ _ 7 8 9

Place O in square: 5


2. Board:

_ _ _ 1 2 3

_ O _ 4 5 6

X _ _ 7 8 9

Computer places X in square 9


3. Board:

_ _ _ 1 2 3

_ O _ 4 5 6

X _ X 7 8 9

Place O in square: 8


4. Board:

_ _ _ 1 2 3

_ O _ 4 5 6

X O X 7 8 9

Computer places X in square 6


5. Board:

_ _ _ 1 2 3

_ O X 4 5 6

X O X 7 8 9

Place O in square: 3


6. Board:

_ _ O 1 2 3

_ O X 4 5 6

X O X 7 8 9

Computer places X in square 1


7. Board:

X _ O 1 2 3

_ O X 4 5 6

X O X 7 8 9

Place O in square: 4


8. Board:

X _ O 1 2 3

O O X 4 5 6

X O X 7 8 9

Computer places X in square 2


9. Board:

X X O 1 2 3

O O X 4 5 6

X O X 7 8 9

Thanks for playing

A "Smart" Version

Tic Tac Toe board configurations

You can use the text below to create boards corresponding to the 48 different board configurations. In the lines of code below an underscore '_' represents we don't care what is in that spot, and a 'B' represents a blank spot. The number given after each configuration is the move 'X' should make if a match is made on that configuration. For instance:

board6 = ( 'X','_','_','X','_','_','B','_','_',7) // note the rightmost 7

represents the board shown at left below:

Board Position Numbers

------ ----------------

X,_,_, 1 2 3

X,_,_, 4 5 6

B,_,_, 7 8 9

where the 7 means that 'X' should move into position 7. This makes sense, since that move for 'X' gives 3 pieces in a row in that column, and 'X' wins.


I suggest you implement a function called something like compare_boards. You should send this function the current board, as well as the board you are comparing against. This function should then return the stored integer value to which to move (7 in the example above) or some other value (0 or -1) if the boards don't match. Getting this to work properly will save you the effort of having to write a bazillion (to use a technical term) if statements.


Board Patterns With Suggested Move

# Each pattern can be split across three lines to look like a board, creating a list of lists:

patterns = [

# For first move, use the center if available, else a corner.

['.','.','.',

'.','_','.',

'.','.','.', 5],


['_','_','_',

'_','O','_',

'_','_','_', 1],

# First check for all patterns where X can win on this move,

# since X has 2 out of 3 in a row, with the 3rd square is blank.

['.','.','.',

'.','.','.',

'X','X','_', 9],


['.','.','.',

'.','.','.',

'_','X','X', 7],


['.','.','_',

'.','.','X',

'.','.','X', 3],


['.','.','X',

'.','.','X',

'.','.','_', 9],


['_','X','X',

'.','.','.',

'.','.','.', 1],


['X','X','_',

'.','.','.',

'.','.','.', 3],


['X','.','.',

'X','.','.',

'_','.','.', 7],


['_','.','.',

'X','.','.',

'X','.','.', 1],


['X','.','.',

'_','.','.',

'X','.','.', 4],


['.','.','.',

'.','.','.',

'X','_','X', 8],


['.','.','X',

'.','.','_',

'.','.','X', 6],


['X','_','X',

'.','.','.',

'.','.','.', 2],


['X','.','.',

'.','X','.',

'.','.','_', 9],


['_','.','.',

'.','X','.',

'.','.','X', 1],


['.','.','_',

'.','X','.',

'X','.','.', 3],


['.','.','X',

'.','X','.',

'_','.','.', 7],


['X','.','.',

'.','_','.',

'.','.','X', 5],


['.','.','X',

'.','_','.',

'X','.','.', 5],


['.','X','.',

'.','X','.',

'.','_','.', 8],


['.','_','.',

'.','X','.',

'.','X','.', 2],


['.','.','.',

'X','X','_',

'.','.','.', 6],


['.','.','.',

'_','X','X',

'.','.','.', 4],


['.','X','.',

'.','_','.',

'.','X','.', 5],


['.','.','.',

'X','_','X',

'.','.','.', 5],


# After checking for an X win above, now see if O can win on the

# next move and so needs to be blocked

['.','.','.',

'.','.','.',

'O','O','_', 9],


['.','.','.',

'.','.','.',

'_','O','O', 7],


['.','.','_',

'.','.','O',

'.','.','O', 3],


['.','.','O',

'.','.','O',

'.','.','_', 9],


['_','O','O',

'.','.','.',

'.','.','.', 1],


['O','O','_',

'.','.','.',

'.','.','.', 3],


['O','.','.',

'O','.','.',

'_','.','.', 7],


['_','.','.',

'O','.','.',

'O','.','.', 1],


['O','.','.',

'_','.','.',

'O','.','.', 4],


['.','.','.',

'.','.','.',

'O','_','O', 8],


['.','.','O',

'.','.','_',

'.','.','O', 6],


['O','_','O',

'.','.','.',

'.','.','.', 2],


['O','.','.',

'.','O','.',

'.','.','_', 9],


['_','.','.',

'.','O','.',

'.','.','O', 1],


['.','.','_',

'.','O','.',

'O','.','.', 3],


['.','.','O',

'.','O','.',

'_','.','.', 7],


['O','.','.',

'.','_','.',

'.','.','O', 5],


['.','.','O',

'.','_','.',

'O','.','.', 5],


['.','O','.',

'.','O','.',

'.','_','.', 8],


['.','_','.',

'.','O','.',

'.','O','.', 2],


['.','.','.',

'O','O','_',

'.','.','.', 6],


['.','.','.',

'_','O','O',

'.','.','.', 4],


['.','O','.',

'.','_','.',

'.','O','.', 5],


['.','.','.',

'O','_','O',

'.','.','.', 5],


# If X's first move is to a middle square on a side and O moves

# into the center, ensure that the next move for X is an adjacent corner,

# since if it moves opposite the original X then O will eventually win.

['_','X','_',

'_','O','_',

'_','_','_', 1],


['_','_','_',

'X','O','_',

'_','_','_', 7],


['_','_','_',

'_','O','_',

'_','X','_', 9],


['_','_','_',

'_','O','X',

'_','_','_', 3],

# At this point neither X nor O can win right away, so try

# to set up a winning configuration where we can create an

# intersecting set of 2 X's, leading to an X win on the next move.

# First intersecting pattern of two edges.

['X','.','.',

'.','O','.',

'_','X','.', 7],


['.','.','.',

'.','O','X',

'X','.','_', 9],


['.','X','_',

'.','O','.',

'.','.','X', 3],


['_','.','X',

'X','O','.',

'.','.','.', 1],


# ... and again with the L/R transposed image

['.','.','X',

'.','O','.',

'_','X','.', 7],


['X','.','.',

'.','O','X',

'.','.','_', 9],


['.','X','_',

'.','O','.',

'X','.','.', 3],


['_','.','.',

'X','O','.',

'.','.','X', 1],


# Second intersecting pattern with middle intersecting a diagonal through center

['X','.','.',

'.','_','.',

'O','X','.', 5],


['.','.','.',

'.','_','X',

'X','.','O', 5],


['.','X','O',

'.','_','.',

'.','.','X', 5],


['O','.','X',

'X','_','.',

'.','.','.', 5],


# ... and again with the L/R transposed image

['.','.','X',

'.','_','.',

'.','X','O', 5],


['X','.','O',

'.','_','X',

'.','.','.', 5],


['O','X','.',

'.','_','.',

'X','.','.', 5],


['.','.','.',

'X','_','.',

'O','.','X', 5],


# Third intersecting pattern, intersecting two middle rows/cols

# through the center.

['.','_','.',

'X','_','_',

'.','X','.', 5],


['.','_','.',

'_','_','X',

'.','X','.', 5],


['.','X','.',

'_','_','X',

'.','_','.', 5],


['.','X','.',

'X','_','_',

'.','_','.', 5],


# Still third intersecting pattern similar to the 4 above, except

# the middle is already taken but three adjacent corners are still

# free, so we create two sets that intersect in the corner.

['_','.','.',

'X','O','.',

'_','X','_', 7],


['.','.','_',

'.','O','X',

'_','X','_', 9],


['_','X','_',

'.','O','X',

'.','.','_', 3],


['_','X','_',

'X','O','.',

'_','.','.', 1],


# Fourth intersecting pattern, intersecting a diagonal with a middle

['.','_','_',

'.','_','.',

'X','X','O', 5],


['_','.','O',

'_','_','X',

'.','.','X', 5],


['O','X','X',

'.','_','.',

'_','_','.', 5],


['X','.','.',

'X','_','_',

'O','.','_', 5],


# Fifth intersecting pattern of a diagonal and an edge.

['.','O','_',

'O','X','X',

'_','_','_', 3],


['_','X','_',

'O','X','_',

'.','O','_', 1],


['_','_','_',

'X','X','O',

'_','O','.', 7],


['_','O','.',

'_','X','O',

'_','X','_', 9],


# ... L/R mirror transposition of the above

['_','O','.',

'X','X','O',

'_','_','_', 1],


['.','O','_',

'O','X','_',

'_','X','_', 7],


['_','_','_',

'O','X','X',

'.','O','_', 9],


['_','X','_',

'_','X','O',

'_','O','.', 3],

]