packages feed

turncoat-1.0: src/MoveGen/PieceCaptures.hs

module MoveGen.PieceCaptures (allCaptures, staticExchangeCaptures, knightCaptures, bishopCaptures, rookCaptures, queenCaptures) where

import           AppPrelude

import           Models.Move
import           Models.Piece
import           Models.Position
import           MoveGen.PieceAttacks
import           Utils.Board


-- Captures legal move generator:
-- - Piece captures
-- - En passant captures
-- - Pawn promotions

allCaptures :: Position -> [Move]
allCaptures pos@Position {..}

  | allCheckers          == 0 = genCaptures id id
  | popCount allCheckers > 1 = allKingCaptures
  | sliderCheckers /= 0       = genCaptures captureChecker pawnCaptureChecker
  | otherwise                = genCaptures captureChecker pawnCaptureChecker

  where
    genCaptures =
      allCapturesHelper allPieces king allKingCaptures pos
    pawnCaptureChecker board =
      board & (allCheckers .| enPassantChecker)
    captureChecker board = board & allCheckers
    allKingCaptures =
      foldBoardSquares King (kingCaptures enemy attacked) [] kingSquare
    allCheckers = leapingCheckers .| sliderCheckers
    enPassantChecker =
      let checker = allCheckers & pawns
      in enPassant & (checker << 8 .| checker >> 8)
    allPieces  = player .| enemy
    kingSquare = lsb king
    king       = player&kings


allCapturesHelper :: Board -> Board -> [Move] -> Position -> (Board -> Board) -> (Board -> Board) -> [Move]
allCapturesHelper allPieces king allKingCaptures Position {..} !f !g =

    foldBoardMoves     Pawn   (g . pawnCapturesAndPromotions
                                     enemy noPieces enPassant color)
                              (unpinned&pawns)

    $ foldBoardMoves   Pawn   (g . pawnPromotions noPieces color
                                 . toBoard)
                              filePinnedPawns

    $ foldBoardMoves   Pawn   (g . diagPawnCaptures enemy color)
                              diagPinnedPawns

    $ foldBoardMoves   Pawn   (g . antiDiagPawnCaptures enemy color)
                              antiDiagPinnedPawns

    $ foldBoardMoves   Knight (f . knightCaptures enemy)
                              (unpinned&knights)

    $ foldBoardMoves   Bishop (f . bishopCaptures
                                     enemy allPieces pinnedPieces king)
                              (player&bishops)

    $ foldBoardMoves   Rook   (f . rookCaptures
                                     enemy allPieces pinnedPieces king)
                              (player&rooks)

    $ foldBoardMoves   Queen  (f . queenCaptures
                                     enemy allPieces pinnedPieces king)
                              (player&queens)
    allKingCaptures

    where
    unpinned            = player .\ pinnedPieces
    pinnedPawns         = pinnedPieces & pawns
    filePinnedPawns     = pinnedPawns & kingFile
    diagPinnedPawns     = pinnedPawns & kingDiag
    antiDiagPinnedPawns = pinnedPawns & kingAntiDiag
    kingFile            = rankMovesVec !! kingSquare
    kingDiag            = antiDiagMovesVec !! kingSquare
    kingAntiDiag        = diagMovesVec !! kingSquare
    kingSquare          = lsb king
    noPieces            = (~) allPieces


staticExchangeCaptures :: Square -> Position -> [Move]
staticExchangeCaptures target pos@Position {..}
  | allCheckers == 0               = genCaptures
  | popCount allCheckers > 1      = allKingCaptures
  | testSquare allCheckers target = genCaptures
  | otherwise                     = []

  where
    genCaptures =
      staticExchangeCapturesHelper target kingSquare allPieces
                                   allKingCaptures pos
    allKingCaptures =
      foldBoardSquares King (kingCaptures (toBoard target) attacked)
      [] kingSquare
    allCheckers     = leapingCheckers .| sliderCheckers
    allPieces       = player .| enemy
    kingSquare      = lsb king
    king            = player&kings


staticExchangeCapturesHelper
  :: Square -> Square -> Board -> [Move] -> Position -> [Move]
staticExchangeCapturesHelper
  target king allPieces allKingCaptures Position {..} =
      foldBoardPawnMovesConst    target (validSliders&pawnAttackers)
    $ foldBoardMovesConst Knight target (unpinned&knightAttackers)
    $ foldBoardMovesConst Bishop target (validSliders&bishopAttackers)
    $ foldBoardMovesConst Rook   target (validSliders&rookAttackers)
    $ foldBoardMovesConst Queen  target (validSliders&queenAttackers)
      allKingCaptures

    where
    pawnAttackers   = pawns & pawnAttacks (reverseColor color) targetBoard
    knightAttackers = knights & knightAttacks target
    bishopAttackers = bishops & bishopRays
    rookAttackers   = rooks & rookRays
    queenAttackers  = queens & (bishopRays .| rookRays)
    bishopRays      = bishopAttacks allPieces target
    rookRays        = rookAttacks allPieces target
    targetBoard     = toBoard target
    unpinned        = player .\ pinnedPieces

    validSliders
      | pinnedPieces .\ knights == 0 = player
      | otherwise = unpinned .| pinnedPieces & getPinningRay target king


getPinningRay :: Square -> Square -> Board
getPinningRay !target !king
    | testSquare kingDiag target     = kingDiag
    | testSquare kingAntiDiag target = kingAntiDiag
    | testSquare kingFile target     = kingFile
    | testSquare kingRank target     = kingRank
    | otherwise                      = 0
  where
  kingDiag        = antiDiagMovesVec !! king
  kingAntiDiag    = diagMovesVec     !! king
  kingFile        = rankMovesVec     !! king
  kingRank        = fileMovesVec     !! king


pawnCapturesAndPromotions :: Board -> Board -> Board -> Color -> Square -> Board
pawnCapturesAndPromotions enemy noPieces enPassant color n =
  pawnPromotions noPieces color board
  .| pawnCaptures enemy enPassant color board
  where
    board = toBoard n


pawnPromotions :: Board -> Color -> Board -> Board
pawnPromotions noPieces color board =
  promotions & noPieces
  where
    promotions = case color of
      White -> (board & rank_7) << 8
      Black -> (board & rank_2) >> 8


pawnCaptures :: Board -> Board -> Color -> Board -> Board
pawnCaptures enemy enPassant color board =
  pawnAttacks color board & (enemy .| enPassant)


diagPawnCaptures :: Board -> Color -> Square -> Board
diagPawnCaptures enemy color n =
  pawnDiagAttacks color board & enemy
  where
    board = toBoard n


antiDiagPawnCaptures :: Board -> Color -> Square -> Board
antiDiagPawnCaptures enemy color n =
  pawnAntiDiagAttacks color board & enemy
  where
    board = toBoard n


knightCaptures :: Board -> Square -> Board
knightCaptures enemy n =
  knightAttacks n & enemy


kingCaptures :: Board -> Board -> Square -> Board
kingCaptures enemy attacked n =
  (kingAttacks n & enemy) .\ attacked


bishopCaptures :: Board -> Board -> Board -> Board -> Square -> Board
bishopCaptures enemy allPieces pinnedPieces king n =
  bishopMoves allPieces pinnedPieces king n & enemy


rookCaptures :: Board -> Board -> Board -> Board -> Square -> Board
rookCaptures enemy allPieces pinnedPieces king n =
  rookMoves allPieces pinnedPieces king n & enemy


queenCaptures :: Board -> Board -> Board -> Board -> Square -> Board
queenCaptures enemy allPieces pinnedPieces king n =
  queenMoves allPieces pinnedPieces king n & enemy