{- Minimax algorithm including alpha-beta prunning Based on Bird & Walder "Introduction to Functional Programming" Pedro Vasconcelos, 2008-2009 -} module Minimax where import Data.Tree import List -- annotate something with an evaluation estimate data Eval a = Eval !Int a deriving (Show) instance Eq (Eval a) where (Eval x _) == (Eval y _) = x==y instance Ord (Eval a) where compare (Eval x _) (Eval y _) = compare x y instance (Show a) => Num (Eval a) where fromInteger n = Eval (fromIntegral n) undefined (+) = undefined (-) = undefined (*) = undefined abs = undefined signum= undefined negate (Eval x a) = Eval (-x) a toEval :: (Integral a, Show b) => a -> Eval b toEval = fromIntegral fromEval :: Eval a -> a fromEval (Eval _ x) = x -- naive minimax algorithm -- nodes are decorated with the static evaluation scores minimax :: (Num a, Ord a) => Tree a -> a minimax (Node n []) = n minimax (Node n ts) = - minimum (map minimax ts) -- minimax with alpha-beta prunning minimax_ab :: (Num a, Ord a) => a -> a -> Tree a -> a minimax_ab a b (Node x []) = a `max` x `min` b minimax_ab a b (Node x ts) = cmx a ts where cmx a [] = a cmx a (t:ts) | a'>=b = a' | otherwise = cmx a' ts where a' = -(minimax_ab (-b) (-a) t) -- heuristic to order subtrees with highest values first highfirst, lowfirst :: (Ord a) => Tree a -> Tree a highfirst (Node x ts) = Node x (sortBy cmp (map lowfirst ts)) where cmp (Node x _) (Node y _) = compare y x lowfirst (Node x ts) = Node x (sortBy cmp (map highfirst ts)) where cmp (Node x _) (Node y _) = compare x y -- some auxiliary rose tree functions -- prune to a fixed depth prunedepth :: Int -> Tree a -> Tree a prunedepth n (Node x ts) | n>0 = Node x (map (prunedepth (n-1)) ts) | otherwise = Node x [] -- prune to a fixed breadth prunebreadth :: Int -> Tree a -> Tree a prunebreadth n (Node x ts) = Node x (map (prunebreadth n) $ take n ts)