packages feed

swarm-0.4: src/Swarm/Game/Terrain.hs

{-# LANGUAGE OverloadedStrings #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Terrain types and properties.
module Swarm.Game.Terrain (
  -- * Terrain
  TerrainType (..),
  readTerrain,
  terrainMap,
  getTerrainDefaultPaletteChar,
  getTerrainWord,
) where

import Data.Aeson (FromJSON (..), withText)
import Data.Map (Map)
import Data.Map qualified as M
import Data.Text qualified as T
import Swarm.Game.Display
import Swarm.Util (failT)
import Text.Read (readMaybe)
import Witch (into)

-- | The different possible types of terrain. Unlike entities and
--   robots, these are hard-coded into the game.
data TerrainType
  = StoneT
  | DirtT
  | GrassT
  | IceT
  | BlankT
  deriving (Eq, Ord, Show, Read, Bounded, Enum)

readTerrain :: T.Text -> Maybe TerrainType
readTerrain t = readMaybe (into @String (T.toTitle t) ++ "T")

instance Semigroup TerrainType where
  t <> BlankT = t
  _ <> t = t

instance Monoid TerrainType where
  mempty = BlankT

instance FromJSON TerrainType where
  parseJSON = withText "text" $ \t ->
    case readTerrain t of
      Just ter -> return ter
      Nothing -> failT ["Unknown terrain type:", t]

getTerrainDefaultPaletteChar :: TerrainType -> Char
getTerrainDefaultPaletteChar = head . show

getTerrainWord :: TerrainType -> T.Text
getTerrainWord = T.toLower . T.pack . init . show

-- | A map containing a 'Display' record for each different 'TerrainType'.
terrainMap :: Map TerrainType Display
terrainMap =
  M.fromList
    [ (StoneT, defaultTerrainDisplay '▒' (ATerrain "stone"))
    , (DirtT, defaultTerrainDisplay '▒' (ATerrain "dirt"))
    , (GrassT, defaultTerrainDisplay '▒' (ATerrain "grass"))
    , (IceT, defaultTerrainDisplay ' ' (ATerrain "ice"))
    , (BlankT, defaultTerrainDisplay ' ' ADefault)
    ]