从Haskell输出ascii动画?

PLL*_*PLL 7 animation haskell ascii-art

我正在尝试使用Haskell生成一些非常快速和脏的动画显示.最简单的尝试似乎是ASCII艺术 - 换句话说,就是:

type Frame = [[Char]]     -- each frame is given as an array of characters

type Animation = [Frame]

display :: Animation -> IO ()
display = ??
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能做到最好?

我根本无法弄清楚的部分是如何确保帧之间的最小暂停; 其余的是简单的使用putStrLn连同clearScreen来自ANSI-终端包,通过发现这样的回答.

C. *_*ann 5

好吧,这是我要做的事情的粗略草图:

import Graphics.UI.SDL.Time (getTicks)
import Control.Concurrent (threadDelay)

type Frame = [[Char]]
type Animation = [Frame]

displayFrame :: Frame -> IO ()
displayFrame = mapM_ putStrLn

timeAction :: IO () -> IO Integer
timeAction act = do t <- getTicks
                    act
                    t' <- getTicks
                    return (fromIntegral $ t' - t)

addDelay :: Integer -> IO () -> IO ()
addDelay hz act = do dt <- timeAction act
                     let delay = calcDelay dt hz
                     threadDelay $ fromInteger delay

calcDelay dt hz = max (frame_usec - dt_usec) 0
  where frame_usec = 1000000 `div` hz
        dt_usec = dt * 1000

runFrames :: Integer -> Animation -> IO ()
runFrames hz frs = mapM_ (addDelay hz . displayFrame) frs
Run Code Online (Sandbox Code Playgroud)

显然我在这里纯粹使用SDL getTicks,因为它是我之前使用过的.随意用任何其他功能替换它以获得当前时间.

第一个参数runFrames是 - 顾名思义 - 以赫兹为单位的帧速率,即每秒帧数.该runFrames函数首先将每个帧转换为绘制它的动作,然后将每个帧分配给addDelay函数,该函数检查运行动作之前和之后的时间,然后休眠直到帧时间结束.

我自己的代码看起来有点不同,因为我通常会有一个更复杂的循环,可以做其他事情,例如,为事件轮询SDL,进行后台处理,将数据传递到下一次迭代,&c.但基本思路是一样的.

显然,这种方法的好处在于,虽然仍然相当简单,但在可能的情况下,您可以获得一致的帧速率,并且可以明确指定目标速度.