Fix bugs in move handling
This commit is contained in:
parent
fcbe15f275
commit
0496047164
|
@ -35,7 +35,7 @@ type
|
||||||
## A chess position
|
## A chess position
|
||||||
|
|
||||||
# Castling metadata. Updated on every move
|
# Castling metadata. Updated on every move
|
||||||
castling: array[64, uint8]
|
castlingRights: array[64, uint8]
|
||||||
# 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
|
||||||
# root of the tree
|
# root of the tree
|
||||||
|
@ -81,8 +81,8 @@ proc pretty*(self: ChessBoard): string
|
||||||
proc spawnPiece(self: ChessBoard, square: Square, piece: Piece)
|
proc spawnPiece(self: ChessBoard, square: Square, piece: Piece)
|
||||||
proc toFEN*(self: ChessBoard): string
|
proc toFEN*(self: ChessBoard): string
|
||||||
proc unmakeMove*(self: ChessBoard)
|
proc unmakeMove*(self: ChessBoard)
|
||||||
proc movePiece(self: ChessBoard, move: Move, attack: bool = true)
|
proc movePiece(self: ChessBoard, move: Move)
|
||||||
proc removePiece(self: ChessBoard, square: Square, attack: bool = true)
|
proc removePiece(self: ChessBoard, square: Square)
|
||||||
|
|
||||||
|
|
||||||
proc extend[T](self: var seq[T], other: openarray[T]) {.inline.} =
|
proc extend[T](self: var seq[T], other: openarray[T]) {.inline.} =
|
||||||
|
@ -163,6 +163,7 @@ proc newChessboard: ChessBoard =
|
||||||
new(result)
|
new(result)
|
||||||
for i in 0..63:
|
for i in 0..63:
|
||||||
result.grid[i] = nullPiece()
|
result.grid[i] = nullPiece()
|
||||||
|
result.currPos = -1
|
||||||
result.position = Position(enPassantSquare: nullSquare(), turn: White)
|
result.position = Position(enPassantSquare: nullSquare(), turn: White)
|
||||||
|
|
||||||
# Indexing operations
|
# Indexing operations
|
||||||
|
@ -326,18 +327,18 @@ proc newChessboardFromFEN*(fen: string): ChessBoard =
|
||||||
discard
|
discard
|
||||||
of 'K':
|
of 'K':
|
||||||
discard
|
discard
|
||||||
# result.position.castlingAvailable.white.king = true
|
# result.position.castlingRightsAvailable.white.king = true
|
||||||
of 'Q':
|
of 'Q':
|
||||||
discard
|
discard
|
||||||
# result.position.castlingAvailable.white.queen = true
|
# result.position.castlingRightsAvailable.white.queen = true
|
||||||
of 'k':
|
of 'k':
|
||||||
discard
|
discard
|
||||||
# result.position.castlingAvailable.black.king = true
|
# result.position.castlingRightsAvailable.black.king = true
|
||||||
of 'q':
|
of 'q':
|
||||||
discard
|
discard
|
||||||
# result.position.castlingAvailable.black.queen = true
|
# result.position.castlingRightsAvailable.black.queen = true
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, &"invalid FEN: unknown symbol '{c}' found in castling availability section")
|
raise newException(ValueError, &"invalid FEN: unknown symbol '{c}' found in castlingRights availability section")
|
||||||
of 3:
|
of 3:
|
||||||
# En passant target square
|
# En passant target square
|
||||||
case c:
|
case c:
|
||||||
|
@ -472,7 +473,7 @@ func isCastling*(move: Move): bool {.inline.} =
|
||||||
|
|
||||||
|
|
||||||
func getCastlingType*(move: Move): MoveFlag {.inline.} =
|
func getCastlingType*(move: Move): MoveFlag {.inline.} =
|
||||||
## Returns the castling type of the given move.
|
## Returns the castlingRights type of the given move.
|
||||||
## The return value of this function is only valid
|
## The return value of this function is only valid
|
||||||
## if isCastling() returns true
|
## if isCastling() returns true
|
||||||
for flag in [CastleLong, CastleShort]:
|
for flag in [CastleLong, CastleShort]:
|
||||||
|
@ -644,7 +645,7 @@ proc generatePawnMovements(self: ChessBoard, moves: var MoveList) =
|
||||||
for square in pawns.forwardRelativeTo(sideToMove) and allowedSquares:
|
for square in pawns.forwardRelativeTo(sideToMove) and allowedSquares:
|
||||||
moves.add(createMove(square.toBitboard().backwardRelativeTo(sideToMove), square))
|
moves.add(createMove(square.toBitboard().backwardRelativeTo(sideToMove), square))
|
||||||
# Double push
|
# Double push
|
||||||
let rank = sideToMove.getFirstRank() # Only pawns on their starting rank can double push
|
let rank = if sideToMove == White: getRankMask(6) else: getRankMask(1) # Only pawns on their starting rank can double push
|
||||||
for square in (pawns and rank).doubleForwardRelativeTo(sideToMove) and allowedSquares:
|
for square in (pawns and rank).doubleForwardRelativeTo(sideToMove) and allowedSquares:
|
||||||
moves.add(createMove(square.toBitboard().doubleBackwardRelativeTo(sideToMove), square, DoublePush))
|
moves.add(createMove(square.toBitboard().doubleBackwardRelativeTo(sideToMove), square, DoublePush))
|
||||||
|
|
||||||
|
@ -964,8 +965,8 @@ proc removePieceFromBitboard(self: ChessBoard, square: Square) =
|
||||||
self.position.pieces.white.queens.uint64.clearBit(square.int8)
|
self.position.pieces.white.queens.uint64.clearBit(square.int8)
|
||||||
of King:
|
of King:
|
||||||
self.position.pieces.white.king.uint64.clearBit(square.int8)
|
self.position.pieces.white.king.uint64.clearBit(square.int8)
|
||||||
else:
|
of Empty:
|
||||||
discard
|
doAssert false, &"cannot remove empty white piece from {square}"
|
||||||
of Black:
|
of Black:
|
||||||
case piece.kind:
|
case piece.kind:
|
||||||
of Pawn:
|
of Pawn:
|
||||||
|
@ -979,11 +980,11 @@ proc removePieceFromBitboard(self: ChessBoard, square: Square) =
|
||||||
of Queen:
|
of Queen:
|
||||||
self.position.pieces.black.queens.uint64.clearBit(square.int8)
|
self.position.pieces.black.queens.uint64.clearBit(square.int8)
|
||||||
of King:
|
of King:
|
||||||
self.position.pieces.black.king.uint64.clearBit(square.int8)
|
self.position.pieces.black.king.uint64.clearBit(square.int8)
|
||||||
else:
|
of Empty:
|
||||||
discard
|
doAssert false, &"cannot remove empty black piece from {square}"
|
||||||
else:
|
else:
|
||||||
discard
|
doAssert false, &"cannot remove empty piece from colorless square {square}"
|
||||||
|
|
||||||
|
|
||||||
proc addPieceToBitboard(self: ChessBoard, square: Square, piece: Piece) =
|
proc addPieceToBitboard(self: ChessBoard, square: Square, piece: Piece) =
|
||||||
|
@ -1026,73 +1027,16 @@ proc addPieceToBitboard(self: ChessBoard, square: Square, piece: Piece) =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
||||||
proc removePiece(self: ChessBoard, square: Square, attack: bool = true) =
|
proc removePiece(self: ChessBoard, square: Square) =
|
||||||
## Removes a piece from the board, updating necessary
|
## Removes a piece from the board, updating necessary
|
||||||
## metadata
|
## metadata
|
||||||
var piece = self.grid[square]
|
var piece = self.grid[square]
|
||||||
self.grid[square] = nullPiece()
|
doAssert piece.kind != Empty and piece.color != None
|
||||||
self.removePieceFromBitboard(square)
|
self.removePieceFromBitboard(square)
|
||||||
#[if attack:
|
self.grid[square] = nullPiece()
|
||||||
self.updateAttackedSquares()]#
|
|
||||||
|
|
||||||
|
|
||||||
proc updateMovepieces(self: ChessBoard, move: Move) =
|
proc movePiece(self: ChessBoard, move: Move) =
|
||||||
## Updates our bitboard representation after a move: note that this
|
|
||||||
## does *not* handle captures, en passant, promotions etc. as those
|
|
||||||
## are already called by helpers such as removePiece() and spawnPiece()
|
|
||||||
var bitboard: uint64
|
|
||||||
let piece = self.grid[move.startSquare]
|
|
||||||
# TODO: Should we use our helpers or is it faster to branch only once?
|
|
||||||
case piece.color:
|
|
||||||
of White:
|
|
||||||
case piece.kind:
|
|
||||||
of Pawn:
|
|
||||||
self.position.pieces.white.pawns.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.white.pawns.uint64.clearBit(move.startSquare.int8)
|
|
||||||
of Bishop:
|
|
||||||
self.position.pieces.white.bishops.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.white.bishops.uint64.clearBit(move.startSquare.int8)
|
|
||||||
of Knight:
|
|
||||||
self.position.pieces.white.knights.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.white.knights.uint64.clearBit(move.startSquare.int8)
|
|
||||||
of Rook:
|
|
||||||
self.position.pieces.white.rooks.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.white.rooks.uint64.clearBit(move.startSquare.int8)
|
|
||||||
of Queen:
|
|
||||||
self.position.pieces.white.queens.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.white.queens.uint64.clearBit(move.startSquare.int8)
|
|
||||||
of King:
|
|
||||||
self.position.pieces.white.king.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.white.king.uint64.clearBit(move.startSquare.int8)
|
|
||||||
else:
|
|
||||||
discard
|
|
||||||
of Black:
|
|
||||||
case piece.kind:
|
|
||||||
of Pawn:
|
|
||||||
self.position.pieces.black.pawns.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.black.pawns.uint64.clearBit(move.startSquare.int8)
|
|
||||||
of Bishop:
|
|
||||||
self.position.pieces.black.bishops.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.black.bishops.uint64.clearBit(move.startSquare.int8)
|
|
||||||
of Knight:
|
|
||||||
self.position.pieces.black.knights.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.black.knights.uint64.clearBit(move.startSquare.int8)
|
|
||||||
of Rook:
|
|
||||||
self.position.pieces.black.rooks.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.black.rooks.uint64.clearBit(move.startSquare.int8)
|
|
||||||
of Queen:
|
|
||||||
self.position.pieces.black.queens.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.black.queens.uint64.clearBit(move.startSquare.int8)
|
|
||||||
of King:
|
|
||||||
self.position.pieces.black.king.uint64.setBit(move.targetSquare.int8)
|
|
||||||
self.position.pieces.black.king.uint64.clearBit(move.startSquare.int8)
|
|
||||||
else:
|
|
||||||
discard
|
|
||||||
else:
|
|
||||||
discard
|
|
||||||
|
|
||||||
|
|
||||||
proc movePiece(self: ChessBoard, move: Move, attack: bool = true) =
|
|
||||||
## Internal helper to move a piece. If attack
|
## Internal helper to move a piece. If attack
|
||||||
## is set to false, then this function does
|
## is set to false, then this function does
|
||||||
## not update attacked squares metadata, just
|
## not update attacked squares metadata, just
|
||||||
|
@ -1100,20 +1044,15 @@ proc movePiece(self: ChessBoard, move: Move, attack: bool = true) =
|
||||||
let piece = self.grid[move.startSquare]
|
let piece = self.grid[move.startSquare]
|
||||||
let targetSquare = self.getPiece(move.targetSquare)
|
let targetSquare = self.getPiece(move.targetSquare)
|
||||||
if targetSquare.color != None:
|
if targetSquare.color != None:
|
||||||
raise newException(AccessViolationDefect, &"attempted to overwrite a piece! {move}")
|
raise newException(AccessViolationDefect, &"{piece} at {move.startSquare} attempted to overwrite {targetSquare} at {move.targetSquare}")
|
||||||
# Update positional metadata
|
# Update positional metadata
|
||||||
self.updateMovePieces(move)
|
self.removePiece(move.startSquare)
|
||||||
# Empty out the starting square
|
self.spawnPiece(move.targetSquare, piece)
|
||||||
self.grid[move.startSquare] = nullPiece()
|
|
||||||
# Actually move the piece on the board
|
|
||||||
self.grid[move.targetSquare] = piece
|
|
||||||
#[if attack:
|
|
||||||
self.updateAttackedSquares()]#
|
|
||||||
|
|
||||||
|
|
||||||
proc movePiece(self: ChessBoard, startSquare, targetSquare: Square, attack: bool = true) =
|
proc movePiece(self: ChessBoard, startSquare, targetSquare: Square) =
|
||||||
## Like the other movePiece(), but with two squares
|
## Like the other movePiece(), but with two squares
|
||||||
self.movePiece(Move(startSquare: startSquare, targetSquare: targetSquare), attack)
|
self.movePiece(Move(startSquare: startSquare, targetSquare: targetSquare))
|
||||||
|
|
||||||
|
|
||||||
proc doMove(self: ChessBoard, move: Move) =
|
proc doMove(self: ChessBoard, move: Move) =
|
||||||
|
@ -1124,14 +1063,16 @@ proc doMove(self: ChessBoard, move: Move) =
|
||||||
|
|
||||||
# Record final position for future reference
|
# Record final position for future reference
|
||||||
self.positions.add(self.position)
|
self.positions.add(self.position)
|
||||||
|
inc(self.currPos)
|
||||||
|
|
||||||
# Final checks
|
# Final checks
|
||||||
let piece = self.grid[move.startSquare]
|
let piece = self.grid[move.startSquare]
|
||||||
|
doAssert piece.kind != Empty and piece.color != None
|
||||||
|
|
||||||
var
|
var
|
||||||
halfMoveClock = self.position.halfMoveClock
|
halfMoveClock = self.position.halfMoveClock
|
||||||
fullMoveCount = self.position.fullMoveCount
|
fullMoveCount = self.position.fullMoveCount
|
||||||
castling = self.position.castling
|
castlingRights = self.position.castlingRights
|
||||||
enPassantTarget = nullSquare()
|
enPassantTarget = nullSquare()
|
||||||
# Needed to detect draw by the 50 move rule
|
# Needed to detect draw by the 50 move rule
|
||||||
if piece.kind == Pawn or move.isCapture() or move.isEnPassant():
|
if piece.kind == Pawn or move.isCapture() or move.isEnPassant():
|
||||||
|
@ -1144,69 +1085,26 @@ proc doMove(self: ChessBoard, move: Move) =
|
||||||
if move.isDoublePush():
|
if move.isDoublePush():
|
||||||
enPassantTarget = move.targetSquare.toBitboard().backwardRelativeTo(piece.color).toSquare()
|
enPassantTarget = move.targetSquare.toBitboard().backwardRelativeTo(piece.color).toSquare()
|
||||||
|
|
||||||
# Castling check: have the rooks moved?
|
|
||||||
if piece.kind == Rook:
|
|
||||||
discard
|
|
||||||
# case piece.color:
|
|
||||||
# of White:
|
|
||||||
# if rowFromSquare(move.startSquare) == piece.getStartRank():
|
|
||||||
# if columnFromSquare(move.startSquare) == 0:
|
|
||||||
# # Queen side
|
|
||||||
# castlingAvailable.white.queen = false
|
|
||||||
# elif columnfromSquare(move.startSquare) == 7:
|
|
||||||
# # King side
|
|
||||||
# castlingAvailable.white.king = false
|
|
||||||
# of Black:
|
|
||||||
# if rowFromSquare(move.startSquare) == piece.getStartRank():
|
|
||||||
# if columnFromSquare(move.startSquare) == 0:
|
|
||||||
# # Queen side
|
|
||||||
# castlingAvailable.black.queen = false
|
|
||||||
# elif columnFromSquare(move.startSquare) == 7:
|
|
||||||
# # King side
|
|
||||||
# castlingAvailable.black.king = false
|
|
||||||
# else:
|
|
||||||
# discard
|
|
||||||
# Has a rook been captured?
|
|
||||||
|
|
||||||
|
|
||||||
# Create new position
|
# Create new position
|
||||||
self.position = Position(plyFromRoot: self.position.plyFromRoot + 1,
|
self.position = Position(plyFromRoot: self.position.plyFromRoot + 1,
|
||||||
halfMoveClock: halfMoveClock,
|
halfMoveClock: halfMoveClock,
|
||||||
fullMoveCount: fullMoveCount,
|
fullMoveCount: fullMoveCount,
|
||||||
turn: self.getSideToMove().opposite,
|
turn: self.getSideToMove().opposite,
|
||||||
castling: castling,
|
castlingRights: castlingRights,
|
||||||
enPassantSquare: enPassantTarget,
|
enPassantSquare: enPassantTarget,
|
||||||
pieces: self.position.pieces
|
pieces: self.position.pieces
|
||||||
)
|
)
|
||||||
# Update position metadata
|
# Update position metadata
|
||||||
|
|
||||||
if move.isCastling():
|
|
||||||
# Move the rook onto the
|
|
||||||
# correct file when castling
|
|
||||||
var
|
|
||||||
square: Square
|
|
||||||
target: Square
|
|
||||||
flag: MoveFlag
|
|
||||||
if move.getCastlingType() == CastleShort:
|
|
||||||
square = piece.color.kingSideRook()
|
|
||||||
target = shortCastleRook(piece.color)
|
|
||||||
flag = CastleShort
|
|
||||||
else:
|
|
||||||
square = piece.color.queenSideRook()
|
|
||||||
target = longCastleRook(piece.color)
|
|
||||||
flag = CastleLong
|
|
||||||
let rook = self.grid[square]
|
|
||||||
self.movePiece(createMove(square, target, flag), attack=false)
|
|
||||||
|
|
||||||
if move.isEnPassant():
|
if move.isEnPassant():
|
||||||
# Make the en passant pawn disappear
|
# Make the en passant pawn disappear
|
||||||
self.removePiece(move.targetSquare.toBitboard().backwardRelativeTo(piece.color).toSquare(), attack=false)
|
self.removePiece(move.targetSquare.toBitboard().backwardRelativeTo(piece.color).toSquare())
|
||||||
|
|
||||||
if move.isCapture():
|
if move.isCapture():
|
||||||
# Get rid of captured pieces
|
# Get rid of captured pieces
|
||||||
self.removePiece(move.targetSquare, attack=false)
|
self.removePiece(move.targetSquare)
|
||||||
# Move the piece to its target square and update attack metadata
|
# Move the piece to its target square
|
||||||
self.movePiece(move, attack=false)
|
self.movePiece(move)
|
||||||
if move.isPromotion():
|
if move.isPromotion():
|
||||||
# Move is a pawn promotion: get rid of the pawn
|
# Move is a pawn promotion: get rid of the pawn
|
||||||
# and spawn a new piece
|
# and spawn a new piece
|
||||||
|
@ -1223,7 +1121,7 @@ proc doMove(self: ChessBoard, move: Move) =
|
||||||
else:
|
else:
|
||||||
# Unreachable
|
# Unreachable
|
||||||
discard
|
discard
|
||||||
#self.updateAttackedSquares()
|
self.updateBoard()
|
||||||
|
|
||||||
|
|
||||||
proc spawnPiece(self: ChessBoard, square: Square, piece: Piece) =
|
proc spawnPiece(self: ChessBoard, square: Square, piece: Piece) =
|
||||||
|
@ -1261,26 +1159,18 @@ proc updateBoard*(self: ChessBoard) =
|
||||||
self.grid[sq] = Piece(color: White, kind: Queen)
|
self.grid[sq] = Piece(color: White, kind: Queen)
|
||||||
for sq in self.position.pieces.black.queens:
|
for sq in self.position.pieces.black.queens:
|
||||||
self.grid[sq] = Piece(color: Black, kind: Queen)
|
self.grid[sq] = Piece(color: Black, kind: Queen)
|
||||||
self.grid[self.position.pieces.white.king.toSquare()] = Piece(color: White, kind: King)
|
for sq in self.position.pieces.white.king:
|
||||||
self.grid[self.position.pieces.black.king.toSquare()] = Piece(color: Black, kind: King)
|
self.grid[sq] = Piece(color: White, kind: King)
|
||||||
|
for sq in self.position.pieces.black.king:
|
||||||
|
self.grid[sq] = Piece(color: Black, kind: King)
|
||||||
|
|
||||||
|
|
||||||
proc unmakeMove*(self: ChessBoard) =
|
proc unmakeMove*(self: ChessBoard) =
|
||||||
## Reverts to the previous board position,
|
## Reverts to the previous board position,
|
||||||
## if one exists
|
## if one exists
|
||||||
if self.currPos > 0:
|
if self.currPos >= 0:
|
||||||
|
self.position = self.positions[self.currPos]
|
||||||
dec(self.currPos)
|
dec(self.currPos)
|
||||||
self.position = self.positions[self.currPos]
|
|
||||||
self.updateBoard()
|
|
||||||
|
|
||||||
|
|
||||||
proc redoMove*(self: ChessBoard) =
|
|
||||||
## Reverts to the next board position, if one
|
|
||||||
## exists. Only makes sense after a call to
|
|
||||||
## unmakeMove
|
|
||||||
if self.positions.high() > self.currPos:
|
|
||||||
inc(self.currPos)
|
|
||||||
self.position = self.positions[self.currPos]
|
|
||||||
self.updateBoard()
|
self.updateBoard()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1386,7 +1276,6 @@ proc pretty*(self: ChessBoard): string =
|
||||||
result &= "\x1b[0m"
|
result &= "\x1b[0m"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc toFEN*(self: ChessBoard): string =
|
proc toFEN*(self: ChessBoard): string =
|
||||||
## Returns a FEN string of the current
|
## Returns a FEN string of the current
|
||||||
## position in the chessboard
|
## position in the chessboard
|
||||||
|
@ -1413,8 +1302,8 @@ proc toFEN*(self: ChessBoard): string =
|
||||||
result &= " "
|
result &= " "
|
||||||
# Castling availability
|
# Castling availability
|
||||||
result &= "-"
|
result &= "-"
|
||||||
# let castleWhite = self.position.castlingAvailable.white
|
# let castleWhite = self.position.castlingRightsAvailable.white
|
||||||
# let castleBlack = self.position.castlingAvailable.black
|
# let castleBlack = self.position.castlingRightsAvailable.black
|
||||||
# if not (castleBlack.king or castleBlack.queen or castleWhite.king or castleWhite.queen):
|
# if not (castleBlack.king or castleBlack.queen or castleWhite.king or castleWhite.queen):
|
||||||
# result &= "-"
|
# result &= "-"
|
||||||
# else:
|
# else:
|
||||||
|
@ -1623,13 +1512,13 @@ proc handleMoveCommand(board: ChessBoard, command: seq[string]): Move {.discarda
|
||||||
|
|
||||||
# Since the user tells us just the source and target square of the move,
|
# Since the user tells us just the source and target square of the move,
|
||||||
# we have to figure out all the flags by ourselves (whether it's a double
|
# we have to figure out all the flags by ourselves (whether it's a double
|
||||||
# push, a capture, a promotion, castling, etc.)
|
# push, a capture, a promotion, etc.)
|
||||||
|
|
||||||
if board.grid[targetSquare].kind != Empty:
|
if board.grid[targetSquare].kind != Empty:
|
||||||
flags.add(Capture)
|
flags.add(Capture)
|
||||||
|
|
||||||
#elif board.grid[startSquare].kind == Pawn and abs(rowFromSquare(startSquare) - rowFromSquare(targetSquare)) == 2:
|
elif board.grid[startSquare].kind == Pawn and abs(rankFromSquare(startSquare) - rankFromSquare(targetSquare)) == 2:
|
||||||
# flags.add(DoublePush)
|
flags.add(DoublePush)
|
||||||
|
|
||||||
if len(moveString) == 5:
|
if len(moveString) == 5:
|
||||||
# Promotion
|
# Promotion
|
||||||
|
@ -1759,7 +1648,7 @@ const HELP_TEXT = """Nimfish help menu:
|
||||||
- position fen "..." moves a2a3 a7a6
|
- position fen "..." moves a2a3 a7a6
|
||||||
- clear: Clear the screen
|
- clear: Clear the screen
|
||||||
- move <move>: Perform the given move in algebraic notation
|
- move <move>: Perform the given move in algebraic notation
|
||||||
- castle: Print castling rights for each side
|
- castle: Print castlingRights rights for each side
|
||||||
- check: Print if the current side to move is in check
|
- check: Print if the current side to move is in check
|
||||||
- undo, u: Undoes the last move. Can be used in succession
|
- undo, u: Undoes the last move. Can be used in succession
|
||||||
- turn: Print which side is to move
|
- turn: Print which side is to move
|
||||||
|
@ -1836,7 +1725,7 @@ proc main: int =
|
||||||
echo board.getPiece(cmd[1])
|
echo board.getPiece(cmd[1])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
echo "error: get: invalid square"
|
echo "error: get: invalid square"
|
||||||
continue
|
continue
|
||||||
of "castle":
|
of "castle":
|
||||||
let canCastle = board.canCastle(board.getSideToMove())
|
let canCastle = board.canCastle(board.getSideToMove())
|
||||||
echo &"Castling rights for {($board.getSideToMove()).toLowerAscii()}:\n - King side: {(if canCastle.king: \"yes\" else: \"no\")}\n - Queen side: {(if canCastle.queen: \"yes\" else: \"no\")}"
|
echo &"Castling rights for {($board.getSideToMove()).toLowerAscii()}:\n - King side: {(if canCastle.king: \"yes\" else: \"no\")}\n - Queen side: {(if canCastle.queen: \"yes\" else: \"no\")}"
|
||||||
|
|
|
@ -240,7 +240,7 @@ func computeKingBitboards: array[64, Bitboard] =
|
||||||
movements = movements or king.leftRelativeTo(White)
|
movements = movements or king.leftRelativeTo(White)
|
||||||
movements = movements or king.rightRelativeTo(White)
|
movements = movements or king.rightRelativeTo(White)
|
||||||
movements = movements or king.backwardRelativeTo(White)
|
movements = movements or king.backwardRelativeTo(White)
|
||||||
movements = movements or king.forwardLeftRelativeTo(White)
|
movements = movements or king.forwardRightRelativeTo(White)
|
||||||
movements = movements or king.backwardRightRelativeTo(White)
|
movements = movements or king.backwardRightRelativeTo(White)
|
||||||
movements = movements or king.backwardLeftRelativeTo(White)
|
movements = movements or king.backwardLeftRelativeTo(White)
|
||||||
# We don't *need* to mask the king off: the engine already masks off
|
# We don't *need* to mask the king off: the engine already masks off
|
||||||
|
@ -265,6 +265,7 @@ func computeKnightBitboards: array[64, Bitboard] =
|
||||||
movements = movements or knight.shortKnightDownRightRelativeTo(White)
|
movements = movements or knight.shortKnightDownRightRelativeTo(White)
|
||||||
movements = movements or knight.shortKnightUpLeftRelativeTo(White)
|
movements = movements or knight.shortKnightUpLeftRelativeTo(White)
|
||||||
movements = movements or knight.shortKnightUpRightRelativeTo(White)
|
movements = movements or knight.shortKnightUpRightRelativeTo(White)
|
||||||
|
movements = movements and not knight
|
||||||
result[i] = movements
|
result[i] = movements
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue