(Connect 4 is a game where you drop circles and try to create 4 connected circles of your color in either vertical, horizontal, or diagonal form.)
I'm building a connect 4 minimax algorithm, and it fails to prevent a loss, but seemingly only strives to win. It only attempts to connect its own pieces while not stopping me from connecting mine.
Algorithm: (X is Player, O is Computer)
def minimax(board, depth, is_maximizing, depthLimit):
if detect(board, ' O '):
return 100 - depth
elif detect(board, ' X '):
if is_maximizing:
return 100 - depth
else:
return -100
elif boardFull(board):
return 0
elif depth == depthLimit + 1:
return 0
if is_maximizing:
max_eval = float('-inf')
for row in range(6):
for column in range(7):
if board[row][column] == ' ' and not isColumnFull(board, column):
board[row][column] = ' O '
eval = minimax(board, depth + 1, False, depthLimit)
board[row][column] = ' '
max_eval = max(max_eval, eval)
return max_eval
else:
min_eval = float('inf')
for row in range(6):
for column in range(7):
if board[row][column] == ' ' and not isColumnFull(board, column):
board[row][column] = ' X '
eval = minimax(board, depth + 1, True, depthLimit)
board[row][column] = ' '
min_eval = min(min_eval, eval)
return min_eval
def isColumnFull(board, column):
for row in range(6):
if board[row][column] == ' ':
return False
return True
def computerMove(board):
best_score = float('-inf')
best_move = None
for row in range(6):
for column in range(7):
print(f'{round(((row/6)*100)+(column/7)*10, 2)}% Done Calculating')
if board[row][column] == ' ' and not isColumnFull(board, column):
board[row][column] = ' O '
score = minimax(board, 0, False, depth)
board[row][column] = ' '
if score > best_score:
best_score = score
best_move = column
for row in range(6):
if board[row][best_move] != ' ':
board[row - 1][best_move] = ' O '
break
elif row == 5:
board[row][best_move] = ' O '
break
if detect(board, ' O '):
print('O Wins!')
return False
return True
'board' is essentially a matrix containing the, well, board:
board = [[' ' for i in range(7)] for f in range(6)]
I've also ruled out the detect()
function being buggy, as it works fine for detecting a win. (detect()
essentially checks if there are 4 connected pieces of the same color/player)
The problem looks to be here.
def minimax(board, depth, is_maximizing, depthLimit):
if detect(board, ' O '):
return 100 - depth
elif detect(board, ' X '):
if is_maximizing:
return 100 - depth
else:
return -100
If O wins, it always returns a large positive. If X wins, it returns a negative or a positive, depending on whose turn it is. If we're maximizing, then it is X's turn, so we return a large positive number. In other words, the AI is indifferent between O winning and X winning on X's turn.
The fix is to make X the opposite of O:
def minimax(board, depth, is_maximizing, depthLimit):
if detect(board, ' O '):
return 100 - depth
elif detect(board, ' X '):
return -100 + depth
After making this change, it can figure out how to block X from winning.