Skip to content

Instantly share code, notes, and snippets.

@emdash
Created March 4, 2023 03:24
Show Gist options
  • Save emdash/9028fed617c57603298f8036e69d18f4 to your computer and use it in GitHub Desktop.
Save emdash/9028fed617c57603298f8036e69d18f4 to your computer and use it in GitHub Desktop.
Ch14 Verified Guessing Game
module Main
import Data.Vect
namespace Game
data State : Type where
NotRunning : State
Running : (guesses : Nat) -> (letters : Nat) -> State
total
letters : String -> List Char
letters str = nub (map toUpper (unpack str))
total
beginGame : String -> (a -> State)
beginGame word = const (Running 6 (length (letters word)))
total
endGame : (a -> State)
endGame = const NotRunning
total
losing : Nat -> State
losing guesses = Running 0 (S guesses)
total
winning : Nat -> State
winning guesses = Running (S guesses) 0
total
playing : Nat -> Nat -> State
playing guesses letters = Running (S guesses) (S letters)
data GuessResult
= Correct
| Incorrect
total
tryGuess : Nat -> Nat -> GuessResult -> State
tryGuess guesses letters Correct = Running (S guesses) letters
tryGuess guesses letters Incorrect = Running guesses (S letters)
data Command
: (ty : Type)
-> State
-> (ty -> State)
-> Type
where
NewGame : (word : String) -> Command () NotRunning beginGame
Won : Command () (winning guesses) endGame
Lost : Command () (losing guesses) endGame
Guess : (c : Char) -> Command GuessResult (playing guesses letters) (tryGuess guesses letters)
Pure : (res : ty) -> Command ty (state_fn res) state_fn
Show : Command () state (const state)
Message : String -> Command () state (const state)
Read : Command Char state (const state)
(>>=)
: (Command a s1 s2f)
-> ((res : a) -> Command b (s2f res) s3f)
-> Command b s1 s3f
data WordState
: (guesses : Nat)
-> (letters : Nat)
-> Type
where
MkWordState
: (word : string)
-> (missing : Vect letters Char)
-> WordState guesses_remaining letters
namespace Loop
data Loop
: (ty : Type)
-> State
-> (ty -> State)
-> Type
where
(>>=)
: Command a s1 s2f
-> ((res : a) -> Inf (Loop b (s2f res) s3f))
-> Loop b s1 s3f
Exit : Loop () NotRunning endGame
loop : Loop () (playing guesses letters) endGame
loop {guesses} {letters} = do
Show
g <- Read
ok <- Guess g
case ok of
Correct => case letters of
Z => do
Won
Show
Exit
S k => do
Message "Correct"
loop
Incorrect => case guesses of
Z => do
Lost
Show
Exit
(S k) => do
Message "Incorrect"
loop
data Game : State -> Type where
Start : Game NotRunning
Win : (word : String) -> Game NotRunning
Loss : (word : String) -> Game NotRunning
InProgress
: (word : String)
-> (guesses : Nat)
-> (missing : Vect letters Char)
-> Game (Running guesses letters)
Show (Game g) where
show Start = "Starting"
show (Win word) = "Win: word was " ++ word
show (Loss word) = "Loss: word was " ++ word
show (InProgress word guesses missing) =
"\n"
++ pack (map (hideMissing) (unpack word))
++ "\n"
++ show guesses
++ " guesses remain"
where
hideMissing : Char -> Char
hideMissing c = if c `elem` missing then '-' else c
data Result
: (ty : Type)
-> (ty -> State)
-> Type
where
OK
: (res : ty)
-> Game (outstate_fn res)
-> Result ty outstate_fn
OutOfFuel : Result ty outstate_fn
data Fuel = Dry | More (Lazy Fuel)
ok : (res : ty) -> Game (outstate_fn res) -> IO (Result ty outstate_fn)
ok res st = pure (OK res st)
runCmd
: Fuel
-> Game instate
-> Command ty instate outstate_fn
-> IO (Result ty outstate_fn)
run
: Fuel
-> Game instate
-> Loop ty instate outstate_fn
-> IO (Result ty outstate_fn)
run Dry _ _ = pure OutOfFuel
run (More fuel) st (cmd >>= next) = do
OK cmdRes newSt <- runCmd fuel st cmd | OutOfFuel => pure OutOfFuel
run fuel newSt (next cmdRes)
run (More fuel) st Exit = ok () st
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment