I already implemented TicTacToe using heuristics, today I was given the task to reimplement my TicTacToe AI using the MiniMax algorithm.
If you don’t already know, MiniMax is an algorithm that can be used in two player games such as Chess, Checkers, or TicTacToe. Using a game tree the algorithm tries to maximize rewards during your turn, and minimize rewards during the opponents turn. Hence its name “Minimax”.
There are two parts to the MiniMax algorithm: the evaluator and the game tree logic.
Evaluator
The evaluator is custom to the each implantation of Minimax. Its job is to take a game state, and rank it. For TicTacToe its job is simple.
You Won:   1
You Lost: -1
Cats:      0The numbers aren’t important, as long as they are in ascending order of what you want to happen. Each game will have their own evaluator. The more complex the game, the more complex the evaluator will have to be.
The Game Tree
The other part of the Minimax algorithm is the game tree logic, which is the same for all of its implementations.
The basic pattern looks like:
class GameTree
  def initialze(game_state, player, whos_turn=nil)
    @game_state, @player = game_state, player
    @whos_turn = whos_turn || player
  end
  def best_move
    children.max(&:score).move
  end
  def score
    return  1 if game_state.over? && game_state.winner == player
    return -1 if game_state.over? && game_state.winner == @opponent
    return  0 if game_state.over?
    if whos_turn == player
      children.map { |child| child.score }.max
    else
      children.map { |child| child.score }.min
    end
  end
  def children
    potential_moves.map { |move| GameTree.new(move, player, next_turn) }
  end
  # ...
end