L-seed-0.1: src/Lseed/Data.hs
-- | 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)