I'm trying to code a tic-tac-toe bot using the minimax algorithm in python. My code seems like it should work to me, but misevaluates positions, searches too many or too few nodes and loses to me every game.
mainboard = ["-", "-", "-", "-", "-", "-", "-", "-", "-"]
nodes = 0
def detectwin(b):
signs = ["O", "X"]
for s in signs:
for i in range(3):
j = 3 * i
if ((b[0 + j]==s and b[1 + j]==s and b[2 + j]==s) or
(b[0 + i]==s and b[1 + i]==s and b[2 + i]==s)):
if s == "O": return 1
if s == "X": return -1
if ((b[0]==s and b[4]==s and b[8]==s) or
(b[2]==s and b[4]==s and b[6]==s)):
if s == "O": return 1
if s == "X": return -1
return 0
def evaluate(board):
return detectwin(board)
def fullboard(board):
return all(cell != "-" for cell in board)
def makemove(board, move, maximizingPlayer):
if maximizingPlayer:
board[move] = "O"
return board
else:
board[move] = "X"
return board
def undomove(board, move):
board[move] = "-"
return board
def minimax(board, depth, maximizingPlayer):
global nodes
if depth == 0 or fullboard(board) or detectwin(board) != 0:
nodes += 1
return evaluate(board)
if maximizingPlayer:
maxEval = -1000
for i in range(9):
if board[i] == "-":
board = makemove(board, i , True)
newEval = minimax(board, depth-1, False)
maxEval = max(maxEval, newEval)
board = undomove(board, i)
return maxEval
else:
minEval = 1000
for i in range(9):
if board[i] == "-":
board = makemove(board, i , False)
newEval = minimax(board, depth-1, True)
minEval = min(minEval, newEval)
board = undomove(board, i)
return minEval
def findbestmove(board, maximizingPlayer):
global nodes
if maximizingPlayer:
bestmove = -1
maxEval = -1000
for i in range(9):
if board[i] == "-":
board = makemove(board, i , True)
nodes = 0
newEval = minimax(board, 9, False)
print(f"Eval move {i}: {newEval} ({nodes} nodes)")
if newEval > maxEval:
maxEval = newEval
bestmove = i
board = undomove(board, i)
return bestmove
def printboard(b):
signs = ["No", "O", "X"]
win = signs[detectwin(b)] + " wins"
print(f'{b[0]} {b[1]} {b[2]}\n{b[3]} {b[4]} {b[5]}\n{b[6]} {b[7]} {b[8]}\n{win}\n')
print("Ready!")
while True:
move = findbestmove(mainboard, True)
mainboard = makemove(mainboard, move, True)
printboard(mainboard)
yourmove = int(input())
mainboard = makemove(mainboard, yourmove, False)
printboard(mainboard)
I've tried evaluating different positions, expecting it to give the correct objective evaluation of the postion by searching every possibility. Instead it searches the wrong number of nodes and evaluates positions incorrectly. Why does it do this?