## Micro Project: TIC-TAC-TOE, simple AI

In this Tic Tac Toe game, you play against a simple artificial intelligence. An artificial intelligence (or AI) is a computer program that can intelligently respond to the player’s moves. The artificial intelligence that plays Tic Tac Toe is really just a few lines of code.

How to play Tic-Tac-Toe:
Two people play Tic Tac Toe with paper and pencil. One player is X and the other player is O. Players take turns placing their X or O. If a player gets three of their marks on the board in a row, column or one of the two diagonals, they win. When the board fills up with neither player winning, the game ends in a draw.

The player makes their move by entering the number of the space they want to go. These numbers are in the same places as the number keys on your keyboard’s keypad.

———–
|  7  |  8  |  9  |
———–
|  4  |  5  |  6  |
———–
|  1  |  2  |  3  |
———–

Again, we make use of OOP. The entire game is enclosed inside a class, so that everything can be reused as need. Code is very simple and easy to follow, no need for extra explanation here.

```import random

class TicTacToe:
def __init__(self):
self.board = [' '] * 10
self.player_letter = ''
self.computer_letter = ''
self.game_status = 'CONTINUE'

def draw_board(self, board):
print "-" * 13
print "| " + board[7] + " | " + board[8] + " | " + board[9] + " |"
print "-" * 13
print "| " + board[4] + " | " + board[5] + " | " + board[6] + " |"
print "-" * 13
print "| " + board[1] + " | " + board[2] + " | " + board[3] + " |"
print "-" * 13

def is_free_space(self, board, index):
# check if a cell is free
return board[index] == ' '

def make_a_move(self, board, index, letter):
# mark a cell
board[index] = letter

def undo_move(self, board, index):
# 'unmark' a cell
board[index] = ' '

def player_choose_leter(self):
# ask player to choose either 'X' or 'O'
letter = ''
while not (letter == 'X' or letter == 'O'):
print 'Do you want to play X or O:'
letter = raw_input().strip()
return letter

def who_goes_first(self):
# simulate two faces of a coin
# face up = 1, computer move first
# face down = 0, player move first
if random.randint(0, 1) == 1:
return 'computer'
else:
return 'player'

def play_again(self):
# return true if player want to play again
print "Do you want to play again? (y,n)"
choice = raw_input().strip()
return choice.startswith('y')

def have_a_winner(self, board, letter):
# determine if the player with the letter 'letter' win
# there are 8 possible ways to win
# across the bottom
# across the middle
# across the top
# down the left side
# down the middle
# down the right side
# diagonals, respectievly
return (board[1] == letter and board[2] == letter and board[3] == letter) \
or (board[4] == letter and board[5] == letter and board[6] == letter) \
or (board[7] == letter and board[8] == letter and board[9] == letter) \
or (board[7] == letter and board[4] == letter and board[1] == letter) \
or (board[8] == letter and board[5] == letter and board[2] == letter) \
or (board[9] == letter and board[6] == letter and board[3] == letter) \
or (board[7] == letter and board[5] == letter and board[3] == letter) \
or (board[9] == letter and board[5] == letter and board[1] == letter)

def get_board_copy(self, board):
# copy the board
copy = []
for i in board:
copy.append(i)
return copy

def get_player_move(self, board):
# ask the player where they want to move
# return index of that move (1-9)
move = ''
while move not in '1 2 3 4 5 6 7 8 9'.split() or not self.is_free_space(board, int(move)):
print 'What\'s your next move? (1-9)'
move = raw_input().strip()
return int(move)

def choose_a_random_move(self, board, move_list):
# get all possible moves from the list
possible_moves = []
for i in move_list:
if self.is_free_space(board, i):
possible_moves.append(i)
if len(possible_moves) > 0:
# pick a random move
return random.choice(possible_moves)
else:
return None

def get_computer_move(self):
# use a simple algorithm to help computer make a move
# return index of the move

# copy the current board
copy_board = self.get_board_copy(self.board)
print 'length', len(copy_board)
# let computer try all possible moves to find a 'win move'
for i in range(1, len(copy_board)):
if self.is_free_space(copy_board, i):
self.make_a_move(copy_board, i, self.computer_letter)
if self.have_a_winner(copy_board, self.computer_letter):
# return the index of the winning move
return i
# undo the move
self.undo_move(copy_board, i)

# now, we cant find a winning move for the computer
# let's find out if player have a winning move
# if player has a winning move, we block that move
for i in range(1, len(copy_board)):
if self.is_free_space(copy_board, i):
self.make_a_move(copy_board, i, self.player_letter)
if self.have_a_winner(copy_board, self.player_letter):
print 'blocked'
return i
self.undo_move(copy_board, i)

# now, both player and computer don't have a winning move
# we randomly choose a possible move

# first, choose all possible moves of the conner
move = self.choose_a_random_move(self.board, [1, 3, 7, 9])
if move != None:
return move
# then if we cant move to corners, choose move to the middle
if self.is_free_space(self.board, 5):
return 5
# finally, move the the rest
move = self.choose_a_random_move(self.board, [2, 4, 6, 8])
return move

def is_board_full(self, board):
# check if the board is full
for i in range(1, len(board)):
if self.is_free_space(board, i):
return False
else:
return True

def start_game(self):
# game's logic is here

ended = False
while not ended:
# start the game by asking player to choose 'X' or 'O'
self.player_letter = self.player_choose_leter()
if self.player_letter == 'X':
self.computer_letter = 'O'
else:
self.computer_letter = 'X'
# then determine who's turn
turn = self.who_goes_first()
while self.game_status == 'CONTINUE':
if turn == 'computer':
print 'computer move : ',
computer_move = self.get_computer_move()
print computer_move
self.make_a_move(self.board, computer_move, self.computer_letter)
turn = 'player'
elif turn == 'player':
player_move = self.get_player_move(self.board)
self.make_a_move(self.board, player_move, self.player_letter)
turn = 'computer'
# print the board
self.draw_board(self.board)
# check if it's a draw
if self.is_board_full(self.board):
self.game_status = 'DRAW'
break
# check if there is a winner
if self.have_a_winner(self.board, self.computer_letter):
self.game_status = 'GAME_OVER'
break
if self.have_a_winner(self.board, self.player_letter):
self.game_status = 'WIN'
break

if self.game_status == 'GAME_OVER':
print 'Too bad, computer has beaten you! You lose.'
elif self.game_status == 'WIN':
print 'Good, you\'ve won the game.'
elif self.game_status == 'DRAW':
print 'It\'s a draw, try again to see if you can beat the computer.'

# check if player want to play again
if self.play_again():
ended = False
self.reset_game()
else:
ended = True

def reset_game(self):
self.board = [' ']*10
self.player_letter = ''
self.computer_letter = ''
self.game_status = 'CONTINUE'

if __name__ == '__main__':
game = TicTacToe()
game.start_game()

```