minesweeper-0.9: Core/Constraint.lhs
> {-# LANGUAGE TypeFamilies, FlexibleContexts, UndecidableInstances, ScopedTypeVariables, EmptyDataDecls #-}
| Core data type for the game.
> module Core.Constraint
> where
Import List
-----------
> import Prelude hiding (null)
> import Data.Binary
> import Data.Domain
> import Data.SetClass hiding (intersection)
> import qualified Data.SetClass as S
> -- import Core.SetContainer hiding (empty, intersection)
> import Data.Data
-------------------------------------
| @Constraint a@ represents ...
> data Constraint c
> = Constraint c Int
> deriving (Eq, Read, Show, Typeable, Data)
> -- should always hold
> constraint_invariant :: Set a => Constraint a -> Bool
> constraint_invariant (Constraint d n) = n >= 0 && n <= size d && size d > 0
> sizeConstraint :: Set a => Constraint a -> Integer
> sizeConstraint (Constraint d n) = binomial (size d) n
> instance Binary a => Binary (Constraint a) where
>
> put (Constraint a b) = put (a, b)
> get = do (a,b) <- get
> return (Constraint a b)
> instance Set a => HasDomain (Constraint a) where
> type Domain (Constraint a) = a
> domain (Constraint a _) = a
> constraint :: Set a => a -> Int -> Constraint a
> constraint d i
> | constraint_invariant c = c
> | otherwise = error $ "makeConstraint: " ++ show (size d, i)
> where
> c = Constraint d i
> intersection :: Set a => Constraint a -> Constraint a -> [[Constraint a]]
> Constraint a av `intersection` Constraint b bv
> = [ filter (not . null . domain)
> [ Constraint (a `fastMinus` c) (av - cv)
> , Constraint c cv
> , Constraint (b `fastMinus` c) (bv - cv)
> ]
> | cv <- [min' .. max'] ]
> where
>
> c = S.intersection a b
>
> min' = 0 `max` (av - (size a - size c)) `max` (bv - (size b - size c))
>
> max' = size c `min` av `min` bv
>
> x `fastMinus` y
> | size x == size y = empty
> | otherwise = x \\ y
Auxiliary Definitions
---------------------
| Cached binomial numbers. The first arguent should be non-negative.
> binomial :: Int -> Int -> Integer
> binomial m n
> | n' < 0 = 0
> | otherwise = pascalsTriangle !! m !! n'
> where
> n' = min n (m-n)
| Pascal's triangle. It has to be a global constant to be cached.
> pascalsTriangle :: [[Integer]]
> pascalsTriangle
> = iterate nextRow [1] where nextRow r = 1: zipWith (+) r (tail r) ++ [1]