I am stuck on implementing the minimax algorithm for a tic tac toe game. I keep getting the same error every time (undefined method `<' for nil:NilClass (NoMethodError)) but me and various people I have now asked, can't seem to fix it.
My minimax implementation is as follows:
def minimax(current_board, current_player)
if user_won?(current_board)
return -10
elsif computer_won?(current_board)
return 10
elsif tie?(current_board)
return 0
end
available_squares = empty_squares(current_board)
moves = []
score = nil
available_squares.each do |available_square|
move = {}
current_board[available_square] = COMPUTER_MARKER if current_player == 'computer'
current_board[available_square] = PLAYER_MARKER if current_player == 'player'
score = minimax(current_board, alternate_player(current_player))
current_board[available_square] = INITIAL_MARKER
move[available_square] = score
moves.push(move)
end
best_move = nil
best_score = current_player == 'computer' ? -Float::INFINITY : Float:: INFINITY
if current_player == 'computer'
moves.each do |hsh|
hsh.each do |move, score|
if score > best_score
best_move = move
best_score = score
end
end
end
else
moves.each do |hsh|
hsh.each do |move, score|
if score < best_score
best_move = move
best_score = score
end
end
end
end
best_move
end
When minimax is called recursively, it sometimes returns nil
, which is then appended to the move
hash, where move
is then appended to the moves
array. This causes the <
operator to raise the said exception. I don't know why nil
is being returned.
I can only assume my logic is flawed. Maybe my board is not being correctly reset after trying possible board states but honestly, I don't know how to proceed. I have tried multiple implementations and always get the same error.
I have been stuck on this for over a week and would really appreciate some help.
I think I have found the problem. In my if tie?(current_board)
condition, tie?
should take the argument available_squares
instead. This stops an exception being raised.
Also, as @Stefan pointed out (credit to him), putting a default value ensures the correct value is output and would be written as:
score = minimax(current_board, alternate_player(current_player)) || 0
This solves it.