module Game.Halma.AI.Base ( Move , outcome , Rating (..) , rateTeam , allOwnPieces , allLegalMoves ) where import Game.Halma.Board import Game.Halma.Rules import Data.List (sort) import Math.Geometry.Grid import qualified Data.Map.Strict as M outcome :: HalmaBoard -> Move -> HalmaBoard outcome board move = case movePiece move board of Left err -> error $ "cannot compute outcome: " ++ err Right board' -> board' data Rating = WinIn Int | Rating Float | LossIn Int deriving (Show, Eq) instance Ord Rating where compare (WinIn n) (WinIn m) = compare m n compare (WinIn _) _ = GT compare _ (WinIn _) = LT compare (LossIn n) (LossIn m) = compare n m compare (LossIn _) _ = LT compare _ (LossIn _) = GT compare (Rating a) (Rating b) = compare a b instance Bounded Rating where maxBound = WinIn 0 minBound = LossIn 0 rateTeam :: Team -> HalmaBoard -> Rating rateTeam team board | hasFinished board team = WinIn 0 | otherwise = Rating . negate . sum $ zipWith (*) pieceWeightingList (sort distances) where grid = getGrid board distanceToEndCorner = fromIntegral . distance grid (endCorner grid team) distances = map distanceToEndCorner (allOwnPieces board team) pieceWeightingList = replicate 12 2 ++ [3..5] allOwnPieces :: HalmaBoard -> Team -> [Index HalmaGrid] allOwnPieces board team = map fst $ filter (isMyPiece . snd) $ M.assocs (toMap board) where isMyPiece piece = pieceTeam piece == team allLegalMoves :: RuleOptions -> HalmaBoard -> Team -> [Move] allLegalMoves opts board team = do piecePos <- allOwnPieces board team endPos <- possibleMoves opts board piecePos pure Move { moveFrom = piecePos, moveTo = endPos }