packages feed

minesweeper-0.8.9: Core/Constraint.lhs

> {-# LANGUAGE TypeFamilies, FlexibleContexts, UndecidableInstances, ScopedTypeVariables, EmptyDataDecls #-}

| Core data type for the game.

> module Core.Constraint
>      where


Import List
-----------

> import Core.SetContainer
> import Core.Square

> import Data.Binary
> import Data.SetClass

> --import Data.List hiding (null, union, (\\))
> import Prelude hiding (null)


-------------------------------------

| @Constraint a@ represents ...

> data Constraint c
>     = Constraint c Int
>         deriving (Eq, Read, Show)

> -- 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 b) = 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
>
> intersectionC :: Set a => Constraint a -> Constraint a -> [[Constraint a]]
> Constraint a av `intersectionC` Constraint b bv
>         = [ filter valid
>              [ Constraint (a `fastMinus` c) (av - cv)
>              , Constraint  c                 cv
>              , Constraint (b `fastMinus` c) (bv - cv) 
>              ] 
>           | cv <- [min' .. max'] ]     
>       where 
> 
>         c = intersection a b     
> 
>         min' = 0 `max` (av - (size a - size c)) `max` (bv - (size b - size c))      
>
>         max' = size c `min` av `min` bv     
>
>         valid (Constraint d n) = not (null d)
>
>         x `fastMinus` y 
>           | size x == size y = empty
>           | otherwise = x \\ y

-----------------------------------------

> data Clear
> data Bomb

> class Decide a where
>   num :: Set b => a -> b -> Int

> instance Decide Bomb where num _ = size
> instance Decide Clear where num _ = const 0

> data (SetContainer a) => EitherC x a
>     = EitherC (Domain (SetContainerElem a)) a
> --        deriving (Show)

> instance Show (EitherC x a) where

> instance (SetContainer a, Binary (Domain (SetContainerElem a)), Binary a) => Binary (EitherC x a) where
> 
>     put (EitherC a b) = put (a, b)
>     get = do (a,b) <- get
>              return (EitherC a b)


> instance (SetContainer a, SetContainerElem a ~ Constraint b, Set b, Decide x) 
>       => SetContainer (EitherC x a) where

>     type SetContainerElem (EitherC x a) = SetContainerElem a

>     emptyC = EitherC empty emptyC

>     decomp (EitherC i o) = [OneElem (Constraint i (num (undefined :: x) i)) | not (null i)] ++ decomp o

>     insertL c@(Constraint s n) (EitherC i o)
>         | n == num (undefined :: x) s      = EitherC (i `union` s) o
>         | otherwise   = EitherC i (insertL c o)

>     relatedElems c@(Constraint s _) (EitherC i o)
>       =  [ (Constraint e (num (undefined :: x) e), EitherC (i \\ e) o) 
>          | let e = s `intersection` i, not (null e) ]
>       ++ [ (x, EitherC i o') | (x, o') <- relatedElems c o ]



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]