-- | Data definitions for L-seed module Lseed.Data where import Data.Foldable (Foldable, foldMap) import Data.Traversable (Traversable, sequenceA) import Control.Applicative ((<$>),(<*>),pure) import Control.Arrow (second) import Data.Monoid import System.Time (ClockTime) -- | User Tag type UserTag = String -- | Light angle type Angle = Double -- | A list of plants, together with their position in the garden, in the interval [0,1] type Garden a = [ Planted a ] -- | Named variants of a garden, for more expressive type signatures type GrowingGarden = Garden GrowthState type AnnotatedGarden = Garden StipeInfo -- | A plant with metainformatoin data Planted a = Planted { plantPosition :: Double -- ^ Position in the garden, interval [0,1] , plantOwner :: Integer -- ^ Id of the user that owns this plant , genome :: GrammarFile -- ^ Lsystem in use , phenotype :: Plant a -- ^ Actual current form of the plant } deriving (Show) -- | Named variants of a Planted, for more expressive type signatures type GrowingPlanted = Planted GrowthState type AnnotatedPlanted = Planted StipeInfo -- | A plant, which is data Plant a -- | a stipe with a length (factor of stipeLength), an angle relative -- to the parent stipe and a list of plants sprouting at the end = Plant { pData :: a , pLength :: Double , pAngle :: Angle , pUserTag :: UserTag , pBranches :: [ Plant a ] } deriving (Show) -- | A straight, untagged plant with length zero and no branches. inititalPlant = Plant () 0 0 "" [] data StipeInfo = StipeInfo { siLength :: Double -- ^ a bit redundant, but what shells , siSubLength :: Double , siLight :: Double , siSubLight :: Double , siAngle :: Angle , siDirection :: Angle , siGrowth :: GrowthState , siOffset :: Double -- ^ Sideways position, relative to Plant origin , siHeight :: Double -- ^ Vertical distance from bottom } deriving (Show) -- | A GrowingPlant can be growing in one of these three ways: data GrowthState = NoGrowth | EnlargingTo Double -- ^ value indicates the growth target | GrowingSeed Double -- ^ value indicates the current state [0..1] deriving (Show) -- | Named variants of a Plant, for more expressive type signatures type GrowingPlant = Plant GrowthState type AnnotatedPlant = Plant StipeInfo -- | Representation of what is on screen data ScreenContent = ScreenContent { scGarden :: AnnotatedGarden , scLightAngle :: Double , scTime :: String } -- | Main loop observers data Observer = Observer { -- | Called once, before the main loop starts obInit :: IO () -- | Called once per tick, with the current tick number and the current -- state of the garden , obState :: Integer -> GrowingGarden -> IO () -- | Also called once per tick, with a function that calculates the -- information that should be displayed given a point in time , obGrowingState :: (ClockTime -> ScreenContent) -> IO () -- | Called before the main loop quits, with the last state of the garden , obFinished :: GrowingGarden -> IO () } nullObserver = Observer (return ()) (\_ _ -> return ()) (\_ -> return ()) (\_ -> return ()) -- | A complete grammar file type GrammarFile = [ GrammarRule ] type Priority = Int type Weight = Int defaultPriority :: Priority defaultPriority = 0 defaultWeight :: Weight defaultWeight = 1 -- | A single Rule. For now, only single branches -- can be matched, not whole subtree structures data GrammarRule = GrammarRule { grName :: String , grPriority :: Priority , grWeight :: Weight , grCondition :: Condition , grAction :: GrammarAction } deriving (Read,Show) data Matchable = MatchLight | MatchSubLight | MatchLength | MatchSubLength | MatchDirection | MatchAngle deriving (Read,Show) data Cmp = LE | Less | Equals | Greater | GE deriving (Read,Show) data Condition = Always Bool -- constant conditions | Condition `And` Condition | Condition `Or` Condition | UserTagIs String | NumCond Matchable Cmp Double deriving (Read,Show) data GrammarAction = SetLength (Maybe UserTag) LengthDescr | AddBranches (Maybe UserTag) Double [(Angle, Double, Maybe UserTag)] | Blossom (Maybe UserTag) deriving (Read,Show) data LengthDescr = Absolute Double | Additional Double | AdditionalRelative Double -- ^ in Percent deriving (Read,Show) -- Instances instance Functor Plant where fmap f p = p { pData = f (pData p) , pBranches = map (fmap f) (pBranches p) } instance Foldable Plant where foldMap f p = mconcat $ f (pData p) : map (foldMap f) (pBranches p) instance Traversable Plant where sequenceA (Plant x len ang ut ps) = Plant <$> x <*> pure len <*> pure ang <*> pure ut <*> sequenceA (map sequenceA ps) instance Functor Planted where fmap f planted = planted { phenotype = fmap f (phenotype planted) } instance Foldable Planted where foldMap f planted = foldMap f (phenotype planted) instance Traversable Planted where sequenceA planted = (\x -> planted { phenotype = x }) <$> sequenceA (phenotype planted)