boardgame-0.0.0.1: executable/Yavalath.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Yavalath where
import Boardgame (
Player(..)
, Position(..)
, PositionalGame(..)
, mapPosition
, isOccupied
, nextPlayer
, drawIf
, criteria
, symmetric
, unless
, player1LosesWhen
, player1WinsWhen
)
import Boardgame.ColoredGraph (
ColoredGraph
, ColoredGraphTransformer(..)
, values
, mapValues
, filterValues
, hexHexGraph
, inARow
, mapEdges
, winningSetPaths
, coloredGraphVertexPositions
, coloredGraphGetVertexPosition
, coloredGraphSetVertexPosition
)
#ifdef WASM
import Data.Aeson (ToJSON(..))
#endif
-------------------------------------------------------------------------------
-- * Yavalath
-------------------------------------------------------------------------------
newtype Yavalath = Yavalath (ColoredGraph (Int, Int) Position String)
deriving (ColoredGraphTransformer (Int, Int) Position String)
instance Show Yavalath where
show (Yavalath b) = show b
#ifdef WASM
instance ToJSON Yavalath where
toJSON (Yavalath b) = toJSON b
#endif
instance PositionalGame Yavalath (Int, Int) where
positions = coloredGraphVertexPositions
getPosition = coloredGraphGetVertexPosition
setPosition = coloredGraphSetVertexPosition
gameOver (Yavalath b) = criterion b
where
criterion =
drawIf (all isOccupied . values) `unless` -- It's a draw if all tiles are owned.
-- Here we say that in any position where one player wins,
-- the other player would win instead if the pieces were swapped.
symmetric (mapValues $ mapPosition nextPlayer)
-- Player1 looses if he has 3 in a row but wins if he has 4 or more in a row.
-- It's important we use `unless` here because otherwise we could have conflicting
-- outcomes from having both 3 in a row and 4 in a row at the same time.
(criteria (player1LosesWhen . inARow (==3) <$> directions) . filterValues (== Occupied Player1) `unless`
criteria (player1WinsWhen . inARow (>=4) <$> directions) . filterValues (== Occupied Player1))
directions = ["vertical", "diagonal1", "diagonal2"]
emptyYavalath :: Int -> Yavalath
emptyYavalath = Yavalath . mapEdges dirName . hexHexGraph
where
dirName (1,0) = "vertical"
dirName (-1,0) = "vertical"
dirName (1,-1) = "diagonal1"
dirName (-1,1) = "diagonal1"
dirName (0,-1) = "diagonal2"
dirName (0,1) = "diagonal2"