module Game.Mastermind.CodeSet where import qualified Data.Set as Set import qualified Data.List as List import qualified Data.List.Key as Key import Data.Function.HT (nest, ) import Data.Ord.HT (comparing, ) import Prelude hiding (null, ) class C set where empty :: set a union, intersection :: (Ord a) => set a -> set a -> set a unit :: set a -- | the left operand must be non-empty leftNonEmptyProduct :: Set.Set a -> set a -> set a flatten :: (Ord a) => set a -> [[a]] symbols :: (Ord a) => set a -> Set.Set a null :: set a -> Bool size :: set a -> Integer select :: set a -> Integer -> [a] representationSize :: set a -> Int -- | simplify set representation by combining set products where possible compress :: (Ord a) => set a -> set a cube :: (C set) => Set.Set a -> Int -> set a cube alphabet n = nest n (leftNonEmptyProduct alphabet) unit unions :: (C set, Ord a) => [set a] -> set a unions = foldr union empty -- simulate priority queue insertSortedBy :: (a -> a -> Ordering) -> a -> [a] -> [a] insertSortedBy cmp x = let recourse [] = [x] recourse (y:ys) = if cmp x y == GT then y : recourse ys else x:y:ys in recourse intersections :: (C set, Ord a) => [set a] -> set a intersections = let go [] = error "intersections: empty list" go [(_, set)] = set go ((_,x):(_,y):rest) = let sec = intersection x y in go (insertSortedBy (comparing fst) (size sec, sec) rest) in go . List.sortBy (comparing fst) . map (\set -> (size set, set)) intersectionsSort :: (C set, Ord a) => [set a] -> set a intersectionsSort = foldl1 intersection . Key.sort size {- | Like 'leftNonEmptyProduct' but the left operand can be empty. -} (*&) :: (C set) => Set.Set a -> set a -> set a c *& set = if Set.null c then empty else leftNonEmptyProduct c set (#*&) :: (C set) => a -> set a -> set a c #*& set = leftNonEmptyProduct (Set.singleton c) set