module Evaluation.Evaluation (evaluatePosition, evaluatePositionBreakdown, evaluateExchange, evaluateMvvLva)
where

import           AppPrelude

import           Evaluation.Material
import           Evaluation.Parameters
import           Evaluation.ScoreBreakdown
import           Models.Move
import           Models.Piece
import           Models.Position
import           Models.Score
import           MoveGen.MakeMove
import           MoveGen.PieceAttacks
import           MoveGen.PieceCaptures
import           MoveGen.PositionQueries
import           Utils.Board



evaluatePosition :: Position -> Score
evaluatePosition :: Position -> Int16
evaluatePosition =
 ScoreBreakdown -> Int16
forall a. EvalScore a => a -> Int16
evalScore (ScoreBreakdown -> Int16)
-> (Position -> ScoreBreakdown) -> Position -> Int16
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Position -> ScoreBreakdown
evaluatePositionBreakdown


evaluatePositionBreakdown :: Position -> ScoreBreakdown
evaluatePositionBreakdown :: Position -> ScoreBreakdown
evaluatePositionBreakdown Position
pos =
  let
    !enemyPos :: Position
enemyPos         = Position -> Position
makeNullMove Position
pos
    !scoresBatch :: ScoresBatch
scoresBatch      = (?phase::Int16) => Position -> ScoresBatch
Position -> ScoresBatch
getScoresBatch Position
pos
    !enemyScoresBatch :: ScoresBatch
enemyScoresBatch = (?phase::Int16) => Position -> ScoresBatch
Position -> ScoresBatch
getScoresBatch Position
enemyPos
    !playerBreakdown :: PlayerScoreBreakdown
playerBreakdown =
      (?phase::Int16, ?colorToMove::Color) =>
ScoresBatch -> ScoresBatch -> Position -> PlayerScoreBreakdown
ScoresBatch -> ScoresBatch -> Position -> PlayerScoreBreakdown
evaluatePlayerBreakdown ScoresBatch
scoresBatch ScoresBatch
enemyScoresBatch Position
pos
    !enemyBreakdown :: PlayerScoreBreakdown
enemyBreakdown  =
      (?phase::Int16, ?colorToMove::Color) =>
ScoresBatch -> ScoresBatch -> Position -> PlayerScoreBreakdown
ScoresBatch -> ScoresBatch -> Position -> PlayerScoreBreakdown
evaluatePlayerBreakdown ScoresBatch
enemyScoresBatch ScoresBatch
scoresBatch Position
enemyPos
    !materialScore :: Int16
materialScore   =
         MaterialBreakdown -> Int16
forall a. EvalScore a => a -> Int16
evalScore PlayerScoreBreakdown
playerBreakdown.materialBreakdown
       Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
- MaterialBreakdown -> Int16
forall a. EvalScore a => a -> Int16
evalScore PlayerScoreBreakdown
enemyBreakdown.materialBreakdown
    !materialTradesScore :: Int16
materialTradesScore =
      Int16 -> Position -> Int16
evaluateMaterialTrades Int16
materialScore Position
pos
  in
    ScoreBreakdown {Int16
PlayerScoreBreakdown
playerBreakdown :: PlayerScoreBreakdown
enemyBreakdown :: PlayerScoreBreakdown
materialTradesScore :: Int16
$sel:playerBreakdown:ScoreBreakdown :: PlayerScoreBreakdown
$sel:enemyBreakdown:ScoreBreakdown :: PlayerScoreBreakdown
$sel:materialTradesScore:ScoreBreakdown :: Int16
..}
  where
    ?phase       = Position
pos.phase
    ?colorToMove = Position
pos.color


evaluatePlayerBreakdown :: (?phase :: Phase, ?colorToMove :: Color)
  => ScoresBatch -> ScoresBatch -> Position -> PlayerScoreBreakdown
evaluatePlayerBreakdown :: (?phase::Int16, ?colorToMove::Color) =>
ScoresBatch -> ScoresBatch -> Position -> PlayerScoreBreakdown
evaluatePlayerBreakdown ScoresBatch
scoresBatch ScoresBatch
enemyScoresBatch Position
pos =
  PlayerScoreBreakdown {
    $sel:materialBreakdown:PlayerScoreBreakdown :: MaterialBreakdown
materialBreakdown =
      (?phase::Int16) => Position -> Board -> Color -> MaterialBreakdown
Position -> Board -> Color -> MaterialBreakdown
evaluatePlayerMaterial Position
pos Position
pos.player Position
pos.color
  , $sel:bonusBreakdown:PlayerScoreBreakdown :: BonusBreakdown
bonusBreakdown    =
      (?phase::Int16, ?colorToMove::Color) =>
ScoresBatch -> Position -> BonusBreakdown
ScoresBatch -> Position -> BonusBreakdown
evaluatePositionBonuses ScoresBatch
scoresBatch Position
pos
  , $sel:penaltyBreakdown:PlayerScoreBreakdown :: PenaltyBreakdown
penaltyBreakdown  =
      ScoresBatch -> ScoresBatch -> Position -> PenaltyBreakdown
evaluatePositionPenalties ScoresBatch
scoresBatch ScoresBatch
enemyScoresBatch Position
pos
  }


evaluatePositionBonuses :: (?phase :: Phase, ?colorToMove :: Color)
  => ScoresBatch -> Position -> BonusBreakdown
evaluatePositionBonuses :: (?phase::Int16, ?colorToMove::Color) =>
ScoresBatch -> Position -> BonusBreakdown
evaluatePositionBonuses ScoresBatch {Int16
mobility :: Int16
threats :: Int16
kingThreats :: Int16
$sel:mobility:ScoresBatch :: ScoresBatch -> Int16
$sel:threats:ScoresBatch :: ScoresBatch -> Int16
$sel:kingThreats:ScoresBatch :: ScoresBatch -> Int16
..} Position
pos =
  BonusBreakdown {
    $sel:mobility:BonusBreakdown :: Int16
mobility        = Int16
mobility
  , $sel:passedPawns:BonusBreakdown :: Int16
passedPawns     = (?phase::Int16, ?colorToMove::Color) => Position -> Int16
Position -> Int16
evaluatePassedPawns      Position
pos
  , $sel:bishopPair:BonusBreakdown :: Int16
bishopPair      = (?phase::Int16) => Position -> Int16
Position -> Int16
evaluateBishopPair       Position
pos
  , $sel:knightOutposts:BonusBreakdown :: Int16
knightOutposts  = (?phase::Int16) => Position -> Int16
Position -> Int16
evaluateKnightOutposts   Position
pos
  , $sel:rooksOnOpenFile:BonusBreakdown :: Int16
rooksOnOpenFile = (?phase::Int16) => Position -> Int16
Position -> Int16
evaluateRooksOnOpenFiles Position
pos
  , $sel:kingPawnShield:BonusBreakdown :: Int16
kingPawnShield  = (?phase::Int16) => Position -> Int16
Position -> Int16
evaluateKingPawnShield   Position
pos
  , $sel:castlingRights:BonusBreakdown :: Int16
castlingRights  = Position -> Int16
evaluateCastlingRights   Position
pos
  }


evaluatePositionPenalties
  :: ScoresBatch -> ScoresBatch -> Position -> PenaltyBreakdown
evaluatePositionPenalties :: ScoresBatch -> ScoresBatch -> Position -> PenaltyBreakdown
evaluatePositionPenalties
  ScoresBatch {Int16
$sel:threats:ScoresBatch :: ScoresBatch -> Int16
threats :: Int16
threats} ScoresBatch {Int16
$sel:kingThreats:ScoresBatch :: ScoresBatch -> Int16
kingThreats :: Int16
kingThreats} Position {Board
player :: Board
$sel:player:Position :: Position -> Board
player, Board
pawns :: Board
$sel:pawns:Position :: Position -> Board
pawns} =
  PenaltyBreakdown {
    $sel:threats:PenaltyBreakdown :: Int16
threats        = Int16
threats
  , $sel:kingThreats:PenaltyBreakdown :: Int16
kingThreats    = Int16
kingThreats
  , $sel:isolatedPawns:PenaltyBreakdown :: Int16
isolatedPawns  = Board -> Int16
evaluateIsolatedPawns (Board
player Board -> Board -> Board
& Board
pawns)
  , $sel:doubledPawns:PenaltyBreakdown :: Int16
doubledPawns   = Board -> Int16
evaluateDoubledPawns  (Board
player Board -> Board -> Board
& Board
pawns)
  }


evaluateBishopPair :: (?phase :: Phase) => Position -> Score
evaluateBishopPair :: (?phase::Int16) => Position -> Int16
evaluateBishopPair Position {Board
$sel:player:Position :: Position -> Board
player :: Board
player, Board
bishops :: Board
$sel:bishops:Position :: Position -> Board
bishops} =
   Int16
(?phase::Int16) => Int16
bishopPairBonus
   Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Int -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral ((Int, Int) -> Int -> Int
forall a. Ord a => (a, a) -> a -> a
clamp (Int
0, Int
1) (Board -> Int
popCount (Board
player Board -> Board -> Board
& Board
bishops) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1))


evaluateKnightOutposts :: (?phase :: Phase) => Position -> Score
evaluateKnightOutposts :: (?phase::Int16) => Position -> Int16
evaluateKnightOutposts Position {Int16
[ZKey]
Word8
Board
Color
$sel:player:Position :: Position -> Board
$sel:pawns:Position :: Position -> Board
$sel:bishops:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Word8
phase :: Int16
color :: Color
player :: Board
enemy :: Board
pawns :: Board
knights :: Board
bishops :: Board
rooks :: Board
queens :: Board
kings :: Board
enPassant :: Board
castling :: Board
attacked :: Board
leapingCheckers :: Board
sliderCheckers :: Board
pinnedPieces :: Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Word8
$sel:phase:Position :: Position -> Int16
$sel:color:Position :: Position -> Color
$sel:enemy:Position :: Position -> Board
$sel:knights:Position :: Position -> Board
$sel:rooks:Position :: Position -> Board
$sel:queens:Position :: Position -> Board
$sel:kings:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:castling:Position :: Position -> Board
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
..} =
  Int16
(?phase::Int16) => Int16
knightOutpostBonus
  Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Board -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Board
-> (Board -> Board -> Board) -> (Int -> Board) -> Board -> Board
forall a b. a -> (a -> b -> a) -> (Int -> b) -> Board -> a
foldlBoard Board
0 Board -> Board -> Board
forall a. Num a => a -> a -> a
(+) Int -> Board
mapFn
    (Board
knightsBoard -> Board -> Board
&Board
player Board -> Board -> Board
& Board
defended Board -> Board -> Board
& Board
ranks Board -> Board -> Board
& Board
knightOupostFiles))
  where
    defended :: Board
defended = Color -> Board -> Board
pawnAttacks Color
color (Board
playerBoard -> Board -> Board
&Board
pawns)
    mapFn :: Int -> Board
mapFn !Int
n = Board -> Board
forall a. (Num a, Ord a) => a -> a
toReverseCondition (Vector Board
attackersVec Vector Board -> Int -> Board
forall a. Storable a => Vector a -> Int -> a
!! Int
n Board -> Board -> Board
& Board
enemyBoard -> Board -> Board
&Board
pawns)
    (!Board
ranks, !Vector Board
attackersVec) = case Color
color of
      Color
