I recently tried creating a simple Tic Tac Toe AI with minimax (with help from YouTube), but I can't get it to work. The algorithm just spits out the first value it checks instead of going through all of them and giving the best one.
I tried copying the code from the YouTube video but it still doesn't work, can someone tell me what's wrong?
import math
import random
print()
board = {1: ' ', 2: ' ', 3: ' ',
4: ' ', 5: ' ', 6: ' ',
7: ' ', 8: ' ', 9: ' '}
computerLetter = 'X'
playerLetter = 'O'
def print_board(board=board):
for i in range(1, 8, 3):
print('|' board[i] '|' board[i 1] '|' board[i 2] '|')
if i < 7:
print('-' * 13)
print()
def space_is_free(position):
if board[position] == ' ':
return True
else:
return False
def free_spaces(board=board):
freeSpaces = 0
for key in board.keys():
if key == ' ':
freeSpaces = 1
return freeSpaces
def make_move(letter, position):
if space_is_free(position):
board[position] = ' ' letter ' '
print_board(board)
if check_for_win(board):
if letter == 'O':
print("You win!!")
exit()
else:
print("The computer wins. Better luck next time!")
exit()
elif check_for_tie(board):
print("It's a tie! Well played.")
exit()
else:
print("Invalid choice.")
position = int(input("Enter new position: "))
make_move(letter, position)
def check_for_win(board=board):
if board[1] == board[2] == board[3] != ' ' or board[4] == board[5] == board[6] != ' ' or board[7] == board[8] \
== board[9] != ' ' or board[1] == board[4] == board[7] != ' ' or board[2] == board[5] == board[6] != \
' ' or board[3] == board[6] == board[9] != ' ' or board[1] == board[5] == board[9] != ' ' or board[3]\
== board[5] == board[7] != ' ':
return True
else:
return False
def check_for_win_letter(letter):
if board[1] == board[2] == board[3] == ' ' letter ' ' or board[4] == board[5] == board[6] == ' ' letter ' '\
or board[7] == board[8] == board[9] == ' ' letter ' ' or board[1] == board[4] or board[7] == ' ' \
letter ' ' or board[2] == board[5] or board[6] == ' ' letter ' ' or board[3] == board[6] or board[9]\
== ' ' letter ' ' or board[1] == board[5] == board[9] == ' ' letter ' ' or board[3] == board[5] ==\
board[7] == ' ' letter ' ':
return True
else:
return False
def check_for_tie(board=board):
for key in board.keys():
if board[key] == ' ':
return False
else:
return True
def player_move(playerLetter='O'):
if free_spaces(board) >= 9:
print_board(board)
position = int(input("Enter position (1-9): "))
make_move(playerLetter, position)
def computer_move(computerLetter='X'):
if free_spaces(board) == 9:
make_move(computerLetter, 5)
else:
bestScore = -math.inf
bestPosition = 0
for key in board.keys():
if space_is_free(key):
board[key] = ' ' computerLetter ' '
score = minimax(board, 0, False)
board[key] = ' '
if score > bestScore:
bestScore = score
bestPosition = key
make_move(computerLetter, bestPosition)
print(f"Computer moves to {bestPosition}.")
def minimax(board, depth, isMaximising):
if check_for_win_letter('X'):
return 1 * (free_spaces(board) 1)
elif check_for_win_letter('O'):
return -1 * (free_spaces(board) 1)
elif check_for_tie(board):
return 0
if isMaximising:
bestScore = -math.inf
for key in board.keys():
if space_is_free(key):
board[key] = ' ' computerLetter ' '
score = minimax(board, depth 1, False)
board[key] = ' '
bestScore = max(score, bestScore)
return bestScore
else:
bestScore = math.inf
for key in board.keys():
if space_is_free(key):
board[key] = ' ' playerLetter ' '
score = minimax(board, depth 1, True)
board[key] = ' '
bestScore = min(score, bestScore)
return bestScore
while not check_for_win(board):
computer_move('X')
player_move('O')
# gameState = input("Would you like to play again? (y/n)")
#
# if gameState.lower() == 'y':
# main()
# elif gameState.lower() == 'n':
# exit()
# else:
# print("Invalid choice.")
I tried changing the computer and player letters, and whether the computer was maximising or minimising but it didn't work.
CodePudding user response:
I think I have found what is wrong with your code, in the minmax function the first if, elif, else statement always ends with a return statement.
def minimax(board, depth, isMaximising):
if check_for_win_letter('X'):
return 1 * (free_spaces(board) 1)
elif check_for_win_letter('O'):
return -1 * (free_spaces(board) 1)
elif check_for_tie(board):
return 0
The else statement is the reason it is failing.
When a return statement is called, it ends the function returning the variable stated, in this case it will always be a number between -9 and 9, and does not run the next block of code, ruining the computer's process to find the best/worst place to play. the else statement means that even if the previous statements are false, it will always return zero, ending the function and halting the process of the next block of code.
I hope this helps! :)
CodePudding user response:
Okay I figured out the problem, it was actually a bunch of logical errors in the functions which were checking for a winner and the winner letter, a few typos per say.
**
- Error 1:
**
def check_for_win(board=board):
if board[1] == board[2] == board[3] != ' ' or board[4] == board[5] == board[6] != ' ' or board[7] == board[8] \
== board[9] != ' ' or board[1] == board[4] == board[7] != ' ' or ****board[2] == board[5] == board[6]**** != \ # board[6] should be board[8]
' ' or board[3] == board[6] == board[9] != ' ' or board[1] == board[5] == board[9] != ' ' or board[3]\
== board[5] == board[7] != ' ':
return True
**
- Error 2:
**
def check_for_win_letter(letter):
if board[1] == board[2] == board[3] == ' ' letter ' ' or board[4] == board[5] == board[6] == ' ' letter ' '\
or board[7] == board[8] == board[9] == ' ' letter ' ' or board[1] == board[4] ****or board[7]**** == ' ' \
letter ' ' or board[2] == board[5] ****or board[6]**** == ' ' letter ' ' or board[3] == board[6] ****or board[9]****\
== ' ' letter ' ' or board[1] == board[5] == board[9] == ' ' letter ' ' or board[3] == board[5] ==\
board[7] == ' ' letter ' ':
return True
The ones statements within asterisks (*) are the errors, the or statements should be '==' and the board[6] should again be board[8].