module MoveGen.MakeMove (makeMove, makeNullMove) where

import           AppPrelude

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


makeMove :: Move -> Position -> Position
makeMove :: Move -> Position -> Position
makeMove Move {Square
Promotion
Piece
piece :: Piece
promotion :: Promotion
start :: Square
end :: Square
$sel:piece:Move :: Move -> Piece
$sel:promotion:Move :: Move -> Promotion
$sel:start:Move :: Move -> Square
$sel:end:Move :: Move -> Square
..} Position
pos =
  Position -> Position
makeNullMove
  (Position -> Position) -> Position -> Position
forall a b. (a -> b) -> a -> b
$ Piece -> Promotion -> Board -> Board -> Position -> Position
movePiece Piece
piece Promotion
promotion Board
startBoard Board
endBoard
  (Position -> Position) -> Position -> Position
forall a b. (a -> b) -> a -> b
$ Board -> Board -> Position -> Position
updatePlayerBoards Board
startBoard Board
endBoard Position
pos
  where
    !startBoard :: Board
startBoard = Square -> Board
toBoard Square
start
    !endBoard :: Board
endBoard = Square -> Board
toBoard Square
end


makeNullMove :: Position -> Position
makeNullMove :: Position -> Position
makeNullMove pos :: Position
pos@Position {Color
color :: Color
$sel:color:Position :: Position -> Color
color, Board
player :: Board
$sel:player:Position :: Position -> Board
player,  Board
enemy :: Board
$sel:enemy:Position :: Position -> Board
enemy, Board
enPassant :: Board
$sel:enPassant:Position :: Position -> Board
enPassant} =
  Position
pos {
    color           = reverseColor color
  , phase           = getPhase pos
  , player          = enemy
  , enemy           = player
  , attacked        = allAttacks pos
  , enPassant       = toReverseCondition enPassantPinnedPawns * enPassant
  , leapingCheckers = getLeapingCheckers pos
  , sliderCheckers  = getSliderCheckers bishopCheckerRays rookCheckerRays
                                        pos
  , pinnedPieces    = getPinnedPieces bishopCheckerRays rookCheckerRays
                                      sliderRays        pos
  }
  where
    bishopCheckerRays :: Board
bishopCheckerRays    = Position -> Board
getBishopCheckerRays    Position
pos
    rookCheckerRays :: Board
rookCheckerRays      = Position -> Board
getRookCheckerRays      Position
pos
    sliderRays :: Board
sliderRays           = Position -> Board
getEnemyKingSliderRays  Position
pos
    enPassantPinnedPawns :: Board
enPassantPinnedPawns = Position -> Board
getEnPassantPinnedPawns Position
pos


updatePlayerBoards :: Board -> Board -> Position -> Position
updatePlayerBoards :: Board -> Board -> Position -> Position
updatePlayerBoards Board
start Board
end pos :: Position
pos@Position {Phase
[ZKey]
Ply
Board
Color
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:phase:Position :: Position -> Phase
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Phase
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: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:castling:Position :: Position -> Board
..} =
  Position
pos {
      previousPositions    = getZobristKey pos
        : if halfMoveClock == 0 then [] else previousPositions
    , halfMoveClock        = fromIntegral
        (toReverseCondition (enemy & end)) * (halfMoveClock + 1)
    , player               = (player ^ start) .| end
    , enemy                = enemy .\ end
    , pawns                = pawns .\ end
    , knights              = knights .\ end
    , bishops              = bishops .\ end
    , rooks                = rooks .\ end
    , queens               = queens .\ end
  }


movePiece :: Piece -> Promotion -> Board -> Board -> Position -> Position
movePiece :: Piece -> Promotion -> Board -> Board -> Position -> Position
movePiece Piece
Pawn Promotion
NoProm Board
start Board
end pos :: Position
pos@Position {Phase
[ZKey]
Ply
Board
Color
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:phase:Position :: Position -> Phase
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Ply
$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:castling:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Phase
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
..} =
  Position
pos {
      halfMoveClock = 0
    , pawns         = (pawns ^ (start .| enPassantCapture)) .| end
    , enemy         = enemy ^ enPassantCapture
    , enPassant     = start <<! 8 & end !>> 8
  }
  where
    (Board -> Square -> Board
(<<!), Board -> Square -> Board
(!>>)) = case Color
color of
      Color
White -> (Board -> Square -> Board
forall a. Bits a => a -> Square -> a
(<<), Board -> Square -> Board
forall a. Bits a => a -> Square -> a
(>>))
      Color
Black -> (Board -> Square -> Board
forall a. Bits a => a -> Square -> a
(>>), Board -> Square -> Board
forall a. Bits a => a -> Square -> a
(<<))
    enPassantCapture :: Board
enPassantCapture = (Board
enPassant Board -> Board -> Board
& Board
end) Board -> Square -> Board
!>> Square
8

movePiece Piece
Pawn Promotion
KnightProm Board
start Board
end pos :: Position
pos@Position {Phase
[ZKey]
Ply
Board
Color
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:phase:Position :: Position -> Phase
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Ply
$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:castling:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Phase
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
..} =
  Position
