packages feed

swarm-0.7.0.0: src/swarm-engine/Swarm/Game/Tick.hs

{-# LANGUAGE DeriveGeneric #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
module Swarm.Game.Tick (
  TickNumber (..),
  addTicks,
  formatTicks,
) where

import Data.Aeson (FromJSON, ToJSON (..))
import Data.Aeson qualified as A
import Data.Bits (Bits (..))
import Data.Int (Int64)
import Data.List (intersperse)
import GHC.Generics (Generic)
import Prettyprinter (Pretty (..))
import Swarm.Util.JSON (optionsUnwrapUnary)
import Swarm.Util.WindowedCounter (Offsettable (..))
import Text.Printf

-- | A newtype representing a count of ticks (typically since the
--   start of a game).
newtype TickNumber = TickNumber {getTickNumber :: Int64}
  deriving (Eq, Ord, Show, Read, Generic)

-- | Add an offset to a 'TickNumber'.
addTicks :: Int -> TickNumber -> TickNumber
addTicks i (TickNumber n) = TickNumber $ n + fromIntegral i

-- | Format a ticks count as a hexadecimal clock.
formatTicks :: Bool -> TickNumber -> String
formatTicks showTicks (TickNumber t) =
  mconcat $
    intersperse
      ":"
      [ printf "%x" (t `shiftR` 20)
      , printf "%02x" ((t `shiftR` 12) .&. ((1 `shiftL` 8) - 1))
      , printf "%02x" ((t `shiftR` 4) .&. ((1 `shiftL` 8) - 1))
      ]
      ++ if showTicks then [".", printf "%x" (t .&. ((1 `shiftL` 4) - 1))] else []

instance ToJSON TickNumber where
  toJSON = A.genericToJSON optionsUnwrapUnary

instance FromJSON TickNumber where
  parseJSON = A.genericParseJSON optionsUnwrapUnary

instance Offsettable TickNumber where
  offsetBy = addTicks

instance Pretty TickNumber where
  pretty = pretty . formatTicks True