class AI

Constants

IN_PROGRESS_SCORE

Attributes

current_player[RW]

Public Class Methods

new(game_rules) click to toggle source
# File lib/ai.rb, line 5
def initialize(game_rules)
  @game_rules = game_rules
end

Public Instance Methods

find_best_move(board, opponent_piece, game_piece) click to toggle source
# File lib/ai.rb, line 11
def find_best_move(board, opponent_piece, game_piece)
  possible_moves = {}
  current_player = game_piece
  depth = 1

  return 4 if empty?(board) 
  
  open_spaces_on(board).each do |move|
    cloned_board = board.clone
    make_move(cloned_board, move, current_player)
    score = rank(cloned_board, depth, opponent_piece, game_piece)
    track_best(move, score, possible_moves)
    new_score = score_available_moves(board, depth + 1, next_player(current_player, opponent_piece, game_piece), score, opponent_piece, game_piece)
    if new_score > score
      score = new_score
    end
    board = reset(board, move)
  end
  best_move(possible_moves)
end
open_spaces_on(board) click to toggle source
# File lib/ai.rb, line 32
def open_spaces_on(board)
  board.size.times.select {|i| board[i] == nil}
end

Private Instance Methods

best_move(possible_moves) click to toggle source
# File lib/ai.rb, line 60
def best_move(possible_moves)
  best_score = possible_moves.values.max
  possible_moves.key(best_score)
end
empty?(board) click to toggle source
# File lib/ai.rb, line 38
def empty?(board)
  board.count(nil) == 9
end
make_move(board, move, current_player) click to toggle source
# File lib/ai.rb, line 74
def make_move(board, move, current_player)
  board[move] = current_player
  board
end
next_player(current_player, opponent_piece, game_piece) click to toggle source
# File lib/ai.rb, line 65
def next_player(current_player, opponent_piece, game_piece)
  current_player == opponent_piece ? game_piece : opponent_piece
end
rank(board, depth, opponent_piece, game_piece) click to toggle source
# File lib/ai.rb, line 79
def rank(board, depth, opponent_piece, game_piece)
  if @game_rules.game_over?(board)
    return TIE - depth if @game_rules.tie?(board)
    return WIN - depth if @game_rules.winner(board) == game_piece
    return LOSS - depth if @game_rules.winner(board) == opponent_piece
  else
    return IN_PROGRESS_SCORE
  end
end
reset(board, move) click to toggle source
# File lib/ai.rb, line 69
def reset(board, move)
  board[move] = nil
  board
end
score_available_moves(board, depth, current_player, score, opponent_piece, game_piece) click to toggle source
# File lib/ai.rb, line 42
def score_available_moves(board, depth, current_player, score, opponent_piece, game_piece)
  return score if @game_rules.game_over?(board)
  open_spaces_on(board).each do |move|
    make_move(board, move, current_player)
    if current_player == opponent_piece
      score = score_available_moves(board, depth + 1, next_player(current_player, opponent_piece, game_piece), score, opponent_piece, game_piece) * -1
    else
      score = score_available_moves(board, depth + 1, next_player(current_player, opponent_piece, game_piece), score, opponent_piece, game_piece)
    end
    board = reset(board, move)
  end
  return score
end
track_best(move, score, possible_moves) click to toggle source
# File lib/ai.rb, line 56
def track_best(move, score, possible_moves)
  possible_moves[move] = score
end