hcheckers-0.1.0.2: src/Learn.hs
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Learn where
import Control.Monad
import Control.Monad.State
import Control.Concurrent.STM
import qualified Control.Monad.Metrics as Metrics
import Data.Text.Format.Heavy
import System.Log.Heavy
import System.Log.Heavy.TH
import Core.Types
import Core.Board
import AI.AlphaBeta
import AI.AlphaBeta.Types
import AI.AlphaBeta.Cache
-- import AI.AlphaBeta.Persistent
import Formats.Types
import Formats.Pdn
doLearn' :: (GameRules rules, Evaluator eval) => rules -> eval -> AICacheHandle rules eval -> AlphaBetaParams -> GameRecord -> Checkers ()
doLearn' rules eval var params gameRec = do
sup <- askSupervisor
supervisor <- liftIO $ atomically $ readTVar sup
let startBoard = initBoardFromTags supervisor (SomeRules rules) (grTags gameRec)
let result = resultFromTags $ grTags gameRec
$info "Initial board: {}; result: {}" (show startBoard, show result)
forM_ (instructionsToMoves $ grMoves gameRec) $ \moves -> do
let (endScore, allBoards) = go [] startBoard result moves
$info "End score: {}" (Single endScore)
where
go boards lastBoard (Just result) [] = (resultToScore result, lastBoard : boards)
go boards lastBoard Nothing [] =
let score = evalBoard eval First lastBoard
in (score, lastBoard : boards)
go boards board0 mbResult (moveRec : rest) =
let board1 = case mrFirst moveRec of
Nothing -> board0
Just rec ->
let Right move1 = parseMoveRec rules First board0 rec
(board1, _, _) = applyMove rules First move1 board0
in board1
board2 = case mrSecond moveRec of
Nothing -> board1
Just rec ->
let Right move2 = parseMoveRec rules Second board1 rec
(board2, _, _) = applyMove rules Second move2 board1
in board2
in go (board1 : boards) board2 mbResult rest
resultToScore FirstWin = win
resultToScore SecondWin = loose
resultToScore Draw = 0
doLearn :: (GameRules rules, Evaluator eval)
=> rules
-> eval
-> AICacheHandle rules eval
-> AlphaBetaParams
-> GameId
-> GameRecord
-> Checkers ()
doLearn rules eval var params gameId gameRec = do
sup <- askSupervisor
supervisor <- liftIO $ atomically $ readTVar sup
let startBoard = initBoardFromTags supervisor (SomeRules rules) (grTags gameRec)
$info "Initial board: {}; tags: {}" (show startBoard, show $ grTags gameRec)
forM_ (instructionsToMoves $ grMoves gameRec) $ \moves -> do
(endScore, allBoards) <- go (0, []) startBoard [] moves
$info "End score: {}" (Single endScore)
where
go (score, boards) lastBoard _ [] = return (score, lastBoard : boards)
go (score0, boards) board0 predicted (moveRec : rest) = do
(board1, predict2, score2) <- do
case mrFirst moveRec of
Nothing -> return (board0, [], score0)
Just rec -> do
let Right move1 = parseMoveRec rules First board0 rec
if move1 `elem` map pmMove predicted
then Metrics.increment "learn.hit"
else Metrics.increment "learn.miss"
let (board1, _,_) = applyMove rules First move1 board0
(predict2, score2) <- processMove rules eval var params gameId Second move1 board1
return (board1, predict2, score2)
case mrSecond moveRec of
Nothing -> return (score2, board0 : board1 : boards)
Just rec -> do
let Right move2 = parseMoveRec rules Second board1 rec
if move2 `elem` map pmMove predict2
then Metrics.increment "learn.hit"
else Metrics.increment "learn.miss"
let (board2, _, _) = applyMove rules Second move2 board1
(predict1, score1) <- processMove rules eval var params gameId First move2 board2
go (score1, board0 : board1 : boards) board2 predict1 rest
processMove :: (GameRules rules, Evaluator eval)
=> rules
-> eval
-> AICacheHandle rules eval
-> AlphaBetaParams
-> GameId
-> Side
-> Move
-> Board
-> Checkers ([PossibleMove], Score)
processMove rules eval var params gameId side move board = do
let ai = AlphaBeta params rules eval
(moves, score) <- runAI ai var gameId side board
$info "Processed: side {}, move: {}, depth: {} => score {}; we think next best moves are: {}" (show side, show move, abDepth params, show score, show moves)
return (moves, score)
learnPdn :: (GameRules rules, VectorEvaluator eval) => AlphaBeta rules eval -> FilePath -> Checkers ()
learnPdn ai@(AlphaBeta params rules eval) path = do
cache <- loadAiCache scoreMoveGroup ai
pdn <- liftIO $ parsePdnFile (Just $ SomeRules rules) path
let n = length pdn
forM_ (zip [1.. ] pdn) $ \(i, gameRec) -> do
-- liftIO $ print pdn
$info "Processing game {}/{}..." (i :: Int, n)
doLearn rules eval cache params (show i) gameRec
-- saveAiCache rules params cache
return ()