Rubyでリバーシ(オセロ)
MinMax法で考える人工知能のプレイヤを作りました。
今まで Scheme や Haskell では作れなかったのですが、やっと作れました。
マシンスペックにもよりますが、3手先読みぐらいが妥当でしょう。4手はかなり遅いです。
require "Reversi" require "ReversiAI" # Min-Max法 # 評価関数は、自分のコマの数。 # depth は 3 or 4 手ぐらいが妥当です。 class MinMaxPlayer < Player # depth手先まで読む。数の多いほうが賢い。 def initialize(color, depth) super(color) @depth = depth end def move(board) hand,_ = min_max(board, @color, @depth) if hand == nil then return :pass end hand end # Min-Max法により、最善の手と評価値を返す。手がなければ、nilを返す。 def min_max(board, col, depth) hands = board.collect_hand(col) if hands.empty? then return [nil,eval(board)] end best_hand = nil best_eval = 999 for h in hands b = board.deep_clone().put(h[0],h[1], col) enemy = (col == :black ? :white : :black) if depth > 0 then _,e = min_max(b, enemy, depth-1) else e = eval(b) end # 最初は、 if best_hand == nil then best_hand = h best_eval = e # 自分なら最善の手を、相手なら最悪の手を選ぶ。 elsif col==@color ? (e > best_eval) : (e < best_eval) then best_hand = h best_eval = e end end [best_hand, best_eval] end # 評価関数。自分のコマの数が多い方がよい。 def eval(board) board.get_count(@color) end end def test() player_b = BeginnerPlayer.new(:black) player_w = MinMaxPlayer.new(:white, 3) play(player_b, player_w) end
BeginnerPlayer(最もひっくり返せる手を打つ)とコイツを対戦させてみました。
コイツの圧勝です。やはり、賢くなっています。
では、私とMinMaxPlayer(3手先読み)と対戦してみました。
私が勝ちました。(^o^)v
やはり隅の攻防が甘いですね。評価関数に隅や端のウェイトをかければもう少し強くなると思う。
> play(ManPlayer.new(:black),MinMaxPlayer.new(:white,3)) ■■■■■■■■■■ ■○○○○○○○○■ ■○○○○○○○○■ ■○●○○●○○○■ ■○●●○○●○○■ ■○○●●○○○○■ ■○●○○●○○○■ ■●●●○○●○○■ ■○○○○○○○○■ ■■■■■■■■■■ ○black 51 ●white 13 winner:black