module Lighthouse.Display
    ( -- * Constants
      lighthouseRows, lighthouseCols
      -- * Display
    , Display (..), Row (..)
    , emptyDisplay, coloredDisplay, generateDisplay
    ) where

import qualified Data.ByteString.Lazy as BL
import Lighthouse.Utils.Color
import Lighthouse.Utils.General
import Lighthouse.Utils.Serializable
import Lighthouse.Utils.Random
import System.Random

-- | The lighthouse's width in pixels.
lighthouseCols :: Int
lighthouseCols :: Int
lighthouseCols = Int
28

-- | The lighthouse's height in pixels.
lighthouseRows :: Int
lighthouseRows :: Int
lighthouseRows = Int
14

-- | A representation of the lighthouse's pixels.
newtype Row = Row [Color] deriving (Int -> Row -> ShowS
[Row] -> ShowS
Row -> String
(Int -> Row -> ShowS)
-> (Row -> String) -> ([Row] -> ShowS) -> Show Row
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Row -> ShowS
showsPrec :: Int -> Row -> ShowS
$cshow :: Row -> String
show :: Row -> String
$cshowList :: [Row] -> ShowS
showList :: [Row] -> ShowS
Show, Row -> Row -> Bool
(Row -> Row -> Bool) -> (Row -> Row -> Bool) -> Eq Row
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Row -> Row -> Bool
== :: Row -> Row -> Bool
$c/= :: Row -> Row -> Bool
/= :: Row -> Row -> Bool
Eq)
newtype Display = Display [Row] deriving (Int -> Display -> ShowS
[Display] -> ShowS
Display -> String
(Int -> Display -> ShowS)
-> (Display -> String) -> ([Display] -> ShowS) -> Show Display
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Display -> ShowS
showsPrec :: Int -> Display -> ShowS
$cshow :: Display -> String
show :: Display -> String
$cshowList :: [Display] -> ShowS
showList :: [Display] -> ShowS
Show, Display -> Display -> Bool
(Display -> Display -> Bool)
-> (Display -> Display -> Bool) -> Eq Display
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Display -> Display -> Bool
== :: Display -> Display -> Bool
$c/= :: Display -> Display -> Bool
/= :: Display -> Display -> Bool
Eq)

-- | A black display.
emptyDisplay :: Display
emptyDisplay :: Display
emptyDisplay = Color -> Display
coloredDisplay Color
black

-- | A display with a uniformly colored background.
coloredDisplay :: Color -> Display
coloredDisplay :: Color -> Display
coloredDisplay Color
c = [Row] -> Display
Display ([Row] -> Display) -> [Row] -> Display
forall a b. (a -> b) -> a -> b
$ [Color] -> Row
Row (Color
c Color -> [Int] -> [Color]
forall a b. a -> [b] -> [a]
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ [Int
0..Int
lighthouseCols]) Row -> [Int] -> [Row]
forall a b. a -> [b] -> [a]
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ [Int
0..Int
lighthouseRows]

-- | Generates a display from the given function.
generateDisplay :: (Int -> Int -> Color) -> Display
generateDisplay :: (Int -> Int -> Color) -> Display
generateDisplay Int -> Int -> Color
pixAt = [Row] -> Display
Display ([Row] -> Display) -> [Row] -> Display
forall a b. (a -> b) -> a -> b
$ Int -> Row
rowAt (Int -> Row) -> [Int] -> [Row]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int
0..Int
lighthouseRows Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]
    where rowAt :: Int -> Row
rowAt Int
y   = [Color] -> Row
Row ([Color] -> Row) -> [Color] -> Row
forall a b. (a -> b) -> a -> b
$ (Int -> Int -> Color) -> Int -> Int -> Color
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> Int -> Color
pixAt Int
y (Int -> Color) -> [Int] -> [Color]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int
0..Int
lighthouseCols Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1]

rowToList :: Row -> [Color]
rowToList :: Row -> [Color]
rowToList (Row [Color]
xs) = [Color]
xs

