如何在haskell中获取游戏循环的输入

时间:2014-11-21 16:38:10

标签: haskell

http://pastebin.com/2CS1k1Zq

在这个游戏中,我需要每隔半秒左右向前迈出一步,同时偶尔获得改变方向的输入。这些似乎无法用haskell做的事情有办法吗?目前我有一个mv胎面失速例外。

1 个答案:

答案 0 :(得分:2)

更新:找到hWaitForInput中的System.IO功能,该功能与waitFor基本相同。

以下是一些主要基于this answer的代码。

我做的主要区别是等待按键的线程不直接执行getCharMVar中传达的结果表示超时或已发生按键操作。实际获得角色是主线程的责任。这可以防止在获取角色并将其放入MVar之间杀死char读取线程时可能出现的竞争条件。

import Control.Concurrent
import Control.Monad
import Data.Maybe
import System.IO
import Control.Exception

data Event = CharReady | TimedOut

withRawStdin :: IO a -> IO a
withRawStdin = bracket uncook restore . const
  where
    uncook = do
        oldBuffering <- hGetBuffering stdin
        oldEcho <- hGetEcho stdin
        hSetBuffering stdin NoBuffering
        hSetEcho stdin False
        return (oldBuffering, oldEcho)
    restore (oldBuffering, oldEcho) = do
        hSetBuffering stdin oldBuffering
        hSetEcho stdin oldEcho

waitFor :: Int -> IO Event
waitFor delay = do
    done <- newEmptyMVar
    withRawStdin . bracket (start done) cleanUp $ \_ -> takeMVar done
  where
    start done = do
        t1 <- forkIO $ hLookAhead stdin >> putMVar done CharReady
        t2 <- forkIO $ threadDelay delay >> putMVar done TimedOut
        return (t1, t2)
    cleanUp (t1, t2) = do
        killThread t1
        killThread t2

loop state = do
  if state <= 0
    then putStrLn "Game over."
    else do putStrLn $ "Rounds to go: " ++ show state
            e <- waitFor 3000000
            case e of
              TimedOut -> do putStrLn "Too late!"; loop state
              CharReady -> do c <- getChar -- should not block
                              if c == 'x'
                                then do putStrLn "Good job!"; loop (state-1)
                                else do putStrLn "Wrong key"; loop state

main = loop 3