packages feed

tak-ai-0.1.0.1: src/TakkyCore.hs

{-# LANGUAGE TypeFamilies #-}
module TakkyCore where

import qualified Data.Foldable as Foldable
import System.IO.Unsafe
import System.Random.Shuffle

import Tak
import PlayTakBot

import qualified Negamax

data Takky = Takky String String

instance Bot Takky where
    botName (Takky username _) = username
    botPassword (Takky _ password) = password
    botEvaluate _ colour botGameState = evaluate colour botGameState
    botChoosePlay _ botGameState = Negamax.chooseplay 3 botGameState 

instance Negamax.Game (BotGameState) where
    type Play BotGameState = Play
    plays botGameState = unsafePerformIO $
        shuffleM $ map (\ (GameBranch p n) -> (p, botGameState{bgsTree = n})) branches
        where GameNode _ _ branches = bgsTree botGameState 
    eval (BotGameState (GameNode _ score _) _) = score
    ourmove (BotGameState (GameNode state _ _) colour) = stPlaysNext state == colour
    finished (BotGameState (GameNode state _ _) _) = stFinished state /= Nothing

--instance Show Takky where
--    show (Takky tree _) = show $ showState $ treeGameState tree

-- | Assigns a score to the current state of the game, from the perspective of
--   black or white. Higher scores indicate an advantageous position.
--   For now, just see who owns more squares.
evaluate :: Colour -> GameState -> Double
evaluate colour state =
    let rand = 0 in --(unsafePreformIO randomIO :: Double) / 100 in
    case stFinished state of
        Nothing ->
            rand + territoryScore (stBoard state) colour
        Just (RoadWin colour') -> if colour == colour'
            then 1e100
            else -1e100
        Just (FlatWin colour' _ _) -> if colour == colour'
            then 1e100
            else -1e100
        Just (Draw _ _) -> 0.0

territoryScore :: Board -> Colour -> Double
territoryScore board ourColour = Foldable.foldr fn 0 board where
    fn [] score = score
    fn ((Flat, colour) : rest) score
        | colour == ourColour = (score + 1) + scoreRest ourColour colour rest
        | otherwise = (score - 1) + scoreRest ourColour colour rest
    fn ((_, colour) : rest) score = score + scoreRest ourColour colour rest

scoreRest :: Colour -> Colour -> Square -> Double
scoreRest ourColour topColour rest = foldr fn 0 rest where
    fn (_, colour) score = score + if colour == topColour
        then if colour == ourColour
            then 0.75
            else -0.75
        else if colour == ourColour
            then 0.25
            else -0.25