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.

90 lines
2.7KB

  1. {-# LANGUAGE DeriveGeneric #-}
  2. module Automata where
  3. import Comonad
  4. import Spaces
  5. import System.Random
  6. import GHC.Generics
  7. import Control.DeepSeq
  8. -----------------------
  9. -- cellular automata --
  10. -----------------------
  11. -- the states our cells can be in
  12. -- may need to provide an ordering
  13. -- may need to generalise the number
  14. -- of states
  15. data CellState = Rock | Paper | Scissors
  16. deriving (Eq, Bounded, Enum, Generic)
  17. instance NFData CellState
  18. instance Random CellState where
  19. random g = case randomR (fromEnum (minBound :: CellState), fromEnum (maxBound :: CellState)) g of
  20. (r, g') -> (toEnum r, g')
  21. randomR (a,b) g = case randomR (fromEnum a, fromEnum b) g of
  22. (r, g') -> (toEnum r, g')
  23. -- how the states are displayed on screen
  24. -- this should probably be input to a function
  25. -- rather than hardcoded
  26. instance Show CellState
  27. where
  28. show Rock = "⬤"
  29. show Paper = " "
  30. show Scissors = "_"
  31. -- -- a rule stating how a cell is determined
  32. -- rule :: Space CellState -> CellState
  33. -- rule (Space (l:_) _ (r:_))
  34. -- | l == r = Dead
  35. -- | otherwise = Alive
  36. --
  37. -- -- a second rule for example
  38. -- rule2 :: Space CellState -> CellState
  39. -- rule2 (Space (l1:l2:_) m (r1:r2:_))
  40. -- | m == Alive && numAlive == 1 = Dead
  41. -- | m == Alive && numAlive == 4 = Dead
  42. -- | m == Dead && numAlive == 3 = Alive
  43. -- | otherwise = m
  44. -- where
  45. -- ns = [l1, l2, r1, r2]
  46. -- numAlive = length $ filter (== Alive) ns
  47. --
  48. -- rule3 :: Space CellState -> CellState
  49. -- rule3 (Space (l:_) m (r:_))
  50. -- | l == r = m
  51. -- | otherwise = if m == Alive then Dead else Alive
  52. --------------
  53. -- 2d rules --
  54. --------------
  55. rps :: Space2 CellState -> CellState
  56. rps (Space2 u m d)
  57. = case me of
  58. Rock -> if (length $ filter (== Paper) ns) > 2 then Paper else Rock
  59. Paper -> if (length $ filter (== Scissors) ns) > 2 then Scissors else Paper
  60. Scissors -> if (length $ filter (== Rock) ns) > 2 then Rock else Scissors
  61. where
  62. f b (Space (l:_) m (r:_)) = [l,r] ++ (if b then [m] else [])
  63. f b (Space [] m (r:_)) = [r] ++ (if b then [m] else [])
  64. f b (Space (l:_) m []) = [l] ++ (if b then [m] else [])
  65. f b (Space [] m []) = if b then [m] else []
  66. safeHead _ [] = []
  67. safeHead b (x:_) = f b x
  68. ns = concat [ (safeHead True u), (f False m), (safeHead True d) ]
  69. me = extract m
  70. --conway :: Space2 CellState -> CellState
  71. --conway (Space2 (u:_) m (d:_))
  72. -- = case me of
  73. -- Alive -> if (length ns) == 2 || (length ns == 3) then Alive else Dead
  74. -- Dead -> if (length ns) == 3 then Alive else Dead
  75. -- where
  76. -- f b (Space (l:_) m (r:_)) = [l,r] ++ (if b then [m] else [])
  77. -- ns = filter (== Alive) $ concat [ (f True u), (f False m), (f True d) ]
  78. -- me = extract m