TicTacToe 的 Minimax 算法(但每个玩家只能拥有 3 个 tacs)
Minimax Algorithm with TicTacToe (But each player can only have 3 tacs on board)
我目前正在制作一款 TicTacToe 游戏,该游戏使用 Minimax 算法进行玩家对战。截至目前,代码在 PvE 上只有困难模式。这是一个使用 Minimax 算法无法战胜的工作机器人。但是,我需要找到一种方法来合并特殊规则...
每位玩家一次只能在棋盘上放置 3 个 'tacs'。一旦达到 3,他们就必须将 tac 从一个位置移动到另一个位置。我不太确定如何实现这个,有人可以给我一些想法吗?
"""
TicTacToe - 3 symbols max
By Gage Gunn (???), Trevor Purta (Player vs. Computer), Toby Howie (Player vs. Player), Rachel Powers (Computer vs. Computer)
"""
# -------- Modules --------
import os
import time
import random
# -------- Global Variables --------
human = 'O'
bot = 'X'
amount_of_x = 0
amount_of_o = 0
ID = '' #Detecting which game mode (PvP, PvE, EvE)
ID2 = '' #Detecting which difficulty in PvE
ID3 = '' #Detecting which difficulty in EvE
# -------- Functions --------
def printBoard(board):
print(board[1] + ' | ' + board[2] + ' | ' + board[3] + ' 1 | 2 | 3')
print(board[4] + ' | ' + board[5] + ' | ' + board[6] + ' 4 | 5 | 6')
print(board[7] + ' | ' + board[8] + ' | ' + board[9] + ' 7 | 8 | 9')
print('\n')
def spaceIsFree(position):
if board[position] == ' ':
return True
else:
return False
def insertLetter(letter, position):
if spaceIsFree(position):
board[position] = letter
printBoard(board)
if (checkDraw()):
print("Draw!")
exit()
if checkForWin():
if letter == 'X':
print("Bot wins!")
exit()
else:
print("Player wins!")
exit()
return
else:
print("Can't insert there!")
position = int(input("Please enter new position: "))
insertLetter(letter, position)
return
def checkForWin():
if (board[1] == board[2] and board[1] == board[3] and board[1] != ' '):
return True
elif (board[4] == board[5] and board[4] == board[6] and board[4] != ' '):
return True
elif (board[7] == board[8] and board[7] == board[9] and board[7] != ' '):
return True
elif (board[1] == board[4] and board[1] == board[7] and board[1] != ' '):
return True
elif (board[2] == board[5] and board[2] == board[8] and board[2] != ' '):
return True
elif (board[3] == board[6] and board[3] == board[9] and board[3] != ' '):
return True
elif (board[1] == board[5] and board[1] == board[9] and board[1] != ' '):
return True
elif (board[7] == board[5] and board[7] == board[3] and board[7] != ' '):
return True
else:
return False
def checkWhichMarkWon(mark):
if board[1] == board[2] and board[1] == board[3] and board[1] == mark:
return True
elif (board[4] == board[5] and board[4] == board[6] and board[4] == mark):
return True
elif (board[7] == board[8] and board[7] == board[9] and board[7] == mark):
return True
elif (board[1] == board[4] and board[1] == board[7] and board[1] == mark):
return True
elif (board[2] == board[5] and board[2] == board[8] and board[2] == mark):
return True
elif (board[3] == board[6] and board[3] == board[9] and board[3] == mark):
return True
elif (board[1] == board[5] and board[1] == board[9] and board[1] == mark):
return True
elif (board[7] == board[5] and board[7] == board[3] and board[7] == mark):
return True
else:
return False
def checkDraw():
for key in board.keys():
if (board[key] == ' '):
return False
return True
def playerMove():
position = int(input("Enter the position for 'O': "))
insertLetter(human, position)
return
def compMove():
bestScore = -800
bestMove = 0
for key in board.keys():
if (board[key] == ' '):
board[key] = bot
score = minimax(board, 0, False)
board[key] = ' '
if (score > bestScore):
bestScore = score
bestMove = key
insertLetter(bot, bestMove)
return
def minimax(board, depth, isMaximizing):
if (checkWhichMarkWon(bot)):
return 1
elif (checkWhichMarkWon(human)):
return -1
elif (checkDraw()):
return 0
if (isMaximizing):
bestScore = -800
for key in board.keys():
if (board[key] == ' '):
board[key] = bot
score = minimax(board, depth + 1, False)
board[key] = ' '
if (score > bestScore):
bestScore = score
return bestScore
else:
bestScore = 800
for key in board.keys():
if (board[key] == ' '):
board[key] = human
score = minimax(board, depth + 1, True)
board[key] = ' '
if (score < bestScore):
bestScore = score
return bestScore
board = {1: ' ', 2: ' ', 3: ' ',
4: ' ', 5: ' ', 6: ' ',
7: ' ', 8: ' ', 9: ' '}
def pick_game_type(): #Pick PvP, PvE, EvE
global ID
print("""
First, Pick which game mode you would like to play!
(Player vs. Player [1], Player vs. Computer [2], Computer vs. Computer [3])
""")
type_choice = input('> ')
if type_choice == "1": #Set global ID for [1]
ID = "1"
elif type_choice == "2": #Set global ID for [2]
ID = "2"
elif type_choice == "3": #Set global ID for [3]
ID = "3"
# -------- Script --------
os.system('cls') #Clear console
print("""
Welcome to Wacky Tacky Toe, Tac, Tic!
By Gage Gunn, Trevor Purta, Toby Howie, and Rachel Power with an s
""")
pick_game_type() #Choose gamemode
if ID == '1': #PvP Chosen
pass
elif ID == '2': #PvE Chosen
os.system('cls')
print('''
Welcome to Player vs Computer! In this version of Tic, Tac, Toe, each player can have a maximum of 3 tacs on the board at a time!
Decide which difficuly you would like to play? (Easy [1] or Hard [2])''')
ID2 = input('> ')
valid_input = False
while not valid_input: #Checks validity of ID2
if ID2 in ['1', '2']:
valid_input = True
else:
ID2 = input('> ')
if ID2 == '1': #Easy was chosen
pass
elif ID2 == '2':
print('You have chosen hard! You are X, the computer is O. The computer will go first')
while not checkForWin():
compMove()
playerMove()
elif ID == '3': #PvE Chosen
pass
您需要将游戏玩法的组件隔离成可重复使用的函数,这些函数可以组合起来模拟 minimax 计算的动作。
因为你需要模拟,所以最好有一个独立的数据结构来表示游戏(棋盘)的状态,包括轮到谁玩(我使用一个 10 个字符的字符串,其中第一个角色是当前玩家,其他 9 个角色是棋盘的当前状态。
您需要实现的第一件事是模拟移动(返回新的游戏状态)的函数:
def playMove(game,toPos,fromPos):
played = [game[0] if i==toPos else "." if i==fromPos else p
for i,p in enumerate(game)]
return "".join(played)
你还需要一个切换当前播放器的功能。这需要分开,以便您可以在模拟对手的动作之前轻松评估当前玩家的结果:
def switchPlayer(game):
return "XO"[game[0]=="X"]+game[1:] # returns a new game state
为了递归地模拟走法,您需要一个函数来给出可能走法的列表。根据您的游戏规则,移动被定义为目标位置 (toPos) 和可选的原点位置 (fromPos)。对于前 3 个动作,将没有原点(让 fromPos = toPos for those)
def getMoves(game):
player,*board = game
moves = [(i,i) for i,p in enumerate(board,1) if p=="."] # 1st 3 moves
if board.count(player)==3: # moves 4+
origins = [r for r,p in enumerate(board,1) if p==player ]
moves = [ (i,r) for i,_ in moves for r in origins] # add origins
return moves
对于模拟和实际游戏,您需要一个函数来确定游戏是否获胜:
winPatterns = [(1,2,3),(4,5,6),(7,8,9),(1,4,7),(2,5,8),(3,6,9),(1,5,9),(3,5,7)]
def isWin(game):
return any(all(game[i]==game[0] for i in p) for p in winPatterns)
对一步棋的结果进行评级可能是一些复杂的公式,但为了简单起见,我们只说获胜是 1,而不是获胜是零。 minimax 函数将递归地模拟动作,根据“最近的”决定性动作给它们一个评级(1 表示获胜,-1 表示失败)。
maxDepth = 6 # maximum depth = computer's skill
memo = dict() # memoization (for performance)
def minimax(game,depth=maxDepth):
if (game,depth) in memo: # known rating at this depth
return memo[game,depth]
if isWin(game): return 1 # no moves after a win (base condition)
if not depth: return 0 # limit depth (avoids infinite loops)
oGame = switchPlayer(game) # will simulate opponent's moves
oRatings = [] # opponent's minimax ratings
for move in getMoves(oGame):
played = playMove(oGame,*move) # simulate
oRatings.append(minimax(played,depth-1)) # get rating
rating = -max(oRatings or [1]) # worst countermove
for d in range(1,depth+1):
memo[game,d]=rating # memorize for this depth and lower
return rating
因为游戏数据结构是可散列的(即字符串),它可以用于记忆,大大提高了 minimax 函数的性能。
使用 minimax 函数,您可以确定计算机玩家(具有最高 minimax 评级的玩家)的最佳着法:
def bestMove(game):
return max(getMoves(game),key=lambda m:minimax(playMove(game,*m)))
您可以在获得 max() 之前随机选择移动,当不止一个移动具有最高评分时随机选择最佳移动
将它们放在一个游戏循环中:
def printBoard(game):
for r in range(1,10,3):
print("("+") (".join(game[r:r+3])+")",list(range(r,r+3)))
from random import sample
while True:
player,computer = sample("XOXO",2) # random starter, random computer
game = player + "."*9
while True:
printBoard(game)
if isWin(game): break
game = switchPlayer(game)
player = game[0]
if player == computer:
toPos,fromPos = bestMove(game)
print(f"Computer plays {player} at {toPos}",end=" ")
print(f"from {fromPos}"*(fromPos!=toPos))
else:
strMoves = [(str(t),str(f)) for t,f in getMoves(game)]
while True:
fromPos = toPos = input(f"Position to play for {player}: ")
if not toPos in (f for f,_ in strMoves):
print("invalid position"); continue
if game[1:].count(player)<3: break
fromPos = input(f"Position to remove {player} from: ")
if (toPos,fromPos) not in strMoves:
print("invalid move")
else: break
game = playMove(game,int(toPos),int(fromPos))
print( f"{player}'s WIN !!!\n")
if input("play again (y/n)") != "y": break
print()
样本运行:
(.) (.) (.) [1, 2, 3]
(.) (.) (.) [4, 5, 6]
(.) (.) (.) [7, 8, 9]
Computer plays O at 5
(.) (.) (.) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(.) (.) (.) [7, 8, 9]
Position to play for X: 1
(X) (.) (.) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(.) (.) (.) [7, 8, 9]
Computer plays O at 3
(X) (.) (O) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(.) (.) (.) [7, 8, 9]
Position to play for X: 7
(X) (.) (O) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(X) (.) (.) [7, 8, 9]
Computer plays O at 4
(X) (.) (O) [1, 2, 3]
(O) (O) (.) [4, 5, 6]
(X) (.) (.) [7, 8, 9]
Position to play for X: 6
(X) (.) (O) [1, 2, 3]
(O) (O) (X) [4, 5, 6]
(X) (.) (.) [7, 8, 9]
Computer plays O at 9 from 3
(X) (.) (.) [1, 2, 3]
(O) (O) (X) [4, 5, 6]
(X) (.) (O) [7, 8, 9]
Position to play for X: 3
Position to remove X from: 7
(X) (.) (X) [1, 2, 3]
(O) (O) (X) [4, 5, 6]
(.) (.) (O) [7, 8, 9]
Computer plays O at 2 from 4
(X) (O) (X) [1, 2, 3]
(.) (O) (X) [4, 5, 6]
(.) (.) (O) [7, 8, 9]
Position to play for X: 8
Position to remove X from: 3
(X) (O) (.) [1, 2, 3]
(.) (O) (X) [4, 5, 6]
(.) (X) (O) [7, 8, 9]
Computer plays O at 3 from 2
(X) (.) (O) [1, 2, 3]
(.) (O) (X) [4, 5, 6]
(.) (X) (O) [7, 8, 9]
Position to play for X: 7
Position to remove X from: 8
(X) (.) (O) [1, 2, 3]
(.) (O) (X) [4, 5, 6]
(X) (.) (O) [7, 8, 9]
Computer plays O at 4 from 9
(X) (.) (O) [1, 2, 3]
(O) (O) (X) [4, 5, 6]
(X) (.) (.) [7, 8, 9]
Position to play for X:
Position to play for X: 9
Position to remove X from: 1
(.) (.) (O) [1, 2, 3]
(O) (O) (X) [4, 5, 6]
(X) (.) (X) [7, 8, 9]
Computer plays O at 8 from 4
(.) (.) (O) [1, 2, 3]
(.) (O) (X) [4, 5, 6]
(X) (O) (X) [7, 8, 9]
Position to play for X: 2
Position to remove X from: 6
(.) (X) (O) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(X) (O) (X) [7, 8, 9]
Computer plays O at 1 from 3
(O) (X) (.) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(X) (O) (X) [7, 8, 9]
Position to play for X: 3
Position to remove X from: 7
(O) (X) (X) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(.) (O) (X) [7, 8, 9]
Computer plays O at 6 from 8
(O) (X) (X) [1, 2, 3]
(.) (O) (O) [4, 5, 6]
(.) (.) (X) [7, 8, 9]
Position to play for X: 7
Position to remove X from: 2
(O) (.) (X) [1, 2, 3]
(.) (O) (O) [4, 5, 6]
(X) (.) (X) [7, 8, 9]
Computer plays O at 4 from 1
(.) (.) (X) [1, 2, 3]
(O) (O) (O) [4, 5, 6]
(X) (.) (X) [7, 8, 9]
O's WIN !!!
play again (y/n) ? n
我目前正在制作一款 TicTacToe 游戏,该游戏使用 Minimax 算法进行玩家对战。截至目前,代码在 PvE 上只有困难模式。这是一个使用 Minimax 算法无法战胜的工作机器人。但是,我需要找到一种方法来合并特殊规则...
每位玩家一次只能在棋盘上放置 3 个 'tacs'。一旦达到 3,他们就必须将 tac 从一个位置移动到另一个位置。我不太确定如何实现这个,有人可以给我一些想法吗?
"""
TicTacToe - 3 symbols max
By Gage Gunn (???), Trevor Purta (Player vs. Computer), Toby Howie (Player vs. Player), Rachel Powers (Computer vs. Computer)
"""
# -------- Modules --------
import os
import time
import random
# -------- Global Variables --------
human = 'O'
bot = 'X'
amount_of_x = 0
amount_of_o = 0
ID = '' #Detecting which game mode (PvP, PvE, EvE)
ID2 = '' #Detecting which difficulty in PvE
ID3 = '' #Detecting which difficulty in EvE
# -------- Functions --------
def printBoard(board):
print(board[1] + ' | ' + board[2] + ' | ' + board[3] + ' 1 | 2 | 3')
print(board[4] + ' | ' + board[5] + ' | ' + board[6] + ' 4 | 5 | 6')
print(board[7] + ' | ' + board[8] + ' | ' + board[9] + ' 7 | 8 | 9')
print('\n')
def spaceIsFree(position):
if board[position] == ' ':
return True
else:
return False
def insertLetter(letter, position):
if spaceIsFree(position):
board[position] = letter
printBoard(board)
if (checkDraw()):
print("Draw!")
exit()
if checkForWin():
if letter == 'X':
print("Bot wins!")
exit()
else:
print("Player wins!")
exit()
return
else:
print("Can't insert there!")
position = int(input("Please enter new position: "))
insertLetter(letter, position)
return
def checkForWin():
if (board[1] == board[2] and board[1] == board[3] and board[1] != ' '):
return True
elif (board[4] == board[5] and board[4] == board[6] and board[4] != ' '):
return True
elif (board[7] == board[8] and board[7] == board[9] and board[7] != ' '):
return True
elif (board[1] == board[4] and board[1] == board[7] and board[1] != ' '):
return True
elif (board[2] == board[5] and board[2] == board[8] and board[2] != ' '):
return True
elif (board[3] == board[6] and board[3] == board[9] and board[3] != ' '):
return True
elif (board[1] == board[5] and board[1] == board[9] and board[1] != ' '):
return True
elif (board[7] == board[5] and board[7] == board[3] and board[7] != ' '):
return True
else:
return False
def checkWhichMarkWon(mark):
if board[1] == board[2] and board[1] == board[3] and board[1] == mark:
return True
elif (board[4] == board[5] and board[4] == board[6] and board[4] == mark):
return True
elif (board[7] == board[8] and board[7] == board[9] and board[7] == mark):
return True
elif (board[1] == board[4] and board[1] == board[7] and board[1] == mark):
return True
elif (board[2] == board[5] and board[2] == board[8] and board[2] == mark):
return True
elif (board[3] == board[6] and board[3] == board[9] and board[3] == mark):
return True
elif (board[1] == board[5] and board[1] == board[9] and board[1] == mark):
return True
elif (board[7] == board[5] and board[7] == board[3] and board[7] == mark):
return True
else:
return False
def checkDraw():
for key in board.keys():
if (board[key] == ' '):
return False
return True
def playerMove():
position = int(input("Enter the position for 'O': "))
insertLetter(human, position)
return
def compMove():
bestScore = -800
bestMove = 0
for key in board.keys():
if (board[key] == ' '):
board[key] = bot
score = minimax(board, 0, False)
board[key] = ' '
if (score > bestScore):
bestScore = score
bestMove = key
insertLetter(bot, bestMove)
return
def minimax(board, depth, isMaximizing):
if (checkWhichMarkWon(bot)):
return 1
elif (checkWhichMarkWon(human)):
return -1
elif (checkDraw()):
return 0
if (isMaximizing):
bestScore = -800
for key in board.keys():
if (board[key] == ' '):
board[key] = bot
score = minimax(board, depth + 1, False)
board[key] = ' '
if (score > bestScore):
bestScore = score
return bestScore
else:
bestScore = 800
for key in board.keys():
if (board[key] == ' '):
board[key] = human
score = minimax(board, depth + 1, True)
board[key] = ' '
if (score < bestScore):
bestScore = score
return bestScore
board = {1: ' ', 2: ' ', 3: ' ',
4: ' ', 5: ' ', 6: ' ',
7: ' ', 8: ' ', 9: ' '}
def pick_game_type(): #Pick PvP, PvE, EvE
global ID
print("""
First, Pick which game mode you would like to play!
(Player vs. Player [1], Player vs. Computer [2], Computer vs. Computer [3])
""")
type_choice = input('> ')
if type_choice == "1": #Set global ID for [1]
ID = "1"
elif type_choice == "2": #Set global ID for [2]
ID = "2"
elif type_choice == "3": #Set global ID for [3]
ID = "3"
# -------- Script --------
os.system('cls') #Clear console
print("""
Welcome to Wacky Tacky Toe, Tac, Tic!
By Gage Gunn, Trevor Purta, Toby Howie, and Rachel Power with an s
""")
pick_game_type() #Choose gamemode
if ID == '1': #PvP Chosen
pass
elif ID == '2': #PvE Chosen
os.system('cls')
print('''
Welcome to Player vs Computer! In this version of Tic, Tac, Toe, each player can have a maximum of 3 tacs on the board at a time!
Decide which difficuly you would like to play? (Easy [1] or Hard [2])''')
ID2 = input('> ')
valid_input = False
while not valid_input: #Checks validity of ID2
if ID2 in ['1', '2']:
valid_input = True
else:
ID2 = input('> ')
if ID2 == '1': #Easy was chosen
pass
elif ID2 == '2':
print('You have chosen hard! You are X, the computer is O. The computer will go first')
while not checkForWin():
compMove()
playerMove()
elif ID == '3': #PvE Chosen
pass
您需要将游戏玩法的组件隔离成可重复使用的函数,这些函数可以组合起来模拟 minimax 计算的动作。
因为你需要模拟,所以最好有一个独立的数据结构来表示游戏(棋盘)的状态,包括轮到谁玩(我使用一个 10 个字符的字符串,其中第一个角色是当前玩家,其他 9 个角色是棋盘的当前状态。
您需要实现的第一件事是模拟移动(返回新的游戏状态)的函数:
def playMove(game,toPos,fromPos):
played = [game[0] if i==toPos else "." if i==fromPos else p
for i,p in enumerate(game)]
return "".join(played)
你还需要一个切换当前播放器的功能。这需要分开,以便您可以在模拟对手的动作之前轻松评估当前玩家的结果:
def switchPlayer(game):
return "XO"[game[0]=="X"]+game[1:] # returns a new game state
为了递归地模拟走法,您需要一个函数来给出可能走法的列表。根据您的游戏规则,移动被定义为目标位置 (toPos) 和可选的原点位置 (fromPos)。对于前 3 个动作,将没有原点(让 fromPos = toPos for those)
def getMoves(game):
player,*board = game
moves = [(i,i) for i,p in enumerate(board,1) if p=="."] # 1st 3 moves
if board.count(player)==3: # moves 4+
origins = [r for r,p in enumerate(board,1) if p==player ]
moves = [ (i,r) for i,_ in moves for r in origins] # add origins
return moves
对于模拟和实际游戏,您需要一个函数来确定游戏是否获胜:
winPatterns = [(1,2,3),(4,5,6),(7,8,9),(1,4,7),(2,5,8),(3,6,9),(1,5,9),(3,5,7)]
def isWin(game):
return any(all(game[i]==game[0] for i in p) for p in winPatterns)
对一步棋的结果进行评级可能是一些复杂的公式,但为了简单起见,我们只说获胜是 1,而不是获胜是零。 minimax 函数将递归地模拟动作,根据“最近的”决定性动作给它们一个评级(1 表示获胜,-1 表示失败)。
maxDepth = 6 # maximum depth = computer's skill
memo = dict() # memoization (for performance)
def minimax(game,depth=maxDepth):
if (game,depth) in memo: # known rating at this depth
return memo[game,depth]
if isWin(game): return 1 # no moves after a win (base condition)
if not depth: return 0 # limit depth (avoids infinite loops)
oGame = switchPlayer(game) # will simulate opponent's moves
oRatings = [] # opponent's minimax ratings
for move in getMoves(oGame):
played = playMove(oGame,*move) # simulate
oRatings.append(minimax(played,depth-1)) # get rating
rating = -max(oRatings or [1]) # worst countermove
for d in range(1,depth+1):
memo[game,d]=rating # memorize for this depth and lower
return rating
因为游戏数据结构是可散列的(即字符串),它可以用于记忆,大大提高了 minimax 函数的性能。
使用 minimax 函数,您可以确定计算机玩家(具有最高 minimax 评级的玩家)的最佳着法:
def bestMove(game):
return max(getMoves(game),key=lambda m:minimax(playMove(game,*m)))
您可以在获得 max() 之前随机选择移动,当不止一个移动具有最高评分时随机选择最佳移动
将它们放在一个游戏循环中:
def printBoard(game):
for r in range(1,10,3):
print("("+") (".join(game[r:r+3])+")",list(range(r,r+3)))
from random import sample
while True:
player,computer = sample("XOXO",2) # random starter, random computer
game = player + "."*9
while True:
printBoard(game)
if isWin(game): break
game = switchPlayer(game)
player = game[0]
if player == computer:
toPos,fromPos = bestMove(game)
print(f"Computer plays {player} at {toPos}",end=" ")
print(f"from {fromPos}"*(fromPos!=toPos))
else:
strMoves = [(str(t),str(f)) for t,f in getMoves(game)]
while True:
fromPos = toPos = input(f"Position to play for {player}: ")
if not toPos in (f for f,_ in strMoves):
print("invalid position"); continue
if game[1:].count(player)<3: break
fromPos = input(f"Position to remove {player} from: ")
if (toPos,fromPos) not in strMoves:
print("invalid move")
else: break
game = playMove(game,int(toPos),int(fromPos))
print( f"{player}'s WIN !!!\n")
if input("play again (y/n)") != "y": break
print()
样本运行:
(.) (.) (.) [1, 2, 3]
(.) (.) (.) [4, 5, 6]
(.) (.) (.) [7, 8, 9]
Computer plays O at 5
(.) (.) (.) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(.) (.) (.) [7, 8, 9]
Position to play for X: 1
(X) (.) (.) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(.) (.) (.) [7, 8, 9]
Computer plays O at 3
(X) (.) (O) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(.) (.) (.) [7, 8, 9]
Position to play for X: 7
(X) (.) (O) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(X) (.) (.) [7, 8, 9]
Computer plays O at 4
(X) (.) (O) [1, 2, 3]
(O) (O) (.) [4, 5, 6]
(X) (.) (.) [7, 8, 9]
Position to play for X: 6
(X) (.) (O) [1, 2, 3]
(O) (O) (X) [4, 5, 6]
(X) (.) (.) [7, 8, 9]
Computer plays O at 9 from 3
(X) (.) (.) [1, 2, 3]
(O) (O) (X) [4, 5, 6]
(X) (.) (O) [7, 8, 9]
Position to play for X: 3
Position to remove X from: 7
(X) (.) (X) [1, 2, 3]
(O) (O) (X) [4, 5, 6]
(.) (.) (O) [7, 8, 9]
Computer plays O at 2 from 4
(X) (O) (X) [1, 2, 3]
(.) (O) (X) [4, 5, 6]
(.) (.) (O) [7, 8, 9]
Position to play for X: 8
Position to remove X from: 3
(X) (O) (.) [1, 2, 3]
(.) (O) (X) [4, 5, 6]
(.) (X) (O) [7, 8, 9]
Computer plays O at 3 from 2
(X) (.) (O) [1, 2, 3]
(.) (O) (X) [4, 5, 6]
(.) (X) (O) [7, 8, 9]
Position to play for X: 7
Position to remove X from: 8
(X) (.) (O) [1, 2, 3]
(.) (O) (X) [4, 5, 6]
(X) (.) (O) [7, 8, 9]
Computer plays O at 4 from 9
(X) (.) (O) [1, 2, 3]
(O) (O) (X) [4, 5, 6]
(X) (.) (.) [7, 8, 9]
Position to play for X:
Position to play for X: 9
Position to remove X from: 1
(.) (.) (O) [1, 2, 3]
(O) (O) (X) [4, 5, 6]
(X) (.) (X) [7, 8, 9]
Computer plays O at 8 from 4
(.) (.) (O) [1, 2, 3]
(.) (O) (X) [4, 5, 6]
(X) (O) (X) [7, 8, 9]
Position to play for X: 2
Position to remove X from: 6
(.) (X) (O) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(X) (O) (X) [7, 8, 9]
Computer plays O at 1 from 3
(O) (X) (.) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(X) (O) (X) [7, 8, 9]
Position to play for X: 3
Position to remove X from: 7
(O) (X) (X) [1, 2, 3]
(.) (O) (.) [4, 5, 6]
(.) (O) (X) [7, 8, 9]
Computer plays O at 6 from 8
(O) (X) (X) [1, 2, 3]
(.) (O) (O) [4, 5, 6]
(.) (.) (X) [7, 8, 9]
Position to play for X: 7
Position to remove X from: 2
(O) (.) (X) [1, 2, 3]
(.) (O) (O) [4, 5, 6]
(X) (.) (X) [7, 8, 9]
Computer plays O at 4 from 1
(.) (.) (X) [1, 2, 3]
(O) (O) (O) [4, 5, 6]
(X) (.) (X) [7, 8, 9]
O's WIN !!!
play again (y/n) ? n