packages feed

wires-0.1.0: examples/ping-pong.hs

-- |
-- Copyright:  (c) 2016 Ertugrul Söylemez
-- License:    BSD3
-- Maintainer: Ertugrul Söylemez <esz@posteo.de>
-- Stability:  experimental

{-# LANGUAGE Arrows #-}

module Main (main) where

import Control.Monad.IO.Class
import Control.Wire
import Control.Wire.Controller
import GHC.Stats
import Prelude hiding ((.), id)
import System.Clock
import System.IO
import System.Mem
import Text.Printf
import Utils


newCharEvent :: (MonadIO m) => Wire m a (Event Char)
newCharEvent = proc _ ->
    newEvent -< liftIO $ do
        b <- hReady stdin
        if b then Just <$> getChar else pure Nothing


newTickEvent :: (MonadIO m) => Wire m a (Event Double)
newTickEvent = proc _ -> do
    times <- newEvent -< Just <$> getT
    withM_ unfoldE getT -< fmap (\t t' -> (secs (t - t'), t)) times

    where
    secs = (/ 1000000000) . fromInteger . toNanoSecs
    getT = liftIO (getTime Monotonic)


myApp :: (MonadIO m) => Wire m a (Event ())
myApp = proc _ -> do
    deltas <- newTickEvent -< ()
    fps <- hold 0 . (fmap recip <$> average 25) -< deltas
    chars <- newCharEvent -< ()

    acc <- scan 1 -< negate <$ filterE (== ' ') chars
    vel <- scan 0 -< fmap (\dt -> min 2 . max (-2) . (+ acc*dt)) deltas
    pos <- scan 0 -< fmap (\dt -> min 1 . max (-1) . (+ vel*dt)) deltas

    animate -< liftIO $ do
        performGC
        mem <- (`div` 1024) . currentBytesUsed <$> getGCStats
        printf "\r%8dk %8.2f %5.2f %s %s\027[K"
            mem
            fps
            vel
            (if acc > 0 then ">" else "<")
            (map (\xI ->
                      let x = -1 + 2 * fromInteger xI / 59
                      in if abs (pos - x) < 0.1 then 'X' else '.')
                 [0..59])
        hFlush stdout

    id -< () <$ filterE (== 'q') chars


main :: IO ()
main = do
    hSetBuffering stdin NoBuffering
    hSetEcho stdin False
    control myApp