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.

111 lines
3.1KB

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