White -> (Board
whiteKnightOutpostRanks , Vector Board
whiteKnightOutpostAttackersVec)
      Color
Black -> (Board
blackKnightOutpostRanks , Vector Board
blackKnightOutpostAttackersVec)


evaluateRooksOnOpenFiles :: (?phase :: Phase) => Position -> Score
evaluateRooksOnOpenFiles :: (?phase::Int16) => Position -> Int16
evaluateRooksOnOpenFiles Position {Int16
[ZKey]
Word8
Board
Color
$sel:player:Position :: Position -> Board
$sel:pawns:Position :: Position -> Board
$sel:bishops:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Word8
$sel:phase:Position :: Position -> Int16
$sel:color:Position :: Position -> Color
$sel:enemy:Position :: Position -> Board
$sel:knights:Position :: Position -> Board
$sel:rooks:Position :: Position -> Board
$sel:queens:Position :: Position -> Board
$sel:kings:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:castling:Position :: Position -> Board
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Word8
phase :: Int16
color :: Color
player :: Board
enemy :: Board
pawns :: Board
knights :: Board
bishops :: Board
rooks :: Board
queens :: Board
kings :: Board
enPassant :: Board
castling :: Board
attacked :: Board
leapingCheckers :: Board
sliderCheckers :: Board
pinnedPieces :: Board
..} =
  Int16
(?phase::Int16) => Int16
rookOnSemiOpenFileBonus
  Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* (Board -> Int16
forall {a}. Num a => Board -> a
eval Board
file_A Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Board -> Int16
forall {a}. Num a => Board -> a
eval Board
file_B Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Board -> Int16
forall {a}. Num a => Board -> a
eval Board
file_C Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Board -> Int16
forall {a}. Num a => Board -> a
eval Board
file_D
   Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Board -> Int16
forall {a}. Num a => Board -> a
eval Board
file_E Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Board -> Int16
forall {a}. Num a => Board -> a
eval Board
file_F Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Board -> Int16
forall {a}. Num a => Board -> a
eval Board
file_G Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Board -> Int16
forall {a}. Num a => Board -> a
eval Board
file_H)
  where
    eval :: Board -> a
eval Board
fileBoard
      | Board
playerRooksInFile Board -> Board -> Bool
forall a. Eq a => a -> a -> Bool
== Board
0                                          = a
0
      | Board
pawnsInFile       Board -> Board -> Bool
forall a. Eq a => a -> a -> Bool
== Board
0 Bool -> Bool -> Bool
|| Board -> Int
lastPieceSquare Board
pawnsInFile       Int -> Int -> Bool
<! Int
n = a
2
      | Board
playerPawnsInFile Board -> Board -> Bool
forall a. Eq a => a -> a -> Bool
== Board
0 Bool -> Bool -> Bool
|| Board -> Int
lastPieceSquare Board
playerPawnsInFile Int -> Int -> Bool
<! Int
n = a
1
      | Bool
otherwise                                                      = a
0
      where
        playerRooksInFile :: Board
playerRooksInFile = Board
player Board -> Board -> Board
& Board
rooks Board -> Board -> Board
& Board
fileBoard
        playerPawnsInFile :: Board
playerPawnsInFile = Board
player Board -> Board -> Board
& Board
pawnsInFile
        pawnsInFile :: Board
pawnsInFile       = Board
pawns  Board -> Board -> Board
& Board
fileBoard
        n :: Int
n                 = Board -> Int
lastPieceSquare Board
playerRooksInFile

    (!Int -> Int -> Bool
(<!), !Board -> Int
lastPieceSquare) = case Color
color of
      Color
White -> (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
(<), Board -> Int
msb)
      Color
Black -> (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
(>), Board -> Int
lsb)


evaluatePassedPawns ::
  (?phase :: Phase, ?colorToMove :: Color) => Position -> Score
evaluatePassedPawns :: (?phase::Int16, ?colorToMove::Color) => Position -> Int16
evaluatePassedPawns pos :: Position
pos@Position {Int16
[ZKey]
Word8
Board
Color
$sel:player:Position :: Position -> Board
$sel:pawns:Position :: Position -> Board
$sel:bishops:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Word8
$sel:phase:Position :: Position -> Int16
$sel:color:Position :: Position -> Color
$sel:enemy:Position :: Position -> Board
$sel:knights:Position :: Position -> Board
$sel:rooks:Position :: Position -> Board
$sel:queens:Position :: Position -> Board
$sel:kings:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:castling:Position :: Position -> Board
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Word8
phase :: Int16
color :: Color
player :: Board
enemy :: Board
pawns :: Board
knights :: Board
bishops :: Board
rooks :: Board
queens :: Board
kings :: Board
enPassant :: Board
castling :: Board
attacked :: Board
leapingCheckers :: Board
sliderCheckers :: Board
pinnedPieces :: Board
..} =
  (?phase::Int16, ?colorToMove::Color) => Board -> Int16
Board -> Int16
eval Board
file_A Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ (?phase::Int16, ?colorToMove::Color) => Board -> Int16
Board -> Int16
eval Board
file_B Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ (?phase::Int16, ?colorToMove::Color) => Board -> Int16
Board -> Int16
eval Board
file_C Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ (?phase::Int16, ?colorToMove::Color) => Board -> Int16
Board -> Int16
eval Board
file_D
  Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ (?phase::Int16, ?colorToMove::Color) => Board -> Int16
Board -> Int16
eval Board
file_E Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ (?phase::Int16, ?colorToMove::Color) => Board -> Int16
Board -> Int16
eval Board
file_F Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ (?phase::Int16, ?colorToMove::Color) => Board -> Int16
Board -> Int16
eval Board
file_G Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ (?phase::Int16, ?colorToMove::Color) => Board -> Int16
Board -> Int16
eval Board
file_H
  where
    eval :: Board -> Int16