displayToList :: Display -> [Row]
displayToList :: Display -> [Row]
displayToList (Display [Row]
xs) = [Row]
xs

instance Random Display where
    random :: forall g. RandomGen g => g -> (Display, g)
random    = RandomM g Display -> g -> (Display, g)
forall g a. RandomM g a -> g -> (a, g)
runRandomM (RandomM g Display -> g -> (Display, g))
-> RandomM g Display -> g -> (Display, g)
forall a b. (a -> b) -> a -> b
$ [Row] -> Display
Display ([Row] -> Display) -> RandomM g [Row] -> RandomM g Display
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> RandomM g [Row]
forall g a. (RandomGen g, Random a) => Int -> RandomM g [a]
nRandoms Int
lighthouseRows
    randomR :: forall g. RandomGen g => (Display, Display) -> g -> (Display, g)
randomR (Display, Display)
r = RandomM g Display -> g -> (Display, g)
forall g a. RandomM g a -> g -> (a, g)
runRandomM (RandomM g Display -> g -> (Display, g))
-> RandomM g Display -> g -> (Display, g)
forall a b. (a -> b) -> a -> b
$ [Row] -> Display
Display ([Row] -> Display) -> RandomM g [Row] -> RandomM g Display
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> ([Row], [Row]) -> RandomM g [Row]
forall g a.
(RandomGen g, Random a) =>
Int -> ([a], [a]) -> RandomM g [a]
nRandomsR Int
lighthouseRows (Display -> [Row]
displayToList (Display -> [Row]) -> (Display, Display) -> ([Row], [Row])
forall a b. (a -> b) -> (a, a) -> (b, b)
<.$.> (Display, Display)
r)

instance Random Row where
    random :: forall g. RandomGen g => g -> (Row, g)
random    = RandomM g Row -> g -> (Row, g)
forall g a. RandomM g a -> g -> (a, g)
runRandomM (RandomM g Row -> g -> (Row, g)) -> RandomM g Row -> g -> (Row, g)
forall a b. (a -> b) -> a -> b
$ [Color] -> Row
Row ([Color] -> Row) -> RandomM g [Color] -> RandomM g Row
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> RandomM g [Color]
forall g a. (RandomGen g, Random a) => Int -> RandomM g [a]
nRandoms Int
lighthouseCols
    randomR :: forall g. RandomGen g => (Row, Row) -> g -> (Row, g)
randomR (Row, Row)
r = RandomM g Row -> g -> (Row, g)
forall g a. RandomM g a -> g -> (a, g)
runRandomM (RandomM g Row -> g -> (Row, g)) -> RandomM g Row -> g -> (Row, g)
forall a b. (a -> b) -> a -> b
$ [Color] -> Row
Row ([Color] -> Row) -> RandomM g [Color] -> RandomM g Row
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> ([Color], [Color]) -> RandomM g [Color]
forall g a.
(RandomGen g, Random a) =>
Int -> ([a], [a]) -> RandomM g [a]
nRandomsR Int
lighthouseCols (Row -> [Color]
rowToList (Row -> [Color]) -> (Row, Row) -> ([Color], [Color])
forall a b. (a -> b) -> (a, a) -> (b, b)
<.$.> (Row, Row)
r)

-- | Converts a display to a binary representation.
instance Serializable Display where
    serialize :: Display -> ByteString
serialize (Display [Row]
d) = [ByteString] -> ByteString
BL.concat ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ Row -> ByteString
forall t. Serializable t => t -> ByteString
serialize (Row -> ByteString) -> [Row] -> [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Row]
d

instance Serializable Row where
    serialize :: Row -> ByteString
serialize (Row [Color]
r) = [ByteString] -> ByteString
BL.concat ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ Color -> ByteString
forall t. Serializable t => t -> ByteString
serialize (Color -> ByteString) -> [Color] -> [ByteString]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Color]
r