chessica-0.1.0.0: src/Chess/Piece.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
-----------------------------------------------------------------------------
-- |
-- Module : Chess.Piece
-- Copyright : (c) Michael Szvetits, 2023
-- License : BSD-3-Clause (see the file LICENSE)
-- Maintainer : typedbyte@qualified.name
-- Stability : stable
-- Portability : portable
--
-- Types and functions to create and analyze chess pieces.
-----------------------------------------------------------------------------
module Chess.Piece
( -- * Representing Pieces
PieceType'(..)
, PieceType(..)
, Piece(..)
, somePiece
, fromSome
-- * Analyzing Piece Types
, equals
-- * Analyzing Pieces
, same
, isOfType
, assume
)where
-- base
import Control.Applicative (Alternative, empty)
import Data.Type.Equality ((:~:)(Refl), TestEquality, testEquality)
import Chess.Color (Color)
import Chess.Some (Some(Some))
-- | Represents the piece types involved in a chess game on the type-level.
data PieceType'
= Pawn'
| Knight'
| Bishop'
| Rook'
| Queen'
| King'
deriving (Eq, Ord, Read, Show)
-- | Represents the piece types involved in a chess game on the term-level.
data PieceType t where
Pawn :: PieceType Pawn'
Knight :: PieceType Knight'
Bishop :: PieceType Bishop'
Rook :: PieceType Rook'
Queen :: PieceType Queen'
King :: PieceType King'
deriving instance Eq (PieceType t)
deriving instance Ord (PieceType t)
deriving instance Show (PieceType t)
instance TestEquality PieceType where
testEquality Pawn Pawn = Just Refl
testEquality Knight Knight = Just Refl
testEquality Bishop Bishop = Just Refl
testEquality Rook Rook = Just Refl
testEquality Queen Queen = Just Refl
testEquality King King = Just Refl
testEquality _ _ = Nothing
-- | Returns true if two piece types are the same.
equals :: PieceType a -> PieceType b -> Bool
equals type1 type2 =
case testEquality type1 type2 of
Just Refl -> True
Nothing -> False
-- | Represents a chess piece, which is a combination of its type and its color.
data Piece t = Piece
{ type' :: PieceType t
, color :: Color
}
deriving (Eq, Ord, Show)
instance Eq (Some Piece) where
Some p1 == Some p2 = same p1 p2
instance Ord (Some Piece) where
compare (Some p1) (Some p2) =
case (p1.type', p2.type') of
(Pawn , Pawn ) -> compareColor
(Pawn , _ ) -> LT
(Knight, Pawn ) -> GT
(Knight, Knight) -> compareColor
(Knight, _ ) -> LT
(Bishop, Pawn ) -> GT
(Bishop, Knight) -> GT
(Bishop, Bishop) -> compareColor
(Bishop, _ ) -> LT
(Rook , King ) -> LT
(Rook , Queen ) -> LT
(Rook , Rook ) -> compareColor
(Rook , _ ) -> GT
(Queen , King ) -> LT
(Queen , Queen ) -> compareColor
(Queen , _ ) -> GT
(King , King ) -> compareColor
(King , _ ) -> GT
where
compareColor = compare p1.color p2.color
instance Show (Some Piece) where
show (Some piece) = show piece
-- | Smart constructor for creating 'Some' 'Piece'.
somePiece :: PieceType t -> Color -> Some Piece
somePiece type' color = Some $ Piece type' color
-- | Smart constructor for creating 'Some' 'Piece' from 'Some' 'PieceType'.
fromSome :: Some PieceType -> Color -> Some Piece
fromSome (Some type') = somePiece type'
-- | Assumes that the given piece has the specified piece type.
assume :: Alternative f => PieceType t -> Piece a -> f (Piece t)
assume type' piece =
case testEquality type' piece.type' of
Just Refl -> pure piece
Nothing -> empty
-- | Returns true if two pieces are the same.
same :: Piece a -> Piece b -> Bool
same piece1 piece2 =
case testEquality piece1.type' piece2.type' of
Just Refl -> piece1.color == piece2.color
Nothing -> False
-- | Returns true if the given piece has the specified piece type.
isOfType :: PieceType t -> Piece a -> Bool
isOfType type' piece =
case testEquality type' piece.type' of
Just Refl -> True
Nothing -> False