pos {
      halfMoveClock = 0
    , pawns         = pawns ^ start
    , knights       = knights .| end
    , enPassant     = 0
  }

movePiece Piece
Pawn Promotion
BishopProm Board
start Board
end pos :: Position
pos@Position {Phase
[ZKey]
Ply
Board
Color
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:phase:Position :: Position -> Phase
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Ply
$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:castling:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Phase
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
..} =
  Position
pos {
      halfMoveClock = 0
    , pawns         = pawns ^ start
    , bishops       = bishops .| end
    , enPassant     = 0
  }

movePiece Piece
Pawn Promotion
RookProm !Board
start !Board
end pos :: Position
pos@Position {Phase
[ZKey]
Ply
Board
Color
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:phase:Position :: Position -> Phase
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Ply
$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:castling:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Phase
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
..} =
  Position
pos {
      halfMoveClock = 0
    , pawns         = pawns ^ start
    , rooks         = rooks .| end
    , enPassant     = 0
  }

movePiece Piece
Pawn Promotion
QueenProm Board
start Board
end pos :: Position
pos@Position {Phase
[ZKey]
Ply
Board
Color
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:phase:Position :: Position -> Phase
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Ply
$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:castling:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Phase
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
..} =
  Position
pos {
      halfMoveClock = 0
    , pawns         = pawns ^ start
    , queens        = queens .| end
    , enPassant     = 0
  }

movePiece Piece
Knight Promotion
_ Board
start Board
end pos :: Position
pos@Position {Phase
[ZKey]
Ply
Board
Color
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:phase:Position :: Position -> Phase
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Ply
$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:castling:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Phase
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
..} =
  Position
pos {
      knights   = (knights ^ start) .| end
    , enPassant = 0
  }

movePiece Piece
Bishop Promotion
_ Board
start Board
end pos :: Position
pos@Position {Phase
[ZKey]
Ply
Board
Color
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:phase:Position :: Position -> Phase
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Ply
$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:castling:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Phase
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
..} =
  Position
pos {
      bishops   = (bishops ^ start) .| end
    , enPassant = 0
  }

movePiece Piece
Rook Promotion
_ Board
start Board
end pos :: Position
pos@Position {Phase
[ZKey]
Ply
Board
Color
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:phase:Position :: Position -> Phase
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Ply
$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:castling:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Phase
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
..} =
  Position
pos {
      rooks     = (rooks ^ start) .| end
    , castling  = castling .\ start
    , enPassant = 0
  }

movePiece Piece
Queen Promotion
_ Board
start Board
end pos :: Position
pos@Position {Phase
[ZKey]
Ply
Board
Color
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:phase:Position :: Position -> Phase
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Ply
$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:castling:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Phase
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
..} =
  Position
pos {
      queens    = (queens ^ start) .| end
    , enPassant = 0
  }

movePiece Piece
King Promotion
_ Board
start Board
end pos :: Position
pos@Position {Phase
[ZKey]
Ply
Board
Color
$sel:color:Position :: Position -> Color
$sel:player:Position :: Position -> Board
$sel:enemy:Position :: Position -> Board
$sel:enPassant:Position :: Position -> Board
$sel:phase:Position :: Position -> Phase
$sel:attacked:Position :: Position -> Board
$sel:leapingCheckers:Position :: Position -> Board
$sel:sliderCheckers:Position :: Position -> Board
$sel:pinnedPieces:Position :: Position -> Board
$sel:previousPositions:Position :: Position -> [ZKey]
$sel:halfMoveClock:Position :: Position -> Ply
$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:castling:Position :: Position -> Board
previousPositions :: [ZKey]
halfMoveClock :: Ply
phase :: Phase
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
..} =
  Position
pos {
      kings     = (kings ^ start) .| end
    , castling  = castling .\ kingRank
    , player    = (player ^ rookStart) .| rookEnd
    , rooks     = (rooks ^ rookStart) .| rookEnd
    , enPassant = 0
  }
  where
    rookStart :: Board
rookStart   = Board
shortCastle Board -> Square -> Board
forall a. Bits a => a -> Square -> a
<< Square
1 Board -> Board -> Board
.| Board
longCastle Board -> Square -> Board
forall a. Bits a => a -> Square -> a
>> Square
2
    rookEnd :: Board
rookEnd     = Board
shortCastle Board -> Square -> Board
forall a. Bits a => a -> Square -> a
>> Square
1 Board -> Board -> Board
.| Board
longCastle Board -> Square -> Board
forall a. Bits a => a -> Square -> a
<< Square
1
    shortCastle :: Board
shortCastle = (Board
start Board -> Square -> Board
forall a. Bits a => a -> Square -> a
<< Square
2) Board -> Board -> Board
& Board
end
    longCastle :: Board
longCastle  = (Board
start Board -> Square -> Board
forall a. Bits a => a -> Square -> a
>> Square
2) Board -> Board -> Board
& Board
end
    kingRank :: Board
kingRank    = Vector Board
fileMovesVec Vector Board -> Square -> Board
forall a. Storable a => Vector a -> Square -> a
!! Board -> Square
lsb Board
start