Transcript Friday 26 October (Tic Tac Toe)
| categories: Transcripts
Today we will examine a program that plays Tic Tac Toe.
It may look scary but if you break it down you'll see that each piece is understandable. This version simply chooses randomly from the available legal moves.
'''Super simple random tic tac toe player'''
import random
def allMoves(position, player):
'''enumerate all possible moves for player'''
moves = []
for i, p in enumerate(position):
if p == ' ':
moves.append(position[:i] + player + position[i + 1:])
return moves
def isWin(p):
'''determine if the current position is a win'''
return ((p[0] != ' ' and (p[0] == p[1] == p[2] or p[0] == p[3] == p[6] or
p[0] == p[4] == p[8])) or
(p[1] != ' ' and (p[1] == p[4] == p[7])) or
(p[2] != ' ' and (p[2] == p[5] == p[8] or p[2] == p[4] == p[6])) or
(p[3] != ' ' and (p[3] == p[4] == p[5])) or
(p[6] != ' ' and (p[6] == p[7] == p[8])))
def show(p):
'''print the current position'''
print '-' * 7
for i in range(0, 9, 3):
print '|' + p[i] + '|' + p[i + 1] + '|' + p[i + 2] + '|'
print '-' * 7
def play(verbose=True):
'''play a game of tic tac toe, return the winner or 'T' for tie'''
position = ' ' * 9 # initially empty board
players = 'XO'
for turn in range(9): # at most 9 turns in a game
player = players[turn % 2] # players alternate turns
choices = allMoves(position, player)
position = random.choice(choices) # choose a random move
if verbose:
print turn, player, 'moves'
show(position)
if isWin(position):
if verbose:
print player, 'wins'
return player
return 'T'
# play a ton of games to see who has the advantage
N = 100000 # number of trials to run
advantage = 0 # advantage for X
tie = 0 # count of tie games
for i in range(N):
winner = play(False)
if winner == 'X':
advantage += 1
elif winner == 'O':
advantage -= 1
else:
tie += 1
print 'Advantage X =', float(advantage) / N
print 'Ties =', float(tie) / N
I chose to represent the state of the game as a 9 character string consisting of space for empty cells, X, or O. I could have used an array, or list, or something else. The choice is arbitrary but has implications everywhere else in the code. You might try making your own version using a 3-tuple of 3 character strings. Then the indexing in isWin will be much cleaner. Of course you'll have to change the other functions as well because my choice of data structure permeates the code.
You may download the code random-player.py
The last bit of the script is relevant to assignment 5. You see we are running the function many times to estimate the statistics of the game under the assumption of terrible players.