packages feed

halma-telegram-bot-0.1.0.0: src/Game/Halma/TelegramBot/View/DrawBoard.hs

{-# LANGUAGE FlexibleContexts #-}

module Game.Halma.TelegramBot.View.DrawBoard
  ( BoardLabels
  , withRenderedBoardInPngFile
  ) where

import Game.Halma.Board
import Game.Halma.Board.Draw
import Game.Halma.TelegramBot.Model.MoveCmd
import Game.Halma.TelegramBot.Model.Types

import Control.Monad.Catch (MonadMask)
import Control.Monad.IO.Class (MonadIO (..))
import Diagrams.Backend.Cairo (Cairo, renderCairo)
import Diagrams.Prelude ((#), (|||), (*^), (&), (.~))
import Diagrams.Query (resetValue)
import Diagrams.Size (dims)
import Diagrams.TwoD.Types (V2 (..))
import System.Directory (getTemporaryDirectory)
import System.IO (hClose)
import System.IO.Temp (withTempFile)
import qualified Data.Text as T
import qualified Data.Map as M
import qualified Diagrams.Prelude as D

type BoardLabels = M.Map (Int, Int) T.Text

withRenderedBoardInPngFile
  :: (MonadIO m, MonadMask m)
  => HalmaState
  -> BoardLabels
  -> (FilePath -> m a)
  -> m a
withRenderedBoardInPngFile game labels action =
  withTempPngFilePath $ \path -> do
    let
      dia = drawBoardForChat game labels # D.centerXY # D.pad 1.1
      bounds = dims (V2 1000 1000)
    liftIO $ renderCairo path bounds dia
    action path
  where
    withTempPngFilePath handler = do
      systemTempDir <- liftIO getTemporaryDirectory
      withTempFile systemTempDir "halma.png" $ \filePath fileHandle -> do
        liftIO (hClose fileHandle)
        handler filePath

drawBoardForChat :: HalmaState -> BoardLabels -> D.Diagram Cairo
drawBoardForChat game labels =
  let
    boardDia = resetValue (drawBoard' (getGrid board) drawField)
  in
    scale ||| D.strut D.unitX ||| boardDia ||| D.strut D.unitX ||| scale
  where
    board = hsBoard game
    dirY = D.rotateBy (1/6) D.unitX
    rowDir = dirY & D._x .~ 0
    boardFontStyle x = x # D.fontSize (D.output 22) # D.font "Arial"
    scale = D.position $ map rowMarker [(-r)..r]
      where
        r = radiusInRows (getGrid board)
        rowMarker i = (rowPosition i, rowNumberLabel i)
        rowPosition i = D.p2 $ D.unr2 $ fromIntegral i *^ rowDir
        rowNumberLabel i =
          let
            humanRowNumber = internalToHumanRowNumber (getGrid board) i
            txt = show (unRowNumber humanRowNumber)
          in
            D.text txt # boardFontStyle # D.fc D.gray
    drawField :: (Int, Int) -> D.Diagram Cairo
    drawField field =
      case lookupHalmaBoard field board of
        Just piece ->
          if Just field == (moveTo <$> hsLastMove game) then
            drawPiece piece # D.lc D.black # D.lw D.medium
          else
            drawPiece piece
        Nothing ->
          case M.lookup field labels of
            Just label -> drawLabel label
            Nothing -> mempty
    drawPiece :: Piece -> D.Diagram Cairo
    drawPiece piece =
      let
        c = defaultTeamColours (pieceTeam piece)
        symbol = T.unpack (showPieceNumber (pieceNumber piece))
        text = D.text symbol # boardFontStyle # D.fc D.white
        circle = D.circle 0.3 # D.fc c
      in
        text `D.atop` circle
    drawLabel :: T.Text -> D.Diagram Cairo
    drawLabel label =
      let
        text = D.text (T.unpack label) # boardFontStyle # D.fc D.gray
        circle = D.circle 0.3 # D.fc D.white
      in
        text `D.atop` circle