-----------------------------------------------------------------------------
-- |
-- Module      : Chess.Rulebook.Standard.Check
-- Copyright   : (c) Michael Szvetits, 2023
-- License     : BSD-3-Clause (see the file LICENSE)
-- Maintainer  : typedbyte@qualified.name
-- Stability   : stable
-- Portability : portable
--
-- Implementation of the check rule, according to the standard rulebook.
-----------------------------------------------------------------------------
module Chess.Rulebook.Standard.Check where

-- base
import Data.List (find)

import Chess.Board                    (Board, piecesOf)
import Chess.Board.PlacedPiece        (PlacedPiece(position, piece))
import Chess.Color                    (oppositeOf)
import Chess.Piece                    (PieceType(King), isOfType)
import Chess.Player                   (Player(color))
import Chess.Rulebook.Standard.Threat (threats)
import Chess.Some                     (Some(Some))

-- | Returns true if the specified player is currently checked, according to the
-- standard rulebook.
checked :: Player -> Board -> Bool
checked :: Player -> Board -> Bool
checked Player
player Board
board =
  let
    enemyThreats :: [Position]
enemyThreats =
      forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap
        ( \(Some PlacedPiece t
enemy) -> forall (t :: PieceType'). PlacedPiece t -> Board -> [Position]
threats PlacedPiece t
enemy Board
board )
        ( Color -> Board -> [Some PlacedPiece]
piecesOf (Color -> Color
oppositeOf Player
player.color) Board
board )
    playerKing :: Maybe (Some PlacedPiece)
playerKing =
      forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find
        ( \(Some PlacedPiece t
friend) -> forall (t :: PieceType') (a :: PieceType').
PieceType t -> Piece a -> Bool
isOfType PieceType 'King'
King PlacedPiece t
friend.piece )
        ( Color -> Board -> [Some PlacedPiece]
piecesOf Player
player.color Board
board )
  in
    case Maybe (Some PlacedPiece)
playerKing of
      Just (Some PlacedPiece t
king) -> forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem PlacedPiece t
king.position [Position]
enemyThreats
      Maybe (Some PlacedPiece)
Nothing          -> Bool
False