eval Board
fileBoard
      | Board
pawnsInFile Board -> Board -> Bool
forall a. Eq a => a -> a -> Bool
== Board
0 Bool -> Bool -> Bool
|| Vector Board
blockersVec Vector Board -> Int -> Board
forall a. Storable a => Vector a -> Int -> a
!! Int
n Board -> Board -> Board
& Board
enemyBoard -> Board -> Board
&Board
pawns Board -> Board -> Bool
forall a. Eq a => a -> a -> Bool
/= Board
0 = Int16
0
      | Bool
otherwise = Int16
passerScore Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Int16
escortedPasserScore
      where
        passerScore :: Int16
passerScore
          | (?colorToMove::Color) => Int -> Bool
Int -> Bool
isUnstoppablePawn Int
n = Int16
unstoppablePawnBonus
          | Int -> Int -> Bool
forall {p}. (Eq p, Num p) => p -> Int -> Bool
isFreePasser Int
rank Int
n = Vector ScorePair
freePassedPawnTable (?phase::Int16) => Vector ScorePair -> Int -> Int16
Vector ScorePair -> Int -> Int16
!!% Int
rank
          | Bool
otherwise           = Vector ScorePair
passedPawnTable     (?phase::Int16) => Vector ScorePair -> Int -> Int16
Vector ScorePair -> Int -> Int16
!!% Int
rank
        escortedPasserScore :: Int16
escortedPasserScore = Int16
(?phase::Int16) => Int16
kingEscortedPassedPawnBonus Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
*
           Int -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int -> Int
getSquareDistance Int
n Int
enemyKingSquare
                       Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int -> Int -> Int
getSquareDistance Int
n Int
kingSquare)
        rank :: Int
rank            = Int -> Int
normalizeRank (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Int -> Int
toRank Int
n
        pawnsInFile :: Board
pawnsInFile     = Board
player Board -> Board -> Board
& Board
pawns Board -> Board -> Board
& Board
fileBoard
        n :: Int
n               = Board -> Int
lastPawnSquare Board
pawnsInFile
        kingSquare :: Int
kingSquare      = Board -> Int
lsb (Board
player Board -> Board -> Board
& Board
kings)
        enemyKingSquare :: Int
enemyKingSquare = Board -> Int
lsb (Board
enemy Board -> Board -> Board
& Board
kings)

    isFreePasser :: p -> Int -> Bool
isFreePasser p
rank Int
n =
      Board -> Int -> Bool
testSquare Board
noPieces (Int -> Int
nextRank Int
n)
      Bool -> Bool -> Bool
&& Move -> Position -> Int16
evaluateExchange (Piece -> Promotion -> Int -> Int -> Move
Move Piece
Pawn Promotion
promotion Int
n (Int -> Move) -> Int -> Move
forall a b. (a -> b) -> a -> b
$ Int -> Int
nextRank Int
n) Position
pos Int16 -> Int16 -> Bool
forall a. Ord a => a -> a -> Bool
>= Int16
0
      where
        promotion :: Promotion
promotion | p
rank p -> p -> Bool
forall a. Eq a => a -> a -> Bool
== p
7 = Promotion
QueenProm
                  | Bool
otherwise = Promotion
NoProm

    isUnstoppablePawn :: Int -> Bool
isUnstoppablePawn Int
pawnSquare =
        Board
enemy Board -> Board -> Board
& (Board
knights Board -> Board -> Board
.| Board
bishops Board -> Board -> Board
.| Board
rooks Board -> Board -> Board
.| Board
queens) Board -> Board -> Bool
forall a. Eq a => a -> a -> Bool
== Board
0
      Bool -> Bool -> Bool
&& Int
kingDistance Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
pawnDistance
      where
        pawnDistance :: Int
pawnDistance = Int -> Int -> Int
getSquareDistance Int
pawnSquare Int
promotionSquare
        kingDistance :: Int
kingDistance =
          Int -> Int -> Int
getSquareDistance Int
kingSquare Int
promotionSquare Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
kingDistanceOffset

        promotionSquare :: Int
promotionSquare = Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
promotionRank Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
pawnFile
        pawnFile :: Int
pawnFile        = Int -> Int
toFile Int
pawnSquare
        kingSquare :: Int
kingSquare      = Board -> Int
lsb (Board
enemy Board -> Board -> Board
& Board
kings)
        kingDistanceOffset :: Int
kingDistanceOffset
          | Color
color Color -> Color -> Bool
forall a. Eq a => a -> a -> Bool
/= ?colorToMove::Color
Color
?colorToMove = Int
1
          | Bool
otherwise            = Int
0

    (!Int -> Int
normalizeRank, !Int -> Int
nextRank, !Board -> Int
lastPawnSquare, !Vector Board
blockersVec,
     !Int
promotionRank) =
      case Color
color of
        Color
White ->
          (Int -> Int
forall a. a -> a
forall {k} (cat :: k -> k -> *) (a :: k). Category cat => cat a a
id   , (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
8)     , Board -> Int
msb, Vector Board
whitePassedPawnBlockersVec, Int
7)
        Color
Black ->
          ((Int
7 -), \Int
n -> Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
8, Board -> Int
lsb, Vector Board
blackPassedPawnBlockersVec, Int
0)
    !noPieces :: Board
noPieces = Board -> Board
(~) (Board
player Board -> Board -> Board
.| Board
enemy)


evaluateKingPawnShield :: (?phase :: Phase) => Position -> Score
evaluateKingPawnShield :: (?phase::Int16) => Position -> Int16
evaluateKingPawnShield Position {Int16
[ZKey]
Word8
Board
Color
$sel:player:Position :: Position -> Board
$sel:pawns:Position :: Position -> Board
$sel:bishops:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Word8
$sel:phase:Position :: Position -> Int16
$sel:color:Position :: Position -> Color
$sel:enemy:Position :: Position -> Board
$sel:knights:Position :: Position -> Board
$sel:rooks:Position :: Position -> Board
$sel:queens:Position :: Position -> Board
$sel:kings:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:castling:Position :: Position -> Board
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Word8
phase :: Int16
color :: Color
player :: Board
enemy :: Board
pawns :: Board
knights :: Board
bishops :: Board
rooks :: Board
queens :: Board
kings :: Board
enPassant :: Board
castling :: Board
attacked :: Board
leapingCheckers :: Board
sliderCheckers :: Board
pinnedPieces :: Board
..} =
  Int16 -> (Board -> Int16) -> Maybe Board -> Int16
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int16
0 (?phase::Int16) => Board -> Int16
Board -> Int16
go
    (Maybe Board -> Int16) -> Maybe Board -> Int16
forall a b. (a -> b) -> a -> b
$ (Element [Board] -> Bool) -> [Board] -> Maybe (Element [Board])
forall seq.
SemiSequence seq =>
(Element seq -> Bool) -> seq -> Maybe (Element seq)
find ((Board -> Int -> Bool
`testSquare` Int
kingSquare) (Board -> Bool) -> (Board -> Board) -> Board -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Board
kingRank &))
      [Board
shortCastleFiles, Board
longCastleFiles]
  where
    go :: Board -> Int16
