続き

  [count_n (next_turn game)
   [(step_game game play) >> (while_game_finished select_ai_for_monte) | _ <- [1..100]]
       | play <- hands]

この時点でそれぞれの着手選択肢について着手した後ゲームが終わるまで100回実行した結果、勝ったのが自分である回数のリストが[IO Int]で得られる。

このうち、そのIntの値が最大であるような着手を選びたい。着手のリストは[Play]だ。

IOの内部を触ることを考える。まずsequence [m a] -> m [a]で IO [Int] に変換する。で、>>=で[Int]を取る関数をbindすればよい。この関数は[Int]を取って、そのIntが最大であるようなPlayを返せばよい。

get_best :: [Int] -> [Play] -> Play
--get_best scores hands = snd $ foldl1 ((<*>) ((<*>).((flip.(flip if')))) (flip ((.).((>).fst)) fst)) $ zip scores hands
get_best scores hands = snd $ foldl1 (\x y -> (if ((fst x) > (fst y)) then x else y)) $ zip scores hands

ラムダを消してみたらかえって汚くなったのでやめた。

-- 単純モンテカルロ(各選択肢について100回ずつランダムに最後まで
-- プレイしてから一番成績の良かったものを選ぶ)
monte_choice :: Think
monte_choice game hands 
    = (liftM2 get_best) 
      (sequence [count_n (next_turn game)
                 [do_random_playout game play 
                  | _ <- [1..100]]
                 | play <- hands]) 
      (return hands)

プレイ

next turn: x
x . .
. . .
. . .

next turn: o
Choice a hand: [(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8)]3
x . .
. o .
. . .

next turn: x
x . x
. o .
. . .

next turn: o
Choice a hand: [(0,1),(1,3),(2,5),(3,6),(4,7),(5,8)]0
x o x
. o .
. . .

next turn: x
x o x
. o .
. x .

next turn: o
Choice a hand: [(0,3),(1,5),(2,6),(3,8)]

高々100回試行しているだけだけど、ゲームがゲームなだけに全くもって危なげないプレイをしている。

さて次はモンテカルロ木探索だ。データを貯めておくために木とか辞書とかつくって破壊的にゴリゴリ値を変更したいぞ。えっ。破壊的にゴリゴリ?(Haskellを選んだことを少し後悔している)