PlusOuMoins/src/Main.hs

102 lines
3.3 KiB
Haskell

{-# LANGUAGE NamedFieldPuns #-}
module Main where
import Control.Monad.IO.Class (MonadIO(..))
import Control.Monad.State (StateT, evalStateT, gets, modify, put)
import Level (Level(..), bounds)
import Menu (formatTitle, select)
import MainMenu (MainMenu(..))
import Mode (Mode(..))
import System.Console.ANSI (clearScreen)
import System.Random (randomRIO)
import Text.Printf (printf)
import Utils (outputLn, prompt)
data Settings = Settings {
level :: Level
, mode :: Mode
}
defaultSettings :: Settings
defaultSettings = Settings {level = Easy, mode = OnePlayer}
type Game = StateT Settings IO
initPlay :: Settings -> Game Int
initPlay (Settings {mode, level}) = do
liftIO clearScreen
case mode of
OnePlayer -> initOnePlayer $ bounds level
PlayerVsPlayer -> initPlayerVsPlayer $ bounds level
initOnePlayer :: (Int, Int) -> Game Int
initOnePlayer range@(minNumber, maxNumber) = do
mapM_ outputLn $ formatTitle "Mode un joueur, vous jouez contre moi."
outputLn (
printf "J'ai choisi un nombre compris entre %d et %d, a vous de deviner lequel" minNumber maxNumber
)
liftIO $ randomRIO range
initPlayerVsPlayer :: (Int, Int) -> Game Int
initPlayerVsPlayer range@(minNumber, maxNumber) = do
mapM_ outputLn $ formatTitle "Mode deux joueurs"
mapM_ outputLn [
printf "L'un des joueurs doit choisir secretement un nombre compris entre %d et %d que le deuxieme joueur va essayer de deviner." minNumber maxNumber
, "Écrivez le nombre choisi sans que l'autre joueur ne le voit : "
]
numberToGuess <- getSecretNumber range
liftIO clearScreen
outputLn "Le nombre choisi a ete enregistre, c'est au deuxieme joueur de le trouver."
return numberToGuess
getSecretNumber :: MonadIO m => (Int, Int) -> m Int
getSecretNumber range = prompt (return ()) (outputLn $ warning range) range
where
warning = uncurry (printf "Merci de choisir un nombre compris ENTRE %d et %d : ")
guess :: Int -> (Int, Int) -> StateT Int IO Int
guess expected range = do
n <- prompt (modify (+1) >> outputLn "Dites un nombre : ") onError range
case n of
_ | n < expected -> outputLn "C'est plus" >> guess expected range
| n > expected -> outputLn "C'est moins" >> guess expected range
| otherwise -> outputLn (found n) >> gets id
where
warning = printf "Pour rappel, le nombre choisi est compris entre %d et %d"
onError = outputLn (uncurry warning range)
found = printf "Excellent! Il fallait effectivement trouver le nombre %d"
play :: Game ()
play = do
numberToGuess <- initPlay =<< gets id
range <- gets (bounds . level)
steps <- liftIO $ evalStateT (guess numberToGuess range) 0
outputLn (printf "Bravo!!! Vous avez trouvé en %s." $ numberOfSteps steps)
select >>= dispatch
where
numberOfSteps 1 = "1 coup"
numberOfSteps n = printf "%d coups" n
settings :: Game ()
settings = do
level <- select
outputLn (printf "Vous jouez en mode %s." $ showLevel level)
mode <- select
put $ Settings {level, mode}
select >>= dispatch
where
showLevel Easy = "facile"
showLevel Normal = "moyen"
showLevel Hard = "difficile"
dispatch :: MainMenu -> Game ()
dispatch Play = play
dispatch ChangeSettings = settings
dispatch Quit = return ()
main :: IO ()
main = do
clearScreen
putStrLn "=====> JEU DU PLUS OU MOINS <====="
evalStateT (select >>= dispatch) defaultSettings