go Board
board =
        Int16
(?phase::Int16) => Int16
pawnShield1RankBonus
        Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Board -> Int16
popCountToScore (Board
pawnShield1Rank Board -> Board -> Board
& Board
board Board -> Board -> Board
& Board
player Board -> Board -> Board
& Board
pawns)
      Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Int16
(?phase::Int16) => Int16
pawnShield2RankBonus
        Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Board -> Int16
popCountToScore (Board
pawnShield2Rank Board -> Board -> Board
& Board
board Board -> Board -> Board
& Board
player Board -> Board -> Board
& Board
pawns)
    (Board
kingRank, Board
pawnShield1Rank, Board
pawnShield2Rank) = case Color
color of
      Color
White -> (Board
rank_1, Board
rank_2, Board
rank_3)
      Color
Black -> (Board
rank_8, Board
rank_7, Board
rank_6)
    kingSquare :: Int
kingSquare = Board -> Int
lsb (Board
player Board -> Board -> Board
& Board
kings)


evaluateCastlingRights :: Position -> Score
evaluateCastlingRights :: Position -> Int16
evaluateCastlingRights Position{Board
$sel:castling:Position :: Position -> Board
castling :: Board
castling}
  | Board
castling Board -> Board -> Bool
forall a. Eq a => a -> a -> Bool
/= Board
0 = Int16
castlingRightsBonus
  | Bool
otherwise    = Int16
0


evaluateIsolatedPawns :: Board -> Score
evaluateIsolatedPawns :: Board -> Int16
evaluateIsolatedPawns Board
pawns =
  Int16
isolatedPawnPenalty Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Board -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Board
isolatedPawnsCount
  where
    isolatedPawnsCount :: Board
isolatedPawnsCount =
        Board -> Board
popCountToBoard (Board
file_B Board -> Board -> Board
& Board
pawns)
        Board -> Board -> Board
forall a. Num a => a -> a -> a
* Board -> Board
forall a. (Num a, Ord a) => a -> a
toReverseCondition (Board
pawns Board -> Board -> Board
& (Board
file_A Board -> Board -> Board
.| Board
file_C))
      Board -> Board -> Board
forall a. Num a => a -> a -> a
+ Board -> Board
popCountToBoard (Board
file_C Board -> Board -> Board
& Board
pawns)
        Board -> Board -> Board
forall a. Num a => a -> a -> a
* Board -> Board
forall a. (Num a, Ord a) => a -> a
toReverseCondition (Board
pawns Board -> Board -> Board
& (Board
file_B Board -> Board -> Board
.| Board
file_D))
      Board -> Board -> Board
forall a. Num a => a -> a -> a
+ Board -> Board
popCountToBoard (Board
file_D Board -> Board -> Board
& Board
pawns)
        Board -> Board -> Board
forall a. Num a => a -> a -> a
* Board -> Board
forall a. (Num a, Ord a) => a -> a
toReverseCondition (Board
pawns Board -> Board -> Board
& (Board
file_C Board -> Board -> Board
.| Board
file_E))
      Board -> Board -> Board
forall a. Num a => a -> a -> a
+ Board -> Board
popCountToBoard (Board
file_E Board -> Board -> Board
& Board
pawns)
        Board -> Board -> Board
forall a. Num a => a -> a -> a
* Board -> Board
forall a. (Num a, Ord a) => a -> a
toReverseCondition (Board
pawns Board -> Board -> Board
& (Board
file_D Board -> Board -> Board
.| Board
file_F))
      Board -> Board -> Board
forall a. Num a => a -> a -> a
+ Board -> Board
popCountToBoard (Board
file_F Board -> Board -> Board
& Board
pawns)
        Board -> Board -> Board
forall a. Num a => a -> a -> a
* Board -> Board
forall a. (Num a, Ord a) => a -> a
toReverseCondition (Board
pawns Board -> Board -> Board
& (Board
file_E Board -> Board -> Board
.| Board
file_G))
      Board -> Board -> Board
forall a. Num a => a -> a -> a
+ Board -> Board
popCountToBoard (Board
file_G Board -> Board -> Board
& Board
pawns)
        Board -> Board -> Board
