crem-0.1.0.0: examples/Crem/Example/TheHobbit.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
-- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wmissing-deriving-strategies
{-# OPTIONS_GHC -Wno-missing-deriving-strategies #-}
-- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunticked-promoted-constructors
{-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-}
-- https://downloads.haskell.org/ghc/latest/docs/users_guide/using-warnings.html#ghc-flag--Wunused-type-patterns
{-# OPTIONS_GHC -Wno-unused-type-patterns #-}
module Crem.Example.TheHobbit where
import Crem.BaseMachine
import Crem.Render.RenderableVertices (AllVertices (..), RenderableVertices)
import Crem.Topology
import "base" Data.Semigroup
import "singletons-base" Data.Singletons.Base.TH
data HobbitCommand
= GoEast
| GoWest
| GoNorth
| GoSouth
| Wait
| GetKey
| UnlockDoor
deriving stock (Eq, Read, Show)
newtype HobbitMessage = HobbitMessage {getMessage :: String}
deriving (Semigroup) via (Last HobbitMessage)
instance Monoid HobbitMessage where
mempty = HobbitMessage ""
$( singletons
[d|
data HobbitVertex
= TunnelLikeHall
| Lonelands
| TrollsClearing
| Rivendell
| MistyMountain
| TrollsPath
| TrollsCave
deriving stock (Eq, Show, Enum, Bounded)
hobbitTopology :: Topology HobbitVertex
hobbitTopology =
Topology
[ (TunnelLikeHall, [Lonelands])
, (Lonelands, [TunnelLikeHall, TrollsClearing])
, (TrollsClearing, [Rivendell, TrollsPath])
, (Rivendell, [TrollsClearing, MistyMountain])
, (MistyMountain, [Rivendell])
, (TrollsPath, [TrollsClearing, TrollsCave])
, (TrollsCave, [TrollsPath])
]
|]
)
deriving via AllVertices HobbitVertex instance RenderableVertices HobbitVertex
data KeyState
= NoKey
| DayDawned
| GotKey
| DoorUnlocked
deriving stock (Eq)
data HobbitState (vertex :: HobbitVertex) where
TunnelLikeHallState :: HobbitState 'TunnelLikeHall
LonelandsState :: HobbitState 'Lonelands
TrollsClearingState :: KeyState -> HobbitState 'TrollsClearing
RivendellState :: KeyState -> HobbitState 'Rivendell
MistyMountainState :: KeyState -> HobbitState 'MistyMountain
TrollsPathState :: KeyState -> HobbitState 'TrollsPath
TrollsCaveState :: HobbitState 'TrollsCave
stateMessage :: HobbitState vertex -> HobbitMessage
stateMessage TunnelLikeHallState =
HobbitMessage
"You are in a tunnel-like hall.\n\
\You can only go east to the Lonelands"
stateMessage LonelandsState =
HobbitMessage
"You are in the lonelands.\n\
\You can either go west to a tunnel-like hall\n\
\or go east to the Trolls clearing"
stateMessage (TrollsClearingState keyState) =
if keyState == DayDawned
then
HobbitMessage
"You are in the Trolls clearing.\n\
\You could go north to the Trolls path,\n\
\you can go east to Rivendell\n\
\or you could get the key for the TrollsCave"
else
HobbitMessage
"You are in the Trolls clearing.\n\
\You could go north to the Trolls path,\n\
\you can go east to Rivendell"
stateMessage (RivendellState _) =
HobbitMessage
"You are in Rivendell.\n\
\You could either go west to the Trolls clearing\n\
\or go east to the Misty mountains\n"
stateMessage (MistyMountainState _) =
HobbitMessage
"You are in the Misty mountains.\n\
\You can only go east to Rivendell"
stateMessage (TrollsPathState keyState) =
case keyState of
NoKey ->
HobbitMessage
"You are in the Trolls path.\n\
\You can go south to the Trolls clearing\n\
\or you can wait a bit"
DayDawned ->
HobbitMessage
"You are in the Trolls path.\n\
\You can go south to the Trolls clearing\n\
\or you can wait some more"
GotKey ->
HobbitMessage
"You are in the Trolls path.\n\
\You can go south to the Trolls clearing,\n\
\you can unlock the door to the Trolls cave\n\
\or you can wait some more"
DoorUnlocked ->
HobbitMessage
"You are in the Trolls path.\n\
\You can go south to the Trolls clearing\n\
\or you can go north to the Trolls cave"
stateMessage TrollsCaveState =
HobbitMessage
"Welcome to the Trolls cave!\n\
\Now you can go back south to the Trolls path"
hobbitResult
:: (Applicative m, AllowedTransition HobbitTopology initialVertex finalVertex)
=> HobbitState finalVertex
-> ActionResult m HobbitTopology HobbitState initialVertex HobbitMessage
hobbitResult hobbitState = pureResult (stateMessage hobbitState) hobbitState
hobbitMachine :: HobbitState vertex -> BaseMachine HobbitTopology HobbitCommand HobbitMessage
hobbitMachine initialState =
BaseMachineT
{ initialState = InitialState initialState
, action = \case
TunnelLikeHallState -> \case
GoEast -> hobbitResult LonelandsState
_ -> hobbitResult TunnelLikeHallState
LonelandsState -> \case
GoEast -> hobbitResult $ TrollsClearingState NoKey
GoWest -> hobbitResult TunnelLikeHallState
_ -> hobbitResult LonelandsState
TrollsClearingState keyState -> \case
GoEast -> hobbitResult $ RivendellState NoKey
GoNorth -> hobbitResult $ TrollsPathState keyState
GetKey ->
if keyState == DayDawned
then hobbitResult $ TrollsClearingState GotKey
else hobbitResult $ TrollsClearingState keyState
_ -> hobbitResult $ TrollsClearingState keyState
RivendellState keyState -> \case
GoEast -> hobbitResult $ MistyMountainState keyState
GoWest -> hobbitResult $ TrollsClearingState keyState
_ -> hobbitResult $ RivendellState keyState
MistyMountainState keyState -> \case
GoWest -> hobbitResult $ RivendellState keyState
_ -> hobbitResult $ MistyMountainState keyState
TrollsPathState keyState -> \case
GoSouth -> hobbitResult $ TrollsClearingState keyState
GoNorth ->
if keyState == DoorUnlocked
then hobbitResult TrollsCaveState
else hobbitResult $ TrollsPathState keyState
Wait ->
if keyState == NoKey
then hobbitResult $ TrollsPathState DayDawned
else hobbitResult $ TrollsPathState keyState
UnlockDoor ->
if keyState == GotKey
then hobbitResult $ TrollsPathState DoorUnlocked
else hobbitResult $ TrollsPathState keyState
_ -> hobbitResult (TrollsPathState keyState)
TrollsCaveState -> \case
GoSouth -> hobbitResult $ TrollsPathState DoorUnlocked
_ -> hobbitResult TrollsCaveState
}