102 lines
3.3 KiB
Haskell
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
|