a one dimensional cellular automata, using comonads
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123 lines
3.5KB

  1. {-# LANGUAGE DeriveGeneric #-}
  2. module Spaces.Space2 where
  3. import Comonad
  4. import Spaces.Space1
  5. import System.Random
  6. import Data.Maybe
  7. import Control.DeepSeq
  8. import GHC.Generics
  9. -- a nested space
  10. data Space2 t = Space2 [(Space t)] (Space t) [(Space t)]
  11. deriving (Generic, Generic1, Show)
  12. -- generating strict data instances
  13. instance NFData a => NFData (Space2 a)
  14. instance NFData1 Space2
  15. -- we can fmap into this structure by recursively fmapping
  16. -- the inner spaces
  17. instance Functor Space2 where
  18. fmap f (Space2 u m d) =
  19. Space2 (fmap (fmap f) u) (fmap f m) (fmap (fmap f) d)
  20. -- map a partial function, converting to non maybe values
  21. fintermap :: (a -> Maybe a) -> [a] -> [a]
  22. fintermap _ [] = []
  23. fintermap f (a:as) = case f a of
  24. Nothing -> []
  25. Just y -> y : fintermap f as
  26. f :: ((Space2 a) -> Maybe (Space2 a)) -> Space (Space2 a) -> Maybe (Space (Space2 a))
  27. f g (Space l m r) = case (g m) of
  28. Nothing -> Nothing
  29. Just y -> Just $ Space (fintermap g l) y (fintermap g r)
  30. -- comonad instance for our 2d space
  31. instance Comonad Space2 where
  32. -- to duplicate we must recursively duplicate in all directions
  33. -- the focussed space becomes the whole space, with left and right
  34. -- mapped to each side.
  35. -- to do the up and down lists, each needs to be the middle space
  36. -- mapped up and down as far as we can.
  37. -- up2 and down2 will return Nothing when they cant go further
  38. duplicate w =
  39. Space2 (finterate (f up2) dm) dm (finterate (f down2) dm)
  40. where
  41. dm = Space (finterate left2 w) w (finterate right2 w)
  42. -- to extract we simply recursively extract
  43. extract (Space2 _ m _) = extract m
  44. -- directional moving of focus
  45. up2 :: Space2 t -> Maybe (Space2 t)
  46. up2 (Space2 [] _ _) = Nothing
  47. up2 (Space2 (u:us) m d) = Just $ Space2 us u (m:d)
  48. down2 :: Space2 t -> Maybe (Space2 t)
  49. down2 (Space2 _ _ []) = Nothing
  50. down2 (Space2 u m (d:ds)) = Just $ Space2 (m:u) d ds
  51. noLeft :: Space t -> Bool
  52. noLeft (Space [] _ _) = True
  53. noLeft _ = False
  54. noRight :: Space t -> Bool
  55. noRight (Space _ _ []) = True
  56. noRight _ = False
  57. -- left and right require mapping further
  58. -- we are assuming things are rectangular (maybe a bad idea?)
  59. left2 :: Space2 t -> Maybe (Space2 t)
  60. left2 (Space2 u m d) =
  61. if check
  62. then Nothing
  63. else Just $ Space2 (fmap (f . left) u) (f $ left m) (fmap (f . left) d)
  64. where
  65. check = noLeft m
  66. f l = fromJust l
  67. right2 :: Space2 t -> Maybe (Space2 t)
  68. right2 (Space2 u m d) =
  69. if check
  70. then Nothing
  71. else Just $ Space2 (fmap (f . right) u) (f $ right m) (fmap (f . right) d)
  72. where
  73. check = noRight m
  74. f l = fromJust l
  75. -- clamp as we do in 1d Spaces
  76. clampRel2 :: Int -> Int -> Int -> Int -> Space2 t -> Space2 t
  77. clampRel2 w x y z (Space2 u m d) = Space2 (take w $ fmap f u) (f m) (take x $ fmap f d)
  78. where
  79. f = clampRel y z
  80. clamp2 :: Int -> Int -> Space2 t -> Space2 t
  81. clamp2 w h = clampRel2 nu nd nl nr
  82. where
  83. nu = h `div` 2
  84. nd = nu - (if even h then 1 else 0)
  85. nr = w `div` 2
  86. nl = nr - (if even w then 1 else 0)
  87. mat2 :: Space2 t -> [[t]]
  88. mat2 (Space2 u m d) = (reverse (fmap mat u)) ++ ((mat m):(fmap mat d))
  89. matn2 :: Int -> Int -> Space2 t -> [[t]]
  90. matn2 w h = mat2 . (clamp2 w h)
  91. step :: Comonad w => (w t -> t) -> w t -> w t
  92. step f w = w =>> f
  93. -- create a randomly filled space
  94. createRandSpace2 :: Random a => StdGen -> Space2 a
  95. createRandSpace2 rng =
  96. Space2 (tail $ map snd $ iterate f (r1, (createRandSpace r1)))
  97. (createRandSpace rng)
  98. (tail $ map snd $ iterate f (r2, (createRandSpace r2)))
  99. where
  100. f (r,s) = let (nr1,nr2) = split r in (nr2, (createRandSpace nr1))
  101. (r1,r2) = split rng