昨日の続き
ゲームと着手を受け取って、更新した新しいゲームを返す関数と、ゲームを受け取ってゲームが終わったかどうかと誰が勝ったのかを返す関数を作った。
-- ゲームと着手を受け取って、更新した新しいゲームを返す step_game :: Game -> Play -> IO Game step_game game play = return (MakeGame [if (i == (play_value play)) then (next_turn game) else x | (i, x) <- zip [0..] (value game)] (3 - (next_turn game))) -- ゲームを受け取ってゲームが終わったかどうかと、誰が勝ったのかを返す check_is_finished :: Game -> (Bool, Int) check_is_finished game = let lines = (map (\x -> (map ((value game)!!) x)) [[0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 4, 8], [2, 4, 6]]) in case find (== [1, 1, 1]) lines of Just x -> (True, 1) Nothing -> case find (== [2, 2, 2]) lines of Just x -> (True, 2) Nothing -> case find (== 0) (value game) of Just x -> (False, 0) Nothing -> (True, 0)
random_choiceやhuman_choiceなどの思考ルーチンはゲームに無関係なのでmonte.hsに移動した。これによりゲームの定義であるTicTacToe.hsはimport IOやimport Randomをしなくなった。正しい。
-- 「考える」とは与えられた選択肢の中から一つ選ぶこと type Think = [Play] -> IO Play -- ランダムに選択可能な着手を受け取って一つ選んで返す random_choice :: Think random_choice hands = do i <- getStdRandom (randomR (0, (length hands) - 1)) return (hands !! i) -- 人間が選択可能な着手を受け取って一つ選んで返す human_choice :: Think human_choice hands = do hSetBuffering stdout NoBuffering putStr ("Choice a hand: " ++ (show (zip [0..] hands))) i <- readNum return (hands !! i) where readNum :: IO Int readNum = readLn
ゲームをするのに必要な部品が揃ったのでmainを頑張ってみた。これでランダムに考えるAIと人間とかゲームで対戦することが出来る。
main = do game <- init_game while_game_finished game while_game_finished :: Game -> IO Int -- IO Who while_game_finished game = if finished then do putStr $ show game putStr "finished\n" return who_won else let choice = if (next_turn game) == 2 then human_choice else random_choice in do putStr $ show game play <- choice $ possible_hands $ game game <- step_game game play while_game_finished game where (finished, who_won) = (check_is_finished game)
次はAIがモンテカルロする。これはつまり
choice = if (next_turn game) == 2 then human_choice else random_choice
の部分を変更できるようにする必要性を示唆している。
-- ゲームを受け取って、その情報によりAIを選択する select_ai_for_human_play :: Game -> Think select_ai_for_human_play game = if (next_turn game) == 2 then human_choice else random_choice select_ai_for_monte :: Game -> Think select_ai_for_monte game = random_choice
こんな感じかな。
ソース
http://bitbucket.org/nishio/montecarlo_game_test/src/tip/monte.hs
http://bitbucket.org/nishio/montecarlo_game_test/src/tip/TicTacToe.hs