I’m not using extensible records in this project (source code). Game
is a big custom type handling the different states a game can be in:
type Game
= Intro
| Playing State
| Lost State LossReason
| Won State
Most of the data from an active game is part of a State
record. This can be modified when in Playing
state and is frozen in a Lost
or Win
state.
type alias State =
{ river : River
, twinPosition : Coordinate.World
, yDirection : YDirection
, scores : List Feet
}
A key insight I had was that I generally had two kinds of actions:
State -> State
which only changed the current playing state (e.g.moveTwinsDownstream
)State -> Game
which transition from one game status to another in response to a playing state change (e.g.checkLoseCondition
)
I created Game.map
and Game.andThen
helpers to compose these two types of actions. In retrospect, I probably shouldn’t have used those names
I wrote a discourse thread about learnings from this project.