forall a. Num a => a -> a -> a
* Board -> Board
forall a. (Num a, Ord a) => a -> a
toReverseCondition (Board
pawns Board -> Board -> Board
& (Board
file_F Board -> Board -> Board
.| Board
file_H))


evaluateDoubledPawns :: Board -> Score
evaluateDoubledPawns :: Board -> Int16
evaluateDoubledPawns Board
pawns =
  Int16
doubledPawnPenalty Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Int -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
doubledPawnsCount
  where
    doubledPawnsCount :: Int
doubledPawnsCount =
        Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Board -> Int
popCount (Board
file_A Board -> Board -> Board
& Board
pawns))
      Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Board -> Int
popCount (Board
file_B Board -> Board -> Board
& Board
pawns))
      Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Board -> Int
popCount (Board
file_C Board -> Board -> Board
& Board
pawns))
      Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Board -> Int
popCount (Board
file_D Board -> Board -> Board
& Board
pawns))
      Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Board -> Int
popCount (Board
file_E Board -> Board -> Board
& Board
pawns))
      Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Board -> Int
popCount (Board
file_F Board -> Board -> Board
& Board
pawns))
      Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Board -> Int
popCount (Board
file_G Board -> Board -> Board
& Board
pawns))
      Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Board -> Int
popCount (Board
file_H Board -> Board -> Board
& Board
pawns))
      Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
8


evaluateMaterialTrades :: Score -> Position -> Score
evaluateMaterialTrades :: Int16 -> Position -> Int16
evaluateMaterialTrades Int16
materialScore Position {Int16
[ZKey]
Word8
Board
Color
$sel:player:Position :: Position -> Board
$sel:pawns:Position :: Position -> Board
$sel:bishops:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Word8
$sel:phase:Position :: Position -> Int16
$sel:color:Position :: Position -> Color
$sel:enemy:Position :: Position -> Board
$sel:knights:Position :: Position -> Board
$sel:rooks:Position :: Position -> Board
$sel:queens:Position :: Position -> Board
$sel:kings:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:castling:Position :: Position -> Board
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Word8
phase :: Int16
color :: Color
player :: Board
enemy :: Board
pawns :: Board
knights :: Board
bishops :: Board
rooks :: Board
queens :: Board
kings :: Board
enPassant :: Board
castling :: Board
attacked :: Board
leapingCheckers :: Board
sliderCheckers :: Board
pinnedPieces :: Board
..} =
    Int16 -> Int16
convert (Int16
losingPenalty Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
- Int16
winningPenalty)
  where
    losingPenalty :: Int16
losingPenalty =
      Int16
pieceTradesPenalty Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Int16
losingMissingPieces Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Int16
absoluteMaterialScore Int16 -> Int16 -> Int16
forall a. Integral a => a -> a -> a
/ Int16
700
    winningPenalty :: Int16
winningPenalty =
      Int16
pawnTradesPenalty  Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Int16
winningMissingPawns Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Int16
absoluteMaterialScore Int16 -> Int16 -> Int16
forall a. Integral a => a -> a -> a
/ Int16
800
    losingMissingPieces :: Int16
losingMissingPieces = Int16 -> Int16 -> Int16
forall a. Ord a => a -> a -> a
max Int16
0
      (Int16
7 Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
- Board -> Int16
popCountToScore (Board
losingBoard Board -> Board -> Board
& (Board
knights Board -> Board -> Board
.| Board
bishops Board -> Board -> Board
.| Board
rooks Board -> Board -> Board
.| Board
queens)))
    winningMissingPawns :: Int16
winningMissingPawns =
      Int16
8 Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
- Board -> Int16
popCountToScore (Board
winningBoard Board -> Board -> Board
& Board
pawns)
    absoluteMaterialScore :: Int16
absoluteMaterialScore = Int16 -> Int16
forall a. Num a => a -> a
abs Int16
materialScore
    (Board
winningBoard, Board
losingBoard, Int16 -> Int16
convert)
      | Int16
materialScore Int16 -> Int16 -> Bool
forall a. Ord a => a -> a -> Bool
> Int16
0 = (Board
player, Board
enemy , Int16 -> Int16
forall a. a -> a
forall {k} (cat :: k -> k -> *) (a :: k). Category cat => cat a a
id)
      | Bool
otherwise         = (Board
enemy , Board
player, Int16 -> Int16
forall a. Num a => a -> a
negate)


getScoresBatch :: (?phase :: Phase) => Position -> ScoresBatch
getScoresBatch :: (?phase::Int16) => Position -> ScoresBatch
getScoresBatch Position
pos
  | Position -> Bool
isKingInCheck Position
pos = ScoresBatch
emptyScoresBatch
getScoresBatch Position {Int16
[ZKey]
Word8
Board
Color
$sel:player:Position :: Position -> Board
$sel:pawns:Position :: Position -> Board
$sel:bishops:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Word8
$sel:phase:Position :: Position -> Int16
$sel:color:Position :: Position -> Color
$sel:enemy:Position :: Position -> Board
$sel:knights:Position :: Position -> Board
$sel:rooks:Position :: Position -> Board
$sel:queens:Position :: Position -> Board
$sel:kings:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:castling:Position :: Position -> Board
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Word8
phase :: Int16
color :: Color
player :: Board
enemy :: Board
pawns :: Board
knights :: Board
bishops :: Board
rooks :: Board
queens :: Board
kings :: Board
enPassant :: Board
castling :: Board
attacked :: Board
leapingCheckers :: Board
sliderCheckers :: Board
pinnedPieces :: Board
..} = ScoresBatch {Int16
$sel:mobility:ScoresBatch :: Int16
$sel:threats:ScoresBatch :: Int16
$sel:kingThreats:ScoresBatch :: Int16
mobility :: Int16
kingThreats :: Int16
threats :: Int16
..}
  where
    mobility :: Int16
