module FilterGames where
import Iso
import Games
import BasicGames
import Data.Maybe
voidGame :: Game t
voidGame = Split (Iso ask bld) voidGame voidGame
where ask = Right
bld (Left x) = x
bld (Right x) = x
filterGame :: (t -> Bool) -> Game t -> Game t
filterGame p g@(Single (Iso _ bld)) =
if p (bld ()) then g else voidGame
filterGame p (Split (Iso ask bld) g1 g2)
= Split (Iso ask bld) (filterGame (p . bld . Left) g1)
(filterGame (p . bld . Right) g2)
filterGameOpt :: (t -> Bool) -> Game t -> Maybe (Game t)
filterGameOpt f (Single iso)
| f (from iso ()) = Just $ Single iso
| otherwise = Nothing
filterGameOpt f (Split (Iso ask bld) g1 g2)
= case filterGameOpt (f . bld . Left) g1 of
Nothing ->
case filterGameOpt (f . bld . Right) g2 of
Nothing -> Nothing
Just g2' -> Just (g2' +> iso2)
Just g1' ->
case filterGameOpt (f . bld . Right) g2 of
Nothing -> Just (g1' +> iso1)
Just g2' -> Just $ Split (Iso ask bld) g1' g2'
where iso1 = Iso (\x -> case ask x of Left x1 -> x1)
(bld . Left)
iso2 = Iso (\x -> case ask x of Right x2 -> x2)
(bld . Right)
filterFinGame :: (t -> Bool) -> Game t -> Maybe (Game t)
filterFinGame p g@(Single (Iso _ bld)) =
if p (bld ()) then Just g else Nothing
filterFinGame p (Split iso@(Iso ask bld) g1 g2)
= case (filterFinGame (p . bld . Left) g1,
filterFinGame (p . bld . Right) g2) of
(Nothing, Nothing) -> Nothing
(Just g1', Nothing) -> Just $ g1' +> iso1
(Nothing, Just g2') -> Just $ g2' +> iso2
(Just g1', Just g2') -> Just $ Split iso g1' g2'
where fromLeft (Left x) = x
fromRight (Right x) = x
iso1 = Iso (fromLeft . ask) (bld . Left )
iso2 = Iso (fromRight . ask) (bld . Right)
pre_filterGame_inf :: Eq t => Game t -> (t -> Bool) -> Game t
pre_filterGame_inf stack f
= case unfoldUntil stack of
(x,rest) | f x ->
let iso = Iso ask (either id id)
ask z = if x == z then Left z else Right z
sing_iso = Iso (\_ -> ()) (\_ -> x)
in Split iso (Single sing_iso) (pre_filterGame_inf rest f)
| otherwise -> pre_filterGame_inf rest f
filterInfGame :: forall t. Eq t => (t -> Bool) -> Game t -> Game t
filterInfGame f g = pre_filterGame_inf (mkStack g) f
where mkStack g = Split (iso :: ISO t (Either t t)) g (Single undefined)
iso = Iso Left (either id id)
unfoldUntil :: Game t -> (t, Game t)
unfoldUntil stack = case find stack of
Left (x,rest) -> (x,rest)
Right unfolded -> unfoldUntil unfolded
unfoldOne :: forall t. Game t -> Game t
unfoldOne (Single undef) = Single undef
unfoldOne (Split iso (Single siso) rest)
= Split iso (Single siso) (unfoldOne rest)
unfoldOne (Split iso (Split iso' g1 g2) rest)
= shufflePartition (Split iso (Split iso' g1 g2) (unfoldOne rest))
find :: forall t. Game t -> Either (t,Game t) (Game t)
find (Single undef) = Right (Single undef)
find (Split (iso :: ISO t (Either t1 t2)) (Single siso) rest)
= let x = from iso $ Left (from siso ())
unfolded = unfoldOne rest +> ciso
ciso :: ISO t t2
ciso = Iso (\x -> case to iso x of Right x2 -> x2) (from iso . Right)
in Left (x,unfolded)
find (Split siso (Split siso' g1 g2) rest)
= case find rest of
Left (x, unfolded) -> Left (from siso (Right x), shufflePartition (Split siso (Split siso' g1 g2) unfolded))
Right unfolded -> Right (shufflePartition (Split siso (Split siso' g1 g2) unfolded))
shufflePartition :: forall t. Game t -> Game t
shufflePartition (Split (siso :: ISO t (Either t1 trest))
(Split (siso' :: ISO t1 (Either t11 t12)) g1 g2) rest)
= Split siso1 g1 (Split siso2 g2 rest)
where siso2 = idI
siso1 = Iso ask bld
ask :: t -> Either t11 (Either t12 trest)
ask x = case to siso x of
Left x1 -> case to siso' x1 of
Left x11 -> Left x11
Right x12 -> Right (Left x12)
Right xrest -> Right (Right xrest)
bld (Left x11) = from siso $ Left (from siso' (Left x11))
bld (Right (Left x12)) = from siso $ Left (from siso' (Right x12))
bld (Right (Right xrest)) = from siso $ Right xrest
mkOddNatGame = filterInfGame odd unaryNatGame
test_odd0 bitstream = dec mkOddNatGame bitstream
test_odd1 num = enc mkOddNatGame num