module Evaluation.Material (evaluatePlayerMaterial, evaluateCapturedPiece) where

import           AppPrelude

import           Evaluation.Parameters
import           Evaluation.ScoreBreakdown
import           Models.Move
import           Models.Piece
import           Models.Position
import           Models.Score
import           Utils.Board


evaluatePlayerMaterial
  :: (?phase :: Phase) => Position -> Board -> Color -> MaterialBreakdown
evaluatePlayerMaterial :: (?phase::Score) => Position -> Board -> Color -> MaterialBreakdown
evaluatePlayerMaterial Position {Score
[ZKey]
Ply
Board
Color
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Score
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 -> Ply
$sel:phase:Position :: Position -> Score
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:pawns:Position :: Position -> Board
$sel:knights:Position :: Position -> Board
$sel:bishops: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
..} !Board
board = \case
    Color
White -> ScorePair
-> ScorePair
-> ScorePair
-> ScorePair
-> ScorePair
-> ScorePair
-> MaterialBreakdown
MaterialBreakdown
          (Score -> Board -> ScorePair
boardScore Score
(?phase::Score) => Score
queenScore                     (Board
board Board -> Board -> Board
& Board
queens))
          (Score -> Board -> ScorePair
boardScore Score
(?phase::Score) => Score
rookScore                      (Board
board Board -> Board -> Board
& Board
rooks))
          (Score -> Board -> ScorePair
boardScore Score
bishopScore                    (Board
board Board -> Board -> Board
& Board
bishops))
          (Score -> Board -> ScorePair
boardScore Score
knightScore                    (Board
board Board -> Board -> Board
& Board
knights))
          (Score -> Board -> ScorePair
boardScore Score
pawnScore                      (Board
board Board -> Board -> Board
& Board
pawns))
          (Score -> Score -> ScorePair
ScorePair Score
0 (Vector ScorePair
whiteKingSquareTable (?phase::Score) => Vector ScorePair -> Int -> Score
Vector ScorePair -> Int -> Score
!!% Board -> Int
lsb (Board
board Board -> Board -> Board
& Board
kings)))
    Color
Black -> ScorePair
-> ScorePair
-> ScorePair
-> ScorePair
-> ScorePair
-> ScorePair
-> MaterialBreakdown
MaterialBreakdown
          (Score -> Board -> ScorePair
boardScore Score
(?phase::Score) => Score
queenScore                     (Board
board Board -> Board -> Board
& Board
queens))
          (Score -> Board -> ScorePair
boardScore Score
(?phase::Score) => Score
rookScore                      (Board
board Board -> Board -> Board
& Board
rooks))
          (Score -> Board -> ScorePair
boardScore Score
bishopScore                    (Board
board Board -> Board -> Board
& Board
bishops))
          (Score -> Board -> ScorePair
boardScore Score
knightScore                    (Board
board Board -> Board -> Board
& Board
knights))
          (Score -> Board -> ScorePair
boardScore Score
pawnScore                      (Board
board Board -> Board -> Board
& Board
pawns))
          (Score -> Score -> ScorePair
ScorePair Score
0 (Vector ScorePair
blackKingSquareTable (?phase::Score) => Vector ScorePair -> Int -> Score
Vector ScorePair -> Int -> Score
!!% Board -> Int
lsb (Board
board Board -> Board -> Board
& Board
kings)))


{-# INLINE  boardScore #-}
boardScore :: Score -> Board -> ScorePair
boardScore :: Score -> Board -> ScorePair
boardScore !Score
pieceTypeScore !Board
board =
  Score -> Score -> ScorePair
ScorePair Score
materialScore Score
0
  where
    materialScore :: Score
materialScore = Score
pieceTypeScore Score -> Score -> Score
forall a. Num a => a -> a -> a
* Int -> Score
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Board -> Int
popCount Board
board)


{-# INLINE  evaluateCapturedPiece #-}
evaluateCapturedPiece :: (?phase :: Phase) => Move -> Position -> Score
evaluateCapturedPiece :: (?phase::Score) => Move -> Position -> Score
evaluateCapturedPiece 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 =
  (?phase::Score) => Promotion -> Score
Promotion -> Score
evaluatePromotion Promotion
promotion
  Score -> Score -> Score
forall a. Num a => a -> a -> a
+ Score -> (Piece -> Score) -> Maybe Piece -> Score
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Score
0 (?phase::Score) => Piece -> Score
Piece -> Score
evaluatePiece (Int -> Position -> Maybe Piece
maybeCapturedPieceAt Int
end Position
pos)


{-# INLINE  evaluatePromotion #-}
evaluatePromotion :: (?phase :: Phase) => Promotion -> Score
evaluatePromotion :: (?phase::Score) => Promotion -> Score
evaluatePromotion = \case
  Promotion
KnightProm -> Score
knightScore
  Promotion
BishopProm -> Score
bishopScore
  Promotion
RookProm   -> Score
(?phase::Score) => Score
rookScore
  Promotion
QueenProm  -> Score
(?phase::Score) => Score
queenScore
  Promotion
NoProm     -> Score
0


{-# INLINE  evaluatePiece #-}
evaluatePiece :: (?phase :: Phase) => Piece -> Score
evaluatePiece :: (?phase::Score) => Piece -> Score
evaluatePiece = \case
  Piece
Pawn   -> Score
pawnScore
  Piece
Knight -> Score
knightScore
  Piece
Bishop -> Score
bishopScore
  Piece
Rook   -> Score
(?phase::Score) => Score
rookScore
  Piece
Queen  -> Score
(?phase::Score) => Score
queenScore
  Piece
King   -> Score
0