Last active
December 16, 2015 10:59
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
current_board() | |
answer = int(input('Please select where to place your marker: ')) | |
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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.