Me and my friends play a variant of Morra when drinking. The rules are as follows:
The players sit in a circle and hold one of their hands in front of them.
One player guesses a number. All the players (including this one) then hold out between 0 and 5 fingers on their hand.
If there are as many fingers held out as the player guessed, he is "saved", leaves the circle and doesn't have to play anymore. Next turn another player tries to guess (otherwise the game just goes on with the player staying in the circle).
The last player to remain in the circle has to drink.
I'm just learning about monad transformers, so I thought it would be nice to implement this simple game.
module Morra where import Control.Monad.Trans.State import Control.Monad.Trans import Control.Monad import Data.List import Data.Char main :: IO () main = do putStrLn "Welcome to Morra. The last to remain has to drink." putStr "Please input the names of players: " psraw <- getLine putStrLn "" ([p], n) <- execStateT (play 0) (words psraw, 0) putStrLn $ p ++ " has lost, after " ++ show n ++ " rounds. (S)he has to take a shot." play :: Int -> StateT ([String], Int) IO () play p = do (ps, n) <- get let currp = ps !! p if length ps == 1 then put (ps, n) else do liftIO $ putStr $ "It's now " ++ currp ++ "'s turn. How many fingers will be help up? " a <- liftIO safeGetLine putNewLine liftIO $ putStrLn "[INPUT PHASE] Each player now chooses, how many fingers does (s)he hold up." fs <- liftIO $ getFingers (length ps) liftIO $ putStr "[END OF INPUT PHASE]" putNewLine if sum fs == a then do liftIO $ putStrLn $ currp ++ " has guessed right, he's out." putNewLine let newps = delete currp ps put (newps, n + 1) play ((p + 1) `mod` length newps) else do liftIO $ putStrLn $ currp ++ " hasn't guessed right, the game goes on!" putNewLine put (ps, n + 1) play ((p + 1) `mod` length ps) where putNewLine = liftIO $ putStrLn "" getFingers :: Int -> IO [Int] getFingers n = replicateM n helper where helper = do putStr "Input the number of fingers you hold up: " fs <- safeGetLine putStrLn "Pass the computer to the next player now. [ENTER]" getLine return fs safeGetLine :: IO Int safeGetLine = do x <- getLine if all isNumber x then return $ read x else do putStrLn "Please input a number" safeGetLine
Firstly, you can see the strings I print are pretty long, longer than the 80 chars limit. What is the common approach to tackle these and keep all the lines below 80 chars?
And secondly, please point out anything that could be made more elegant, whatever that might be (even changing the underlaying StateT). I'm also open to new ideas and challenges.