如何在一个简单的猜谜游戏(Haskell)中跟踪猜测数量

在过去的几周里,我一直在尝试独立学习 Haskell.目前,我正在尝试实施一个愚蠢的小猜谜游戏,其中计算机选择一个随机数,用户试图猜测它.如果用户错误,程序会告诉用户答案更高或更低,并允许用户猜测,直到他们猜对.我已经有了它的工作,但我想添加跟踪用户每场比赛的猜测次数的能力,并在他们正确猜测后向用户报告该数字.

来自命令性的背景,自然要做的就是让每次用户猜测时都会增加一个计数器,但是你不能在Haskell中真正做到这一点(至少看起来像是无状态和一切都是不变的)会阻止这种情况).

我玩弄了让getGuess和giveHints函数获取一个额外参数的想法,该参数表示到目前为止的猜测次数(让我们称之为numGuesses),并且在每次调用这些方法时,传递(numGuesses 1).但我无法让它工作(更不用说我甚至不知道这是否有效).

我的代码如下.任何建议都会非常感激.我主要是在寻找想法,但也可以随意发布实际代码.另外,如果你发现任何令人发指的事情,我可以随时告诉我,如果我的代码糟透了,以及我如何改进它(我只在功能上编程了几个星期!)

import System.Random
    import System.IO
    import Control.Monad

    main = do
        gen <- getStdGen
        let (ans,_) = randomR (1,100) gen :: (Int,StdGen)
        putStrLn $"I'm thinking of a number between 1 and 100..."
        getGuess ans
        putStrLn "You guessed it in __ guesses!"
        putStr "Play again? "
        hFlush stdout
        desire <- getLine
        when ((desire !! 0) `elem` ['y','Y']) $do
            putStrLn ""
            newStdGen
            main

    getGuess ans = do   
        putStr "Your guess? "
        hFlush stdout
        guessStr <- getLine
        giveHints ans (read guessStr)

    giveHints ans guess = do
        when (ans /= guess) $do
           if ans > guess 
               then putStrLn "It's higher." 
               else putStrLn "It's lower."
           getGuess ans

注意:我正在使用hFlush标准输出,因为我正在使用行缓冲,没有它,某些交互的顺序不是人们所期望的.

实际上,您可以实现您正在考虑的计数方法,但您仍然必须明确地传递状态.但在这种情况下,它根本不是一件麻烦事.实际上,这是一个人们经常看到辅助函数的模式,实际上使用State monad会有些过分.

我所指的模式通常如下所示:

doStuff xs' = go xs' 0
  where
    go (x:xs) n = .. etc ..

这是代码.

import System.Random       (randomRIO)
import Control.Applicative ((<$>))
import Control.Monad       (when)
import Text.Printf         (printf)  

playGame :: Int -> Int -> IO ()
playGame answer curGuesses = do
    putStrLn "What is your guess?"
    putStr   ">"
    guess <- getGuessFromUser
    when (guess /= answer) $do
        giveHints answer guess
        playGame answer (curGuesses + 1)
    when (guess == answer) $do
        putStrLn "You guessed it!"
        printf   "You guessed %d times!\n" (curGuesses + 1)

giveHints :: Int -> Int -> IO ()
giveHints answer guess 
    | answer > guess = putStrLn "It's higher!"
    | otherwise      = putStrLn "It's lower!"

getGuessFromUser :: IO Int
getGuessFromUser = do
    read <$> getLine

main :: IO ()
main = do
    answer <- randomRIO (1, 100)
    putStrLn "I'm thinking of a number between 1 and 100."
    playGame answer 0

笔记

>< $>是fmap>我在Daniel提到的时候使用了randomRIO,因为我们已经在IO monad中了.>我没有必要在Windows上使用命令提示符来使用hSetBuffering或hFlush来获得正确的输出.但是,YMMV.

相关文章
相关标签/搜索