2018-01-23 01:04:38 +00:00
|
|
|
class Bot
|
|
|
|
|
2018-01-25 19:37:24 +00:00
|
|
|
attr_reader :best_choice, :val
|
2018-01-23 01:04:38 +00:00
|
|
|
|
|
|
|
def initialize board, piece
|
2018-01-25 19:37:24 +00:00
|
|
|
@val = piece
|
2018-01-23 01:04:38 +00:00
|
|
|
@piece = piece
|
|
|
|
@opponent = switch piece
|
|
|
|
end
|
|
|
|
|
|
|
|
def move board
|
|
|
|
minmax board, @piece
|
|
|
|
board.set @piece, @best_choice
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def minmax board, cur_player
|
|
|
|
return score(board) if game_done?(board)
|
|
|
|
|
|
|
|
scores = {}
|
|
|
|
|
|
|
|
board.get_free.each do |space|
|
2018-01-25 19:37:24 +00:00
|
|
|
# dup and clone only create a shallow clone, so it doesn't clone the array inside the board object.
|
|
|
|
board.set cur_player, space
|
|
|
|
|
|
|
|
scores[space] = minmax(board, switch(cur_player))
|
2018-01-23 01:04:38 +00:00
|
|
|
|
2018-01-25 19:37:24 +00:00
|
|
|
board.remove space
|
2018-01-23 01:04:38 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
@best_choice, best_score = best_choice cur_player, scores
|
|
|
|
best_score
|
|
|
|
end
|
|
|
|
|
|
|
|
def switch cur
|
|
|
|
cur == " X " ? " O " : " X "
|
|
|
|
end
|
|
|
|
|
|
|
|
def game_done? board
|
|
|
|
board.any_winner? || board.is_full?
|
|
|
|
end
|
|
|
|
|
|
|
|
def best_choice piece, scores
|
|
|
|
if piece == @piece then
|
|
|
|
#p scores
|
|
|
|
scores.max_by { |_k, v| v}
|
|
|
|
else
|
|
|
|
scores.min_by { |_k, v| v}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def score board
|
2018-01-25 19:44:22 +00:00
|
|
|
|
2018-01-23 01:04:38 +00:00
|
|
|
if board.is_winner? @piece
|
|
|
|
return 10
|
|
|
|
elsif board.is_winner? @opponent
|
|
|
|
return -10
|
|
|
|
end
|
|
|
|
0
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|