module MinimaxRB

Public Class Methods

best_move(args) click to toggle source
# File lib/minimax_rb.rb, line 2
def self.best_move args
  minimax(args[:board], args[:curr_player_marker], args[:opponent_marker], args.fetch(:empty_marker, nil))
end

Private Class Methods

available_moves(array, empty_marker) click to toggle source
# File lib/minimax_rb.rb, line 28
def self.available_moves array, empty_marker
  available_moves = []
  array.each_with_index do |value, index|
    if value == empty_marker
      available_moves << index
    end
  end
  available_moves
end
board_full?(board, empty_marker) click to toggle source
# File lib/minimax_rb.rb, line 80
def self.board_full? board, empty_marker
  not board.include?(empty_marker)
end
columns(board) click to toggle source
# File lib/minimax_rb.rb, line 54
def self.columns board
  rows(board).transpose
end
diagonals(board) click to toggle source
# File lib/minimax_rb.rb, line 58
def self.diagonals board
  left_diag = []
  right_diag = []
  (0...grid_size(board)).each do |i|
    left_diag.push(rows(board)[i][i])
    right_diag.push(rows(board).reverse[i][i])
  end
  [left_diag, right_diag]
end
draw?(board, marker, opponent, empty_marker) click to toggle source
# File lib/minimax_rb.rb, line 72
def self.draw? board, marker, opponent, empty_marker
  board_full?(board, empty_marker) and not win?(board, marker, opponent)
end
grid_size(board) click to toggle source
# File lib/minimax_rb.rb, line 68
def self.grid_size board
  Math.sqrt(board.length)
end
marker_winner?(marker, board) click to toggle source
# File lib/minimax_rb.rb, line 42
def self.marker_winner? marker, board
  combos = [rows(board), columns(board), diagonals(board)]
  combos.each do |combo|
    combo.each { |line| return true if marker_winning_combo?(marker, line) }
  end
  false
end
marker_winning_combo?(marker, board) click to toggle source
# File lib/minimax_rb.rb, line 38
def self.marker_winning_combo? marker, board
  board.uniq.length == 1 and board.include?(marker)
end
max_move(best_score) click to toggle source
# File lib/minimax_rb.rb, line 20
def self.max_move best_score
  best_score.max_by { |key, value| value }[0]
end
max_score(best_score) click to toggle source
# File lib/minimax_rb.rb, line 24
def self.max_score best_score
  best_score.max_by { |key, value| value }[1]
end
minimax(board, marker, opponent, empty_marker, depth=0, best_score={}) click to toggle source
# File lib/minimax_rb.rb, line 7
def self.minimax board, marker, opponent, empty_marker, depth=0, best_score={}
  return 0 if draw?(board, marker, opponent, empty_marker)
  return -1 if win?(board, marker, opponent)

  available_moves(board, empty_marker).each do |move|
    board[move] = marker
    best_score[move] = -1 * minimax(board, opponent, marker, empty_marker, depth+1, {})
    board[move] = empty_marker
  end

  depth == 0 ? max_move(best_score) : max_score(best_score)
end
rows(board) click to toggle source
# File lib/minimax_rb.rb, line 50
def self.rows board
  board.each_slice(grid_size(board)).to_a
end
win?(board, marker, opponent) click to toggle source
# File lib/minimax_rb.rb, line 76
def self.win? board, marker, opponent
  marker_winner?(marker, board) or marker_winner?(opponent, board)
end