In today’s Programming Praxis exercise, our goal is to implement the well-known “Petals Around the Rose” game. Let’s get started, shall we?

Some imports:

import Control.Monad import System.Random import Text.Printf

We’ll need to show the intro text.

showIntro :: IO () showIntro = putStrLn "Let's play 'Petals Around The Rose.'\n\ \The name of the game is significant.\n\ \At each turn I will roll five dice,\n\ \then ask you for the score, which\n\ \will always be zero or an even number.\n\ \After you guess the score, I will tell\n\ \you if you are right, or tell you the\n\ \correct score if you are wrong. The game\n\ \ends when you prove that you know the\n\ \secret by guessing the score correctly\n\ \six times in a row.\n"

When playing, we keep a count of the current streak length. After 6 consecutive correct guesses we assume the player has figured out the trick. Otherwise, we roll 5 dice and see if the player’s guess is correct.

play :: Int -> IO () play 6 = putStrLn "Congratulations! You are now a member\n\ \of the Fraternity of the Petals Around\n\ \The Rose. You must pledge never to\n\ \reveal the secret to anyone." play streak = do dice <- replicateM 5 $ randomRIO (1,6) putStrLn $ "The five dice are: " ++ unwords (map show dice) putStr "What is the score? " guess <- readLn if guess == score dice then putStrLn "Correct\n" >> play (streak + 1) else printf "The correct answer is %d.\n\n" (score dice) >> play 0

And here’s the heart of the program: the score function. It’s pretty simple, once you know the secret.

score :: [Int] -> Int score = sum . map ([0,0,0,2,0,4,0] !!)

To play a game, just show the intro and start playing.

main :: IO () main = showIntro >> play 0