mobility =
      Int16
knightsMobility Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Int16
bishopsMobility Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Int16
rooksMobility Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Int16
queensMobility

    kingThreats :: Int16
kingThreats =
      (Vector Int16
kingThreatPiecesTable Vector Int16 -> Int -> Int16
forall a. Storable a => Vector a -> Int -> a
!! Int
piecesCount) Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Int16
kingThreatScore Int16 -> Int16 -> Int16
forall a. Integral a => a -> a -> a
/ Int16
100

    piecesCount :: Int
piecesCount =
      Int
knightsCount Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
bishopsCount Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
rooksCount Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
queensCount

    threats :: Int16
threats =
      Int16
queenThreat
        Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Board -> Int16
popCountToScore (Board
player Board -> Board -> Board
& Board
queens Board -> Board -> Board
& (Board
minorDefended Board -> Board -> Board
.| Board
pawnDefended))
      Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Int16
rookThreat
        Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Board -> Int16
popCountToScore (Board
player Board -> Board -> Board
& Board
rooks Board -> Board -> Board
& Board
pawnDefended)
      Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Int16
minorPieceThreat
        Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Board -> Int16
popCountToScore (Board
player Board -> Board -> Board
& (Board
knights Board -> Board -> Board
.| Board
bishops) Board -> Board -> Board
& Board
pawnDefended)

    kingThreatScore :: Int16
kingThreatScore =
        Int16
threatByMinorPenalty Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Int -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral
          (Int
byKnightThreats Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
byBishopThreats)
      Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Int16
threatByRookPenalty  Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Int -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
byRookThreats
      Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Int16
threatByQueenPenalty Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
* Int -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
byQueenThreats

    (Int16
knightsMobility, Int
byKnightThreats, Int
knightsCount) =
      (?phase::Int16) =>
Vector ScorePair
-> (Int -> Board) -> Board -> Board -> (Int16, Int, Int)
Vector ScorePair
-> (Int -> Board) -> Board -> Board -> (Int16, Int, Int)
foldBoardScores Vector ScorePair
knightMobilityTable
        Int -> Board
knightAttacks
        Board
pawnDefended
        (Board
unpinnedBoard -> Board -> Board
&Board
knights)

    (Int16
bishopsMobility, Int
byBishopThreats, Int
bishopsCount) =
      (?phase::Int16) =>
Vector ScorePair
-> (Int -> Board) -> Board -> Board -> (Int16, Int, Int)
Vector ScorePair
-> (Int -> Board) -> Board -> Board -> (Int16, Int, Int)
foldBoardScores Vector ScorePair
bishopMobilityTable
        (Board -> Board -> Board -> Int -> Board
bishopMoves (Board
allPieces Board -> Board -> Board
.\ Board
player Board -> Board -> Board
& Board
queens) Board
pinnedPieces Board
king)
        Board
pawnDefended
        (Board
playerBoard -> Board -> Board
&Board
bishops)

    (Int16
rooksMobility, Int
byRookThreats, Int
rooksCount) =
      (?phase::Int16) =>
Vector ScorePair
-> (Int -> Board) -> Board -> Board -> (Int16, Int, Int)
Vector ScorePair
-> (Int -> Board) -> Board -> Board -> (Int16, Int, Int)
foldBoardScores Vector ScorePair
rookMobilityTable
        (Board -> Board -> Board -> Int -> Board
rookMoves (Board
allPieces Board -> Board -> Board
.\ Board
player Board -> Board -> Board
& Board
queens)
         Board
pinnedPieces Board
king)
        (Board
pawnDefended Board -> Board -> Board
.| Board
minorDefended)
        (Board
playerBoard -> Board -> Board
&Board
rooks)

    (Int16
queensMobility, Int
byQueenThreats, Int
queensCount) =
      (?phase::Int16) =>
Vector ScorePair
-> (Int -> Board) -> Board -> Board -> (Int16, Int, Int)
Vector ScorePair
-> (Int -> Board) -> Board -> Board -> (Int16, Int, Int)
foldBoardScores Vector ScorePair
queenMobilityTable
        (Board -> Board -> Board -> Int -> Board
queenMoves Board
allPieces Board
pinnedPieces Board
king)
        (Board
pawnDefended Board -> Board -> Board
.| Board
minorDefended Board -> Board -> Board
.| Board
rookDefended)
        (Board
playerBoard -> Board -> Board
&Board
queens)


    foldBoardScores :: Vector ScorePair
-> (Int -> Board) -> Board -> Board -> (Int16, Int, Int)
foldBoardScores !Vector ScorePair
mobilityTable !Int -> Board
movesFn !Board
defended !Board
board =
      (Int16, Int, Int)
-> ((Int16, Int, Int) -> Board -> (Int16, Int, Int))
-> (Int -> Board)
-> Board
-> (Int16, Int, Int)
forall a b. a -> (a -> b -> a) -> (Int -> b) -> Board -> a
foldlBoard (Int16
0, Int
0, Int
0) (?phase::Int16) => (Int16, Int, Int) -> Board -> (Int16, Int, Int)
(Int16, Int, Int) -> Board -> (Int16, Int, Int)
foldFn Int -> Board
movesFn Board
board
      where
        foldFn :: (Int16, Int, Int) -> Board -> (Int16, Int, Int)
foldFn (!Int16
x, !Int
y, !Int
z) !Board
attackArea =
          (Int16
x Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
+ Vector ScorePair
mobilityTable
           (?phase::Int16) => Vector ScorePair -> Int -> Int16
Vector ScorePair -> Int -> Int16
!!% Board -> Int
popCount (Board
attackArea Board -> Board -> Board
.\ (Board
player Board -> Board -> Board
.| Board
defended)),
           Int
y Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
threatenedSquares,
           Int
z Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
forall a. (Ord a, Num a) => a -> a
toCondition Int
threatenedSquares)
          where
            !threatenedSquares :: Int
threatenedSquares = Board -> Int
popCount (Board
enemyKingArea Board -> Board -> Board
& Board
attackArea)

    !king :: Board
king           = Board
player Board -> Board -> Board
& Board
kings
    !unpinned :: Board
unpinned       = Board
player Board -> Board -> Board
.\ Board
pinnedPieces
    !allPieces :: Board
allPieces      = Board
player Board -> Board -> Board
.| Board
enemy

    !enemyKingArea :: Board
enemyKingArea  =
      Int -> Board
kingAttacks (Board -> Int
lsb (Board
enemyBoard -> Board -> Board
&Board
kings))
    !pawnDefended :: Board
pawnDefended   =
      Color -> Board -> Board
pawnAttacks (Color -> Color
reverseColor Color
color) (Board
enemyBoard -> Board -> Board
&Board
pawns)
    !minorDefended :: Board
minorDefended =
         (Int -> Board) -> Board -> Board
foldBoardAttacks Int -> Board
knightAttacks (Board
enemyBoard -> Board -> Board
&Board
knights)
      Board -> Board -> Board
.| (Int -> Board) -> Board -> Board
foldBoardAttacks (Board -> Int -> Board
bishopAttacks Board
allPieces) (Board
enemyBoard -> Board -> Board
&Board
bishops)
    !rookDefended :: Board
rookDefended =
       (Int -> Board) -> Board -> Board
foldBoardAttacks (Board -> Int -> Board
rookAttacks Board
allPieces) (Board
enemyBoard -> Board -> Board
&Board
rooks)


evaluateExchange :: Move -> Position -> Score
evaluateExchange :: Move -> Position -> Int16
evaluateExchange Move
initialMv Position
initialPos =
  let ?phase = Position
initialPos.phase
  in (?phase::Int16) => Move -> Position -> Int16
Move -> Position -> Int16
go Move
initialMv Position
initialPos
  where
    !square :: Int
square = Move
initialMv.end
    go :: Move -> Position -> Int16
go !Move
mv !Position
pos =
      let newPos :: Position
newPos = Move -> Position -> Position
makeMove Move
mv Position
pos
      in (?phase::Int16) => Move -> Position -> Int16
Move -> Position -> Int16
evaluateCapturedPiece Move
mv Position
pos
      Int16 -> Int16 -> Int16
forall a. Num a => a -> a -> a
- case [Move] -> Maybe (Element [Move])
forall mono. MonoFoldable mono => mono -> Maybe (Element mono)
headMay ([Move] -> Maybe (Element [Move]))
-> [Move] -> Maybe (Element [Move])
forall a b. (a -> b) -> a -> b
$ Int -> Position -> [Move]
staticExchangeCaptures Int
square Position
newPos of
        Just Element [Move]
newMv -> Int16 -> Int16 -> Int16
forall a. Ord a => a -> a -> a
max Int16
0 (Int16 -> Int16) -> Int16 -> Int16
forall a b. (a -> b) -> a -> b
$! Move -> Position -> Int16
go Element [Move]
Move
newMv Position
newPos
        Maybe (Element [Move])
Nothing    -> Int16
0


{-# INLINE evaluateMvvLva #-}
evaluateMvvLva :: Move -> Position -> Word8
evaluateMvvLva :: Move -> Position -> Word8
evaluateMvvLva Move {Int
Promotion
Piece
piece :: Piece
promotion :: Promotion
start :: Int
end :: Int
$sel:piece:Move :: Move -> Piece
$sel:promotion:Move :: Move -> Promotion
$sel:start:Move :: Move -> Int
$sel:end:Move :: Move -> Int
..} Position
pos =
  Word8
promotionValue Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8 -> (Piece -> Word8) -> Maybe Piece -> Word8
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Word8
0 Piece -> Word8
exchangeValue (Int -> Position -> Maybe Piece
maybeCapturedPieceAt Int
end Position
pos)
  where
    exchangeValue :: Piece -> Word8
exchangeValue Piece
capturedPiece =
      Word8
10 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
* (Piece -> Word8
getPieceValue Piece
capturedPiece Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
1)
      Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
- Piece -> Word8
getPieceValue Piece
piece
    promotionValue :: Word8
promotionValue = Word8
10 Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
* (Word8
promotionPieceValue Word8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
+ Word8
1)
    promotionPieceValue :: Word8
promotionPieceValue = case Promotion
promotion of
      Promotion
QueenProm  -> Piece -> Word8
getPieceValue Piece
Queen
      Promotion
KnightProm -> Piece -> Word8
getPieceValue Piece
Knight
      Promotion
BishopProm -> Piece -> Word8
getPieceValue Piece
Bishop
      Promotion
RookProm   -> Piece -> Word8
getPieceValue Piece
Rook
      Promotion
NoProm     -> Word8
0


data ScoresBatch = ScoresBatch {
    ScoresBatch -> Int16
mobility    :: Score
  , ScoresBatch -> Int16
threats     :: Score
  , ScoresBatch -> Int16
kingThreats :: Score

}

emptyScoresBatch :: ScoresBatch
emptyScoresBatch :: ScoresBatch
emptyScoresBatch = ScoresBatch {
    $sel:mobility:ScoresBatch :: Int16
mobility    = Int16
0
  , $sel:threats:ScoresBatch :: Int16
threats     = Int16
0
  , $sel:kingThreats:ScoresBatch :: Int16
kingThreats = Int16
0
}


popCountToScore :: Board -> Score
popCountToScore :: Board -> Int16
popCountToScore = Int -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int16) -> (Board -> Int) -> Board -> Int16
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Board -> Int
popCount