Add nim.cfg and various bugfixes to movegen
This commit is contained in:
parent
68c170568e
commit
04bfe74ad5
|
@ -2,7 +2,6 @@
|
||||||
nimcache/
|
nimcache/
|
||||||
nimblecache/
|
nimblecache/
|
||||||
htmldocs/
|
htmldocs/
|
||||||
nim.cfg
|
|
||||||
bin
|
bin
|
||||||
# Python
|
# Python
|
||||||
__pycache__
|
__pycache__
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
--cc:clang
|
||||||
|
-o:"bin/nimfish"
|
||||||
|
-d:danger
|
||||||
|
--passL:"-flto"
|
||||||
|
--passC:"-Ofast -flto -march=native -mtune=native"
|
|
@ -16,9 +16,5 @@ requires "nim >= 2.0"
|
||||||
requires "jsony >= 1.1.5"
|
requires "jsony >= 1.1.5"
|
||||||
|
|
||||||
|
|
||||||
after build:
|
|
||||||
exec "nimble test"
|
|
||||||
|
|
||||||
|
|
||||||
task test, "Runs the test suite":
|
task test, "Runs the test suite":
|
||||||
exec "python tests/suite.py -d 5 --bulk"
|
exec "python tests/suite.py -d 6 --bulk"
|
||||||
|
|
|
@ -43,6 +43,7 @@ type
|
||||||
|
|
||||||
# A bunch of simple utility functions and forward declarations
|
# A bunch of simple utility functions and forward declarations
|
||||||
proc toFEN*(self: Chessboard): string
|
proc toFEN*(self: Chessboard): string
|
||||||
|
proc updateChecksAndPins*(self: Chessboard)
|
||||||
|
|
||||||
|
|
||||||
proc newChessboard: Chessboard =
|
proc newChessboard: Chessboard =
|
||||||
|
@ -168,6 +169,7 @@ proc newChessboardFromFEN*(fen: string): Chessboard =
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, "invalid FEN: too many fields in FEN string")
|
raise newException(ValueError, "invalid FEN: too many fields in FEN string")
|
||||||
inc(index)
|
inc(index)
|
||||||
|
result.updateChecksAndPins()
|
||||||
|
|
||||||
|
|
||||||
proc newDefaultChessboard*: Chessboard {.inline.} =
|
proc newDefaultChessboard*: Chessboard {.inline.} =
|
||||||
|
@ -353,13 +355,13 @@ proc updateChecksAndPins*(self: Chessboard) =
|
||||||
|
|
||||||
# Is the pinning ray obstructed by any of our friendly pieces? If so, the
|
# Is the pinning ray obstructed by any of our friendly pieces? If so, the
|
||||||
# piece is pinned
|
# piece is pinned
|
||||||
if (pinningRay and friendlyPieces).countSquares() > 0:
|
if (pinningRay and friendlyPieces).countSquares() == 1:
|
||||||
self.position.diagonalPins = self.position.diagonalPins or pinningRay
|
self.position.diagonalPins = self.position.diagonalPins or pinningRay
|
||||||
|
|
||||||
for piece in canPinOrthogonally:
|
for piece in canPinOrthogonally:
|
||||||
let pinningRay = getRayBetween(friendlyKing, piece) or piece.toBitboard()
|
let pinningRay = getRayBetween(friendlyKing, piece) or piece.toBitboard()
|
||||||
if (pinningRay and friendlyPieces).countSquares() > 0:
|
if (pinningRay and friendlyPieces).countSquares() == 1:
|
||||||
self.position.orthogonalPins = self.position.orthogonalPins or pinningRay
|
self.position.orthogonalPins = self.position.orthogonalPins or pinningRay
|
||||||
|
|
||||||
|
|
||||||
func inCheck*(self: Chessboard): bool {.inline.} =
|
func inCheck*(self: Chessboard): bool {.inline.} =
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
## Move generation logic
|
||||||
|
|
||||||
import std/strformat
|
import std/strformat
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,16 +31,13 @@ export bitboards, magics, pieces, moves, position, rays, misc, board
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc generatePawnMoves(self: Chessboard, moves: var MoveList, mask: Bitboard) =
|
proc generatePawnMoves(self: Chessboard, moves: var MoveList, destinationMask: Bitboard) =
|
||||||
let
|
let
|
||||||
sideToMove = self.position.sideToMove
|
sideToMove = self.position.sideToMove
|
||||||
pawns = self.getBitboard(Pawn, sideToMove)
|
pawns = self.getBitboard(Pawn, sideToMove)
|
||||||
occupancy = self.getOccupancy()
|
occupancy = self.getOccupancy()
|
||||||
# We can only capture enemy pieces (except the king)
|
# We can only capture enemy pieces (except the king)
|
||||||
enemyPieces = self.getOccupancyFor(sideToMove.opposite())
|
enemyPieces = self.getOccupancyFor(sideToMove.opposite())
|
||||||
# We can only capture diagonally and forward
|
|
||||||
rightMovement = pawns.forwardRightRelativeTo(sideToMove)
|
|
||||||
leftMovement = pawns.forwardLeftRelativeTo(sideToMove)
|
|
||||||
epTarget = self.position.enPassantSquare
|
epTarget = self.position.enPassantSquare
|
||||||
checkers = self.position.checkers
|
checkers = self.position.checkers
|
||||||
diagonalPins = self.position.diagonalPins
|
diagonalPins = self.position.diagonalPins
|
||||||
|
@ -61,13 +60,51 @@ proc generatePawnMoves(self: Chessboard, moves: var MoveList, mask: Bitboard) =
|
||||||
# If a pawn is pinned diagonally, it cannot move
|
# If a pawn is pinned diagonally, it cannot move
|
||||||
pushablePawns = pawns and not diagonalPins
|
pushablePawns = pawns and not diagonalPins
|
||||||
# Neither can it move if it's pinned orthogonally
|
# Neither can it move if it's pinned orthogonally
|
||||||
singlePushes = pushablePawns.forwardRelativeTo(sideToMove) and not occupancy and not orthogonalPins
|
singlePushes = (pushablePawns.forwardRelativeTo(sideToMove) and not enemyPieces) and destinationMask and not orthogonalPins
|
||||||
# Only pawns on their starting rank can double push
|
# We do this weird dance instead of using doubleForwardRelativeTo() because that doesn't have any
|
||||||
doublePushes = (pushablePawns and startingRank).doubleForwardRelativeTo(sideToMove) and not occupancy and orthogonalPins
|
# way to check if there's pieces on the two squares ahead of the pawn
|
||||||
|
var canDoublePush = pushablePawns and startingRank
|
||||||
|
canDoublePush = canDoublePush.forwardRelativeTo(sideToMove) and not occupancy and not orthogonalPins
|
||||||
|
canDoublePush = canDoublePush.forwardRelativeTo(sideToMove) and not occupancy and destinationMask
|
||||||
|
|
||||||
|
for pawn in singlePushes:
|
||||||
|
let pawnBB = pawn.toBitboard()
|
||||||
|
if promotionRank.contains(pawn):
|
||||||
|
for promotion in [PromoteToBishop, PromoteToBishop, PromoteToQueen, PromoteToRook]:
|
||||||
|
moves.add(createMove(pawnBB.backwardRelativeTo(sideToMove), pawn, promotion))
|
||||||
|
else:
|
||||||
|
moves.add(createMove(pawnBB.backwardRelativeTo(sideToMove), pawn))
|
||||||
|
|
||||||
|
for pawn in canDoublePush:
|
||||||
|
moves.add(createMove(pawn.toBitboard().doubleBackwardRelativeTo(sideToMove), pawn, DoublePush))
|
||||||
|
|
||||||
|
let canCapture = pawns and not orthogonalPins
|
||||||
|
var
|
||||||
|
captureLeft = canCapture.forwardLeftRelativeTo(sideToMove) and enemyPieces and destinationMask
|
||||||
|
captureRight = canCapture.forwardRightRelativeTo(sideToMove) and enemyPieces and destinationMask
|
||||||
|
# If a capturing pawn is pinned diagonally, it is allowed to capture only
|
||||||
|
# in the direction of the pin
|
||||||
|
if (diagonalPins and captureLeft) != 0:
|
||||||
|
captureLeft = captureLeft and diagonalPins
|
||||||
|
if (diagonalPins and captureRight) != 0:
|
||||||
|
captureRight = captureRight and diagonalPins
|
||||||
|
for pawn in captureLeft:
|
||||||
|
let pawnBB = pawn.toBitboard()
|
||||||
|
if promotionRank.contains(pawn):
|
||||||
|
for promotion in [PromoteToBishop, PromoteToBishop, PromoteToQueen, PromoteToRook]:
|
||||||
|
moves.add(createMove(pawnBB.backwardRightRelativeTo(sideToMove), pawn, Capture, promotion))
|
||||||
|
else:
|
||||||
|
moves.add(createMove(pawnBB.backwardRightRelativeTo(sideToMove), pawn, Capture))
|
||||||
|
for pawn in captureRight:
|
||||||
|
let pawnBB = pawn.toBitboard()
|
||||||
|
if promotionRank.contains(pawn):
|
||||||
|
for promotion in [PromoteToBishop, PromoteToBishop, PromoteToQueen, PromoteToRook]:
|
||||||
|
moves.add(createMove(pawnBB.backwardLeftRelativeTo(sideToMove), pawn, Capture, promotion))
|
||||||
|
else:
|
||||||
|
moves.add(createMove(pawnBB.backwardLeftRelativeTo(sideToMove), pawn, Capture))
|
||||||
|
|
||||||
|
|
||||||
proc generateRookMoves(self: Chessboard, moves: var MoveList, mask: Bitboard) =
|
proc generateRookMoves(self: Chessboard, moves: var MoveList, destinationMask: Bitboard) =
|
||||||
## Helper of generateSlidingMoves to generate rook moves
|
|
||||||
let
|
let
|
||||||
sideToMove = self.position.sideToMove
|
sideToMove = self.position.sideToMove
|
||||||
occupancy = self.getOccupancy()
|
occupancy = self.getOccupancy()
|
||||||
|
@ -82,22 +119,21 @@ proc generateRookMoves(self: Chessboard, moves: var MoveList, mask: Bitboard) =
|
||||||
let
|
let
|
||||||
blockers = occupancy and Rook.getRelevantBlockers(square)
|
blockers = occupancy and Rook.getRelevantBlockers(square)
|
||||||
moveset = getRookMoves(square, blockers)
|
moveset = getRookMoves(square, blockers)
|
||||||
for target in moveset and not occupancy and pinMask and mask:
|
for target in moveset and pinMask and destinationMask and not enemyPieces:
|
||||||
moves.add(createMove(square, target))
|
moves.add(createMove(square, target))
|
||||||
for target in moveset and enemyPieces and pinMask and mask:
|
for target in moveset and enemyPieces and pinMask and destinationMask:
|
||||||
moves.add(createMove(square, target, Capture))
|
moves.add(createMove(square, target, Capture))
|
||||||
for square in unpinnedRooks:
|
for square in unpinnedRooks:
|
||||||
let
|
let
|
||||||
blockers = occupancy and Rook.getRelevantBlockers(square)
|
blockers = occupancy and Rook.getRelevantBlockers(square)
|
||||||
moveset = getRookMoves(square, blockers)
|
moveset = getRookMoves(square, blockers)
|
||||||
for target in moveset and not occupancy and mask:
|
for target in moveset and destinationMask and not enemyPieces:
|
||||||
moves.add(createMove(square, target))
|
moves.add(createMove(square, target))
|
||||||
for target in moveset and enemyPieces and mask:
|
for target in moveset and enemyPieces and destinationMask:
|
||||||
moves.add(createMove(square, target, Capture))
|
moves.add(createMove(square, target, Capture))
|
||||||
|
|
||||||
|
|
||||||
proc generateBishopMoves(self: Chessboard, moves: var MoveList, mask: Bitboard) =
|
proc generateBishopMoves(self: Chessboard, moves: var MoveList, destinationMask: Bitboard) =
|
||||||
## Helper of generateSlidingMoves to generate bishop moves
|
|
||||||
let
|
let
|
||||||
sideToMove = self.position.sideToMove
|
sideToMove = self.position.sideToMove
|
||||||
occupancy = self.getOccupancy()
|
occupancy = self.getOccupancy()
|
||||||
|
@ -112,28 +148,27 @@ proc generateBishopMoves(self: Chessboard, moves: var MoveList, mask: Bitboard)
|
||||||
let
|
let
|
||||||
blockers = occupancy and Bishop.getRelevantBlockers(square)
|
blockers = occupancy and Bishop.getRelevantBlockers(square)
|
||||||
moveset = getBishopMoves(square, blockers)
|
moveset = getBishopMoves(square, blockers)
|
||||||
for target in moveset and pinMask and mask:
|
for target in moveset and pinMask and destinationMask and not enemyPieces:
|
||||||
moves.add(createMove(square, target))
|
moves.add(createMove(square, target))
|
||||||
for target in moveset and enemyPieces and pinMask and mask:
|
for target in moveset and enemyPieces and destinationMask:
|
||||||
moves.add(createMove(square, target, Capture))
|
moves.add(createMove(square, target, Capture))
|
||||||
for square in unpinnedBishops:
|
for square in unpinnedBishops:
|
||||||
let
|
let
|
||||||
blockers = occupancy and Bishop.getRelevantBlockers(square)
|
blockers = occupancy and Bishop.getRelevantBlockers(square)
|
||||||
moveset = getBishopMoves(square, blockers)
|
moveset = getBishopMoves(square, blockers)
|
||||||
for target in moveset and mask:
|
for target in moveset and destinationMask and not enemyPieces:
|
||||||
moves.add(createMove(square, target))
|
moves.add(createMove(square, target))
|
||||||
for target in moveset and enemyPieces and mask:
|
for target in moveset and enemyPieces and destinationMask:
|
||||||
moves.add(createMove(square, target, Capture))
|
moves.add(createMove(square, target, Capture))
|
||||||
|
|
||||||
|
|
||||||
proc generateKingMoves(self: Chessboard, moves: var MoveList) =
|
proc generateKingMoves(self: Chessboard, moves: var MoveList) =
|
||||||
## Generates all legal king moves for the side to move
|
|
||||||
let
|
let
|
||||||
sideToMove = self.position.sideToMove
|
sideToMove = self.position.sideToMove
|
||||||
king = self.getBitboard(King, sideToMove)
|
king = self.getBitboard(King, sideToMove)
|
||||||
occupancy = self.getOccupancy()
|
occupancy = self.getOccupancy()
|
||||||
nonSideToMove = sideToMove.opposite()
|
nonSideToMove = sideToMove.opposite()
|
||||||
enemyPieces = self.getOccupancyFor(nonSideToMove) and not self.getBitboard(King, nonSideToMove)
|
enemyPieces = self.getOccupancyFor(nonSideToMove)
|
||||||
bitboard = getKingAttacks(king.toSquare())
|
bitboard = getKingAttacks(king.toSquare())
|
||||||
noKingOccupancy = occupancy and not king
|
noKingOccupancy = occupancy and not king
|
||||||
for square in bitboard and not occupancy:
|
for square in bitboard and not occupancy:
|
||||||
|
@ -144,23 +179,29 @@ proc generateKingMoves(self: Chessboard, moves: var MoveList) =
|
||||||
moves.add(createMove(king, square, Capture))
|
moves.add(createMove(king, square, Capture))
|
||||||
|
|
||||||
|
|
||||||
proc generateKnightMoves(self: Chessboard, moves: var MoveList, mask: Bitboard) =
|
proc generateKnightMoves(self: Chessboard, moves: var MoveList, destinationMask: Bitboard) =
|
||||||
## Generates all the legal knight moves for the side to move
|
|
||||||
let
|
let
|
||||||
sideToMove = self.position.sideToMove
|
sideToMove = self.position.sideToMove
|
||||||
knights = self.getBitboard(Knight, sideToMove)
|
knights = self.getBitboard(Knight, sideToMove)
|
||||||
nonSideToMove = sideToMove.opposite()
|
nonSideToMove = sideToMove.opposite()
|
||||||
pinned = self.position.diagonalPins or self.position.orthogonalPins
|
pinned = self.position.diagonalPins or self.position.orthogonalPins
|
||||||
unpinnedKnights = knights and not pinned
|
unpinnedKnights = knights and not pinned
|
||||||
enemyPieces = self.getOccupancyFor(nonSideToMove) and not self.getBitboard(King, nonSideToMove)
|
enemyPieces = self.getOccupancyFor(nonSideToMove)
|
||||||
for square in unpinnedKnights:
|
for square in unpinnedKnights:
|
||||||
let bitboard = getKnightAttacks(square)
|
let bitboard = getKnightAttacks(square)
|
||||||
for target in bitboard and mask:
|
for target in bitboard and destinationMask and not enemyPieces:
|
||||||
moves.add(createMove(square, target))
|
moves.add(createMove(square, target))
|
||||||
for target in bitboard and enemyPieces:
|
for target in bitboard and enemyPieces:
|
||||||
moves.add(createMove(square, target, Capture))
|
moves.add(createMove(square, target, Capture))
|
||||||
|
|
||||||
|
|
||||||
|
proc generateCastling(self: Chessboard, moves: var MoveList) =
|
||||||
|
let
|
||||||
|
sideToMove = self.position.sideToMove
|
||||||
|
rooks = self.getBitboard(Rook, sideToMove)
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
|
||||||
proc generateMoves*(self: Chessboard, moves: var MoveList) =
|
proc generateMoves*(self: Chessboard, moves: var MoveList) =
|
||||||
## Generates the list of all possible legal moves
|
## Generates the list of all possible legal moves
|
||||||
## in the current position
|
## in the current position
|
||||||
|
@ -176,18 +217,17 @@ proc generateMoves*(self: Chessboard, moves: var MoveList) =
|
||||||
# moves
|
# moves
|
||||||
return
|
return
|
||||||
if not self.inCheck():
|
if not self.inCheck():
|
||||||
# TODO: Castling
|
self.generateCastling(moves)
|
||||||
discard
|
|
||||||
|
|
||||||
# We pass a mask to our move generators to remove stuff
|
# We pass a mask to our move generators to remove stuff
|
||||||
# like our friendly pieces from the set of possible
|
# like our friendly pieces from the set of possible
|
||||||
# target squares, as well as to ensure checks are not
|
# target squares, as well as to ensure checks are not
|
||||||
# ignored
|
# ignored
|
||||||
|
|
||||||
var mask: Bitboard
|
var destinationMask: Bitboard
|
||||||
if not self.inCheck():
|
if not self.inCheck():
|
||||||
# Not in check: cannot move over friendly pieces
|
# Not in check: cannot move over friendly pieces
|
||||||
mask = not self.getOccupancyFor(sideToMove)
|
destinationMask = not self.getOccupancyFor(sideToMove)
|
||||||
else:
|
else:
|
||||||
# We *are* in check (from a single piece, because the two checks
|
# We *are* in check (from a single piece, because the two checks
|
||||||
# case was handled above already). If the piece is a slider, we'll
|
# case was handled above already). If the piece is a slider, we'll
|
||||||
|
@ -197,12 +237,11 @@ proc generateMoves*(self: Chessboard, moves: var MoveList) =
|
||||||
# the ray will be empty so the only legal move will be to capture
|
# the ray will be empty so the only legal move will be to capture
|
||||||
# the checking piece
|
# the checking piece
|
||||||
let checker = self.position.checkers.lowestSquare()
|
let checker = self.position.checkers.lowestSquare()
|
||||||
mask = getRayBetween(checker, self.getBitboard(King, sideToMove).toSquare()) or checker.toBitboard()
|
destinationMask = getRayBetween(checker, self.getBitboard(King, sideToMove).toSquare()) or checker.toBitboard()
|
||||||
|
self.generatePawnMoves(moves, destinationMask)
|
||||||
self.generatePawnMoves(moves, mask)
|
self.generateKnightMoves(moves, destinationMask)
|
||||||
self.generateKnightMoves(moves, mask)
|
self.generateRookMoves(moves, destinationMask)
|
||||||
self.generateRookMoves(moves, mask)
|
self.generateBishopMoves(moves, destinationMask)
|
||||||
self.generateBishopMoves(moves, mask)
|
|
||||||
# Queens are just handled rooks + bishops
|
# Queens are just handled rooks + bishops
|
||||||
|
|
||||||
|
|
||||||
|
@ -290,7 +329,8 @@ proc doMove*(self: Chessboard, move: Move) =
|
||||||
sideToMove: self.position.sideToMove.opposite(),
|
sideToMove: self.position.sideToMove.opposite(),
|
||||||
castlingRights: castlingRights,
|
castlingRights: castlingRights,
|
||||||
enPassantSquare: enPassantTarget,
|
enPassantSquare: enPassantTarget,
|
||||||
pieces: self.position.pieces
|
pieces: self.position.pieces,
|
||||||
|
castlingAvailability: self.position.castlingAvailability
|
||||||
)
|
)
|
||||||
# Update position metadata
|
# Update position metadata
|
||||||
|
|
||||||
|
@ -336,7 +376,6 @@ proc makeMove*(self: Chessboard, move: Move): Move {.discardable.} =
|
||||||
## Makes a move on the board
|
## Makes a move on the board
|
||||||
result = move
|
result = move
|
||||||
# Updates checks and pins for the side to move
|
# Updates checks and pins for the side to move
|
||||||
self.updateChecksAndPins()
|
|
||||||
if not self.isLegal(move):
|
if not self.isLegal(move):
|
||||||
return nullMove()
|
return nullMove()
|
||||||
self.doMove(move)
|
self.doMove(move)
|
||||||
|
|
|
@ -22,12 +22,10 @@ type
|
||||||
Position* = object
|
Position* = object
|
||||||
## A chess position
|
## A chess position
|
||||||
|
|
||||||
# Castling metadata. Updated on every move
|
|
||||||
castlingRights*: array[64, uint8]
|
|
||||||
# Castling availability. This just keeps track
|
# Castling availability. This just keeps track
|
||||||
# of whether the king or the rooks on either side
|
# of whether the king or the rooks on either side
|
||||||
# moved and is only useful for printing the correct
|
# moved, the actual checks for the legality of castling
|
||||||
# FEN for a given position
|
# are done elsewhere
|
||||||
castlingAvailability*: tuple[white, black: tuple[queen, king: bool]]
|
castlingAvailability*: tuple[white, black: tuple[queen, king: bool]]
|
||||||
# Number of half-moves that were performed
|
# Number of half-moves that were performed
|
||||||
# to reach this position starting from the
|
# to reach this position starting from the
|
||||||
|
|
|
@ -170,7 +170,7 @@ proc handleGoCommand(board: Chessboard, command: seq[string]) =
|
||||||
else:
|
else:
|
||||||
let t = cpuTime()
|
let t = cpuTime()
|
||||||
let data = board.perft(ply, divide=true, verbose=verbose)
|
let data = board.perft(ply, divide=true, verbose=verbose)
|
||||||
let tot = cpuTime()
|
let tot = cpuTime() - t
|
||||||
echo &"\nNodes searched (bulk-counting: off): {data.nodes}"
|
echo &"\nNodes searched (bulk-counting: off): {data.nodes}"
|
||||||
echo &" - Captures: {data.captures}"
|
echo &" - Captures: {data.captures}"
|
||||||
echo &" - Checks: {data.checks}"
|
echo &" - Checks: {data.checks}"
|
||||||
|
@ -179,7 +179,7 @@ proc handleGoCommand(board: Chessboard, command: seq[string]) =
|
||||||
echo &" - Castles: {data.castles}"
|
echo &" - Castles: {data.castles}"
|
||||||
echo &" - Promotions: {data.promotions}"
|
echo &" - Promotions: {data.promotions}"
|
||||||
echo ""
|
echo ""
|
||||||
echo &"Time taken: {round(t, 3)} seconds\nNodes per second: {round(data.nodes / tot).uint64}"
|
echo &"Time taken: {round(tot, 3)} seconds\nNodes per second: {round(data.nodes / tot).uint64}"
|
||||||
except ValueError:
|
except ValueError:
|
||||||
echo "Error: go: perft: invalid depth"
|
echo "Error: go: perft: invalid depth"
|
||||||
else:
|
else:
|
||||||
|
@ -217,7 +217,7 @@ proc handleMoveCommand(board: Chessboard, command: seq[string]): Move {.discarda
|
||||||
if board.getPiece(targetSquare).kind != Empty:
|
if board.getPiece(targetSquare).kind != Empty:
|
||||||
flags.add(Capture)
|
flags.add(Capture)
|
||||||
|
|
||||||
elif board.getPiece(targetSquare).kind == Pawn and abs(rankFromSquare(startSquare) - rankFromSquare(targetSquare)) == 2:
|
if board.getPiece(startSquare).kind == Pawn and abs(rankFromSquare(startSquare) - rankFromSquare(targetSquare)) == 2:
|
||||||
flags.add(DoublePush)
|
flags.add(DoublePush)
|
||||||
|
|
||||||
if len(moveString) == 5:
|
if len(moveString) == 5:
|
||||||
|
|
Loading…
Reference in New Issue