-1

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.

testing09
  • 73
  • 7
  • Does this answer your question? [minimax algorithm tic-tac-toe](https://stackoverflow.com/questions/65054060/minimax-algorithm-tic-tac-toe) – TheSlater Dec 01 '20 at 11:08
  • Nope :(. Unfortunately it doesn't. – testing09 Dec 01 '20 at 11:10
  • _"I don't know why nil is being returned"_ – when `moves` is empty, i.e. `[]`, `best_move` stays `nil` which then becomes the return value. – Stefan Dec 01 '20 at 11:19
  • I don't understand how `minimax` works, but if you need a numeric value, you could change the method's last line to `best_move || 0` to provide a default value (change `0` to whatever makes sense) – Stefan Dec 01 '20 at 11:24
  • That is ok @Stefan. I dont know Ruby but MiniMax and try to solve the problem ;) – TheSlater Dec 01 '20 at 11:53

2 Answers2

1

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.

testing09
  • 73
  • 7
0

The loop available_squares.each has to be followed by return 0 ifc there where no moves anymore.

TheSlater
  • 642
  • 1
  • 4
  • 11