Skip to content

Instantly share code, notes, and snippets.

@alenbasic
Last active December 16, 2015 10:59
Show Gist options
  • Save alenbasic/5424379 to your computer and use it in GitHub Desktop.
Save alenbasic/5424379 to your computer and use it in GitHub Desktop.
A game of tic tac toe with in built AI. With a little tweak you could randomize the AI's strategy so the game won't always end in a draw.
import random
# the board we print out
board = ['[0]','[1]','[2]','[3]','[4]','[5]','[6]','[7]','[8]']
# the list of winning combinations
win_list = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]
X = '\033[92m' + ' X ' + '\033[0m' # makes the x green in *nix systems
O = '\033[91m' + ' O ' + '\033[0m' # makes the o red in *nix systems
# stylizes text
def style_text(string):
print('#' * 20)
print(string)
print('#' * 20)
# prints the current board layout
def current_board():
print board[0],board[1],board[2]
print board[3],board[4],board[5]
print board[6],board[7],board[8]
# checks the win list to see if 3 in a row has occurred
# if not, checks to see if a draw and if not does nothing
def check_board(marker,player):
for win in win_list:
if board[win[0]] + board[win[1]] + board[win[2]] == marker * 3:
style_text('Player %s wins' % player)
current_board()
exit(0)
if board.count(X) + board.count(O) == 9:
style_text('Draw!')
current_board()
exit(0)
def ai_turn(marker,player):
hot_spots = [0,2,6,8] # this is the list of the corners to pick from
combos = [1,3,5,7]
random.shuffle(combos)
random.shuffle(hot_spots) # we shuffle them so it's not predictable
# First, attempt to win if it has 2 in a row anywhere
for grid in win_list:
if board[grid[0]].count(O) + board[grid[1]].count(O) + board[grid[2]].count(O) == 2:
for win in grid:
if board[win] != O and board[win] != X:
return win
# Second, if it can't win it will see if it can block a combo
for grid in win_list:
if board[grid[0]].count(X) + board[grid[1]].count(X) + board[grid[2]].count(X) == 2:
for win in grid:
if board[win] != O and board[win] != X:
return win
# If there isn't a combo, see if you can block a dual set up
if board[1] == X and board[3] == X and board[0] != X and board[0] != O:
return 0
if board[1] == X and board[5] == X and board[2] != X and board[2] != O:
return 2
if board[7] == X and board[3] == X and board[6] != X and board[6] != O:
return 6
if board[7] == X and board[5] == X and board[8] != X and board[8] != O:
return 8
# If it can't win or block, it will try to go for the middle
if board[4] != X and board[4] != O:
return 4
# If it managed to get the middle, it'll combo via columns or rows
if board[4] == O:
for spot in combos:
if board[spot] != X and board[spot] != O:
return spot
# If the middle is taken, it will go for one of the corners
for spot in hot_spots:
if board[spot] != X and board[spot] != O:
return spot
# Failing all other options, it will go for an available square at random
while True:
i = random.randrange(len(board))
if board[i] != X and board[i] != O:
return i
def main():
global board
player = 'One'
marker = X
while True:
if marker == X:
style_text("Player %s's Turn" % player)
print
current_board()
print
answer = int(input('Please select where to place your marker: '))
print
else:
answer = ai_turn(marker,player)
if board[answer] == X or board[answer] == O:
print('Please select a square that is not already used.')
continue
else:
board[answer] = marker
check_board(marker,player)
if marker == X:
player = 'AI'
marker = O
else:
player = 'One'
marker = X
main()
@alenbasic
Copy link
Author

Updated the code so the markers are easier to spot, and added an extra piece of logic that closed a loophole, allowing the user to consistently win.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment