class PerfectComputer

Constants

EARLIEST_CHANCE_TO_WIN
MAXIMUM_DEPTH_TO_CHECK
MAXIMUM_SCORE
STARTING_DEPTH

Attributes

marker[R]

Public Class Methods

new(marker) click to toggle source
# File lib/perfect_computer.rb, line 12
def initialize(marker)
  @marker = marker
end

Public Instance Methods

choose_space(board) click to toggle source
# File lib/perfect_computer.rb, line 16
def choose_space(board)
  @best_score = {}
  negamax(board)
  @best_score.size > EARLIEST_CHANCE_TO_WIN ? choose_random_space(board) : best_space_to_pick
end

Private Instance Methods

best_space_to_pick() click to toggle source
# File lib/perfect_computer.rb, line 47
def best_space_to_pick
  @best_score.max_by {|key, value| value}[0]
end
choose_random_space(board) click to toggle source
# File lib/perfect_computer.rb, line 51
def choose_random_space(board)
  SimpleComputer.new(board.current_player_marker).choose_space(board)
end
negamax(board, depth = STARTING_DEPTH, alpha = -MAXIMUM_SCORE, beta = MAXIMUM_SCORE, color = 1, max_depth = MAXIMUM_DEPTH_TO_CHECK) click to toggle source
# File lib/perfect_computer.rb, line 24
def negamax(board, depth = STARTING_DEPTH, alpha = -MAXIMUM_SCORE, beta = MAXIMUM_SCORE, color = 1, max_depth = MAXIMUM_DEPTH_TO_CHECK)
  return color * score_scenarios(board, depth) if board.game_over? || depth > max_depth

  max = -MAXIMUM_SCORE

  board.check_available_spaces.each do |space|
    new_board = board.place_marker(space)
    negamax_value = -negamax(new_board, depth+1, -beta, -alpha, -color)
    max = [max, negamax_value].max
    @best_score[space] = max if depth == STARTING_DEPTH
    alpha = [alpha, negamax_value].max
    return alpha if alpha >= beta
  end

  max
end
score_scenarios(board, depth) click to toggle source
# File lib/perfect_computer.rb, line 41
def score_scenarios(board, depth)
  return 0 if board.game_tied?
  return MAXIMUM_SCORE / depth if board.game_won_by?(marker)
  return -MAXIMUM_SCORE / depth
end