Fix bugs with en passant

This commit is contained in:
Mattia Giambirtone 2024-04-12 16:05:01 +02:00
parent 54a6217bd3
commit f75f7533f5
1 changed files with 30 additions and 27 deletions

View File

@ -133,12 +133,15 @@ proc doMove(self: ChessBoard, move: Move)
proc pretty*(self: ChessBoard): string
proc spawnPiece(self: ChessBoard, location: Location, piece: Piece)
proc updateAttackedSquares(self: ChessBoard)
proc updateSlidingAttacks(self: ChessBoard)
proc getPinnedDirections(self: ChessBoard, loc: Location): seq[Location]
proc getAttacks*(self: ChessBoard, loc: Location): Attacked
proc getSlidingAttacks(self: ChessBoard, loc: Location): tuple[attacks: Attacked, pins: Attacked]
proc inCheck*(self: ChessBoard, color: PieceColor = None): bool
proc toFEN*(self: ChessBoard): string
proc undoLastMove*(self: ChessBoard)
proc movePiece(self: ChessBoard, move: Move, attack: bool = true)
proc removePiece(self: ChessBoard, location: Location, attack: bool = true)
proc extend[T](self: var seq[T], other: openarray[T]) {.inline.} =
@ -847,27 +850,21 @@ proc generatePawnMoves(self: ChessBoard, location: Location): seq[Move] =
if target.isValid():
let otherPiece = self.grid[target]
if target == self.position.enPassantSquare and self.grid[enPassantPawn].color == piece.color.opposite():
# Ensure en passant doesn't create a check
let king = self.getKing(piece.color)
var ok = true
if king.row == location.row:
var current = location
while true:
current = current + piece.color.rightSide()
if not current.isValid():
break
let p = self.grid[current.row, current.col]
if p.color == piece.color:
break
if p.color == None:
continue
# Bishops can't create checks through en passant (neither can knights)
if p.color == piece.color.opposite() and p.kind in [Queen, Rook]:
ok = false
break
if ok:
# En passant may be possible
let targetPawn = self.grid[enPassantPawn]
# Remove both pieces and see if the king ends up in check
self.removePiece(enPassantPawn, attack=false)
self.removePiece(location, attack=false)
self.updateAttackedSquares()
if not self.inCheck(piece.color):
# King is not in check after en passant: move is legal
directions.add(diagonal)
# Reset what we just did and reupdate the attack metadata
self.spawnPiece(location, piece)
self.spawnPiece(enPassantPawn, targetPawn)
self.updateAttackedSquares()
elif otherPiece.color == piece.color.opposite() and otherPiece.kind != King: # Can't capture the king!
# A capture may be possible
directions.add(diagonal)
# Check for pins
let pinned = self.getPinnedDirections(location)
@ -924,8 +921,9 @@ proc generateSlidingMoves(self: ChessBoard, location: Location): seq[Move] =
if direction in pinned:
newDirections.add(direction)
directions = newDirections
let checked = self.inCheck()
let resolutions = if not checked: @[] else: self.getCheckResolutions(piece.color)
let
checked = self.inCheck()
resolutions = if not checked: @[] else: self.getCheckResolutions(piece.color)
for direction in directions:
# Slide in this direction as long as it's possible
var
@ -1333,9 +1331,10 @@ proc updateSlidingAttacks(self: ChessBoard) =
proc updateAttackedSquares(self: ChessBoard) =
## Updates internal metadata about which squares
## are attacked
self.position.attacked.white.setLen(0)
self.position.attacked.black.setLen(0)
self.position.pinned.white.setLen(0)
self.position.pinned.black.setLen(0)
# Pawns
self.updatePawnAttacks()
# Sliding pieces
@ -1687,8 +1686,6 @@ proc undoLastMove*(self: ChessBoard) =
proc isLegal(self: ChessBoard, move: Move): bool {.inline.} =
## Returns whether the given move is legal
if self.grid[move.startSquare.row, move.startSquare.col].color != self.getActiveColor():
return false
return move in self.generateMoves(move.startSquare)
@ -2047,6 +2044,8 @@ proc handleMoveCommand(board: ChessBoard, command: seq[string]): Move {.discarda
move.flags = move.flags or CastleLong.uint16
elif move.targetSquare == move.startSquare + shortCastleKing():
move.flags = move.flags or CastleShort.uint16
if move.targetSquare == board.getEnPassantTarget():
move.flags = move.flags or EnPassant.uint16
result = board.makeMove(move)
if result == emptyMove():
echo &"Error: move: {moveString} is illegal"
@ -2095,7 +2094,7 @@ proc handlePositionCommand(board: var ChessBoard, command: seq[string]) =
try:
tempBoard = newChessboardFromFEN(fenString)
except ValueError:
echo &"Error: position: {getCurrentExceptionMsg()}"
echo &"error: position: {getCurrentExceptionMsg()}"
return
if args.len() > 0:
var i = 0
@ -2113,6 +2112,9 @@ proc handlePositionCommand(board: var ChessBoard, command: seq[string]) =
echo board
of "pretty":
echo board.pretty()
else:
echo &"error: position: unknown subcommand '{command[1]}'"
return
proc handleUCICommand(board: var ChessBoard, command: seq[string]) =
@ -2154,7 +2156,8 @@ const HELP_TEXT = """Nimfish help menu:
- ep: Print the current en passant target
- pretty: Shorthand for "position pretty"
- print: Shorthand for "position print"
- fen: Shorthand for "position fen" (print only!)
- fen: Shorthand for "position fen"
- pos <args>: Shorthand for "position <args>"
- get <square>: Get the piece on the given square
- uci: enter UCI mode (WIP)
"""
@ -2189,7 +2192,7 @@ proc main: int =
echo HELP_TEXT
of "go":
handleGoCommand(board, cmd)
of "position":
of "position", "pos":
handlePositionCommand(board, cmd)
of "move":
handleMoveCommand(board, cmd)