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.

177 lines
4.8KB

  1. {-# LANGUAGE BangPatterns #-}
  2. {-# LANGUAGE DeriveGeneric #-}
  3. module Spaces where
  4. import Comonad
  5. import System.Random
  6. import Control.DeepSeq
  7. import GHC.Generics
  8. ------------
  9. -- spaces --
  10. ------------
  11. -- a locally focussed space
  12. data Space t = Space [t] t [t]
  13. deriving (Generic, Generic1)
  14. instance NFData a => NFData (Space a)
  15. instance NFData1 Space
  16. -- spaces are also functors
  17. instance Functor Space where
  18. fmap f (Space l c r) = Space (map f l) (f c) (map f r)
  19. -- our space is a comonad
  20. instance Comonad Space where
  21. -- duplicate will create a new space where
  22. -- the focussed element is our original space
  23. -- and each side is increasingly shifted copies
  24. -- in that direction
  25. duplicate w =
  26. Space (tail $ iterate left w)
  27. w
  28. (tail $ iterate right w)
  29. -- extract simply returns the focussed element
  30. extract (Space _ c _) = c
  31. -- functions for moving the point
  32. -- of locality.
  33. -- todo: question the empty list cases
  34. -- most spaces should be infinite
  35. right :: Space t -> Space t
  36. right w@(Space l m []) = w
  37. right (Space l c (r:rs)) = Space (c:l) r rs
  38. left :: Space t -> Space t
  39. left w@(Space [] m r) = w
  40. left (Space (l:ls) c r) = Space ls l (c:r)
  41. -- bound will take an infinite space
  42. -- and bound it by i and j on each side
  43. -- (not including the focus) and
  44. -- turn it into a list for printing
  45. bound :: Int -> Int -> Space t -> [t]
  46. bound i j (Space l c r) = (reverse (take i l)) ++ (c:(take j r))
  47. -- boundw works as above, but the
  48. -- entire list will be the size
  49. -- given
  50. boundw :: Int -> Space t -> [t]
  51. boundw n = bound (x-m) x
  52. where
  53. o = if odd n then 1 else 0
  54. m = if even n then 1 else 0
  55. x = (n - o) `div` 2
  56. ---------------
  57. -- 2d spaces --
  58. ---------------
  59. data Space2 t =
  60. Space2 [(Space t)]
  61. (Space t)
  62. [(Space t)]
  63. deriving (Generic, Generic1)
  64. instance NFData a => NFData (Space2 a)
  65. instance NFData1 Space2
  66. instance Functor Space2 where
  67. fmap f (Space2 u m d) =
  68. Space2 (fmap (fmap f) u) (fmap f m) (fmap (fmap f) d)
  69. instance Comonad Space2 where
  70. duplicate w =
  71. Space2 (tail $ iterate (f up2) dm)
  72. dm
  73. (tail $ iterate (f down2) dm)
  74. where
  75. f g (Space l m r) = Space (fmap g l) (g m) (fmap g r)
  76. dm = Space (tail $ iterate left2 w) w (tail $ iterate right2 w)
  77. extract (Space2 _ m _) = extract m
  78. down2 :: Space2 t -> Space2 t
  79. down2 w@(Space2 u m []) = w
  80. down2 (Space2 u m (d:ds)) = Space2 (m:u) d ds
  81. up2 :: Space2 t -> Space2 t
  82. up2 w@(Space2 [] m d) = w
  83. up2 (Space2 (u:us) m d) = Space2 us u (m:d)
  84. left2 :: Space2 t -> Space2 t
  85. left2 (Space2 u m d) = Space2 (fmap left u) (left m) (fmap left d)
  86. right2 :: Space2 t -> Space2 t
  87. right2 (Space2 u m d) = Space2 (fmap right u) (right m) (fmap right d)
  88. bound2 :: Int -> Int -> Int -> Int -> Space2 t -> [[t]]
  89. bound2 u d l r (Space2 uw mw dw) = (reverse (take u (map (bound l r) uw))) ++ ((bound l r mw):(take d (map (bound l r) dw)))
  90. bound2w :: Int -> Int -> Space2 t -> [[t]]
  91. bound2w x y = bound2 (r-q) r (n-m) n
  92. where
  93. o = if odd x then 1 else 0
  94. m = if even x then 1 else 0
  95. n = (x - o) `div` 2
  96. p = if odd y then 1 else 0
  97. q = if even y then 1 else 0
  98. r = (y - p) `div` 2
  99. bound2cw :: NFData t => Int -> Int -> Space2 t -> [[t]]
  100. bound2cw x y w = bound2 (r-q) r (n-m) n $ clamp2 (r-q+1) (r+1) (n-m+1) (n+1) w
  101. where
  102. o = if odd x then 1 else 0
  103. m = if even x then 1 else 0
  104. n = (x - o) `div` 2
  105. p = if odd y then 1 else 0
  106. q = if even y then 1 else 0
  107. r = (y - p) `div` 2
  108. clamp2cw :: NFData t => Int -> Int -> Space2 t -> Space2 t
  109. clamp2cw x y w = clamp2 (r-q+1) (r+1) (n-m+1) (n+1) w
  110. where
  111. o = if odd x then 1 else 0
  112. m = if even x then 1 else 0
  113. n = (x - o) `div` 2
  114. p = if odd y then 1 else 0
  115. q = if even y then 1 else 0
  116. r = (y - p) `div` 2
  117. clamp2 :: NFData t => Int -> Int -> Int -> Int -> Space2 t -> Space2 t
  118. clamp2 u d l r (Space2 uw mw dw)
  119. = force $ Space2 (take u $ fmap (clamp l r) uw)
  120. (clamp l r mw)
  121. (take d $ fmap (clamp l r) dw)
  122. clamp :: NFData t => Int -> Int -> Space t -> Space t
  123. clamp x y (Space l m r) = force $ Space (take x l) m (take y r)
  124. -- take a space and a rule and
  125. -- return the next space
  126. step :: Comonad w => (w t -> t) -> w t -> w t
  127. step f w = w =>> f
  128. -------------------
  129. -- Random Spaces --
  130. -------------------
  131. createRandSpace :: Random a => StdGen -> Space a
  132. createRandSpace rng =
  133. Space (tail $ map snd $ iterate f (r1, (fst (random rng))))
  134. (fst (random rng))
  135. (tail $ map snd $ iterate f (r2, (fst (random rng))))
  136. where
  137. f (r,b) = let (nb,nr) = (random r) in (nr,nb)
  138. (r1,r2) = split rng
  139. createRandSpace2 :: Random a => StdGen -> Space2 a
  140. createRandSpace2 rng =
  141. Space2 (tail $ map snd $ iterate f (r1, (createRandSpace r1)))
  142. (createRandSpace rng)
  143. (tail $ map snd $ iterate f (r2, (createRandSpace r2)))
  144. where
  145. f (r,s) = let (nr1,nr2) = split r in (nr2, (createRandSpace nr1))
  146. (r1,r2) = split rng