Fix bugs with pawn movegen and add promotions
This commit is contained in:
parent
8f54603d08
commit
ac14dd9bde
|
@ -46,21 +46,21 @@ func `!=`*(a: Bitboard, b: SomeInteger): bool {.inline.} = a.uint64 != b.uint64
|
||||||
|
|
||||||
|
|
||||||
func getFileMask*(file: int): Bitboard = Bitboard(0x101010101010101'u64) shl file.uint64
|
func getFileMask*(file: int): Bitboard = Bitboard(0x101010101010101'u64) shl file.uint64
|
||||||
func getRankMask*(rank: int): Bitboard = Bitboard(uint64.high()) shl uint64(8 * (rank + 1))
|
func getRankMask*(rank: int): Bitboard = Bitboard(0xff) shl uint64(8 * rank)
|
||||||
func squareToBitboard*(square: SomeInteger): Bitboard = Bitboard(1'u64) shl square.uint64
|
func toBitboard*(square: SomeInteger): Bitboard = Bitboard(1'u64) shl square.uint64
|
||||||
func squareToBitboard*(square: Square): Bitboard = squareToBitboard(square.int8)
|
func toBitboard*(square: Square): Bitboard = toBitboard(square.int8)
|
||||||
|
|
||||||
proc bitboardToSquare*(b: Bitboard): Square = Square(b.uint64.countTrailingZeroBits())
|
proc toSquare*(b: Bitboard): Square = Square(b.uint64.countTrailingZeroBits())
|
||||||
func createMove*(startSquare: Bitboard, targetSquare: Square, flags: varargs[MoveFlag]): Move =
|
func createMove*(startSquare: Bitboard, targetSquare: Square, flags: varargs[MoveFlag]): Move =
|
||||||
result = createMove(startSquare.bitboardToSquare(), targetSquare, flags)
|
result = createMove(startSquare.toSquare(), targetSquare, flags)
|
||||||
|
|
||||||
|
|
||||||
func createMove*(startSquare: Square, targetSquare: Bitboard, flags: varargs[MoveFlag]): Move =
|
func createMove*(startSquare: Square, targetSquare: Bitboard, flags: varargs[MoveFlag]): Move =
|
||||||
result = createMove(startSquare, targetSquare.bitboardToSquare(), flags)
|
result = createMove(startSquare, targetSquare.toSquare(), flags)
|
||||||
|
|
||||||
|
|
||||||
func createMove*(startSquare, targetSquare: Bitboard, flags: varargs[MoveFlag]): Move =
|
func createMove*(startSquare, targetSquare: Bitboard, flags: varargs[MoveFlag]): Move =
|
||||||
result = createMove(startSquare.bitboardToSquare(), targetSquare.bitboardToSquare(), flags)
|
result = createMove(startSquare.toSquare(), targetSquare.toSquare(), flags)
|
||||||
|
|
||||||
|
|
||||||
func toBin*(x: Bitboard, b: Positive = 64): string = toBin(BiggestInt(x), b)
|
func toBin*(x: Bitboard, b: Positive = 64): string = toBin(BiggestInt(x), b)
|
||||||
|
@ -73,7 +73,7 @@ iterator items*(self: Bitboard): Square =
|
||||||
## are set
|
## are set
|
||||||
var bits = self
|
var bits = self
|
||||||
while bits != 0:
|
while bits != 0:
|
||||||
yield bits.bitboardToSquare()
|
yield bits.toSquare()
|
||||||
bits = bits and bits - 1
|
bits = bits and bits - 1
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,10 +165,10 @@ func getDirectionMask*(bitboard: Bitboard, color: PieceColor, direction: Directi
|
||||||
return bitboard shl 8
|
return bitboard shl 8
|
||||||
of Backward:
|
of Backward:
|
||||||
return bitboard shr 8
|
return bitboard shr 8
|
||||||
|
of ForwardLeft:
|
||||||
|
return bitboard shl 9
|
||||||
of ForwardRight:
|
of ForwardRight:
|
||||||
return bitboard shl 7
|
return bitboard shl 7
|
||||||
of ForwardLeft:
|
|
||||||
return bitboard shr 9
|
|
||||||
of BackwardRight:
|
of BackwardRight:
|
||||||
return bitboard shr 9
|
return bitboard shr 9
|
||||||
of BackwardLeft:
|
of BackwardLeft:
|
||||||
|
@ -179,34 +179,35 @@ func getDirectionMask*(bitboard: Bitboard, color: PieceColor, direction: Directi
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
||||||
|
func getLastRank*(color: PieceColor): Bitboard = (if color == White: getRankMask(0) else: getRankMask(7))
|
||||||
|
|
||||||
func getDirectionMask*(square: Square, color: PieceColor, direction: Direction): Bitboard =
|
func getDirectionMask*(square: Square, color: PieceColor, direction: Direction): Bitboard =
|
||||||
## Get a bitmask for the given direction for a piece
|
## Get a bitmask for the given direction for a piece
|
||||||
## of the given color located at the given square
|
## of the given color located at the given square
|
||||||
result = getDirectionMask(squareToBitboard(square), color, direction)
|
result = getDirectionMask(toBitboard(square), color, direction)
|
||||||
|
|
||||||
|
|
||||||
func forwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard = getDirectionMask(self, side, Forward)
|
func forwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard = getDirectionMask(self, side, Forward)
|
||||||
func doubleForwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard = self.forwardRelativeTo(side).forwardRelativeTo(side)
|
func doubleForwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard = self.forwardRelativeTo(side).forwardRelativeTo(side)
|
||||||
|
|
||||||
func backwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard = getDirectionMask(self, side, Backward)
|
func backwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard = getDirectionMask(self, side, Backward)
|
||||||
|
func doubleBackwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard = self.backwardRelativeTo(side).backwardRelativeTo(side)
|
||||||
|
|
||||||
|
|
||||||
# We mask off the first and last ranks/files for
|
# We mask off the first and last ranks for
|
||||||
# left and right movements respectively to
|
# left and right movements respectively to
|
||||||
# avoid weird wraparounds
|
# avoid weird wraparounds
|
||||||
func topRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
func forwardRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
||||||
getDirectionMask(self, side, ForwardRight) and not getFileMask(7)
|
getDirectionMask(self, side, ForwardRight) and not getFileMask(7)
|
||||||
|
|
||||||
|
|
||||||
func topLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
func forwardLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
||||||
getDirectionMask(self, side, ForwardLeft) and not getFileMask(0)
|
getDirectionMask(self, side, ForwardLeft) and not getFileMask(0)
|
||||||
|
|
||||||
|
|
||||||
func bottomRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
func bottomRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
||||||
let lastRank = if side == White: getRankMask(0) else: getRankMask(7)
|
getDirectionMask(self, side, BackwardRight) and not getFileMask(7)
|
||||||
getDirectionMask(self, side, BackwardRight) and not lastRank
|
|
||||||
|
|
||||||
|
|
||||||
func bottomLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
func bottomLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
||||||
let lastRank = if side == White: getRankMask(0) else: getRankMask(7)
|
getDirectionMask(self, side, BackwardLeft) and not getFileMask(0)
|
||||||
getDirectionMask(self, side, BackwardLeft) and not getRankMask(7)
|
|
|
@ -85,9 +85,8 @@ proc updateBoard*(self: ChessBoard)
|
||||||
|
|
||||||
|
|
||||||
# A bunch of getters
|
# A bunch of getters
|
||||||
func getActiveColor*(self: ChessBoard): PieceColor {.inline.} =
|
func getSideToMove*(self: ChessBoard): PieceColor {.inline.} =
|
||||||
## Returns the currently active color
|
## Returns the currently side to move
|
||||||
## (turn of who has to move)
|
|
||||||
return self.position.turn
|
return self.position.turn
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,17 +140,6 @@ func getKingStartingSquare(color: PieceColor): Square {.inline.} =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
||||||
func getLastRank(color: PieceColor): int {.inline.} =
|
|
||||||
## Retrieves the square of the last
|
|
||||||
## rank relative to the given color
|
|
||||||
case color:
|
|
||||||
of White:
|
|
||||||
return 0
|
|
||||||
of Black:
|
|
||||||
return 7
|
|
||||||
else:
|
|
||||||
return -1
|
|
||||||
|
|
||||||
func kingSideRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 7) else: makeSquare(0, 7))
|
func kingSideRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 7) else: makeSquare(0, 7))
|
||||||
func queenSideRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 0) else: makeSquare(0, 0))
|
func queenSideRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 0) else: makeSquare(0, 0))
|
||||||
func longCastleKing(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 2) else: makeSquare(0, 5))
|
func longCastleKing(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 2) else: makeSquare(0, 5))
|
||||||
|
@ -369,7 +357,7 @@ proc newChessboardFromFEN*(fen: string): ChessBoard =
|
||||||
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.updateAttackedSquares()
|
# result.updateAttackedSquares()
|
||||||
#[if result.inCheck(result.getActiveColor().opposite):
|
#[if result.inCheck(result.getSideToMove().opposite):
|
||||||
# Opponent king cannot be captured on the next move
|
# Opponent king cannot be captured on the next move
|
||||||
raise newException(ValueError, "invalid position: opponent king can be captured")]#
|
raise newException(ValueError, "invalid position: opponent king can be captured")]#
|
||||||
if result.position.pieces.white.king == Bitboard(0) or result.position.pieces.black.king == Bitboard(0):
|
if result.position.pieces.white.king == Bitboard(0) or result.position.pieces.black.king == Bitboard(0):
|
||||||
|
@ -509,7 +497,7 @@ func getKing(self: ChessBoard, color: PieceColor = None): Square {.inline.} =
|
||||||
## color (if it is None, the active color is used)
|
## color (if it is None, the active color is used)
|
||||||
var color = color
|
var color = color
|
||||||
if color == None:
|
if color == None:
|
||||||
color = self.getActiveColor()
|
color = self.getSideToMove()
|
||||||
case color:
|
case color:
|
||||||
of White:
|
of White:
|
||||||
return Square(self.position.pieces.white.king.uint64.countTrailingZeroBits())
|
return Square(self.position.pieces.white.king.uint64.countTrailingZeroBits())
|
||||||
|
@ -541,54 +529,61 @@ proc getOccupancy(self: ChessBoard): Bitboard =
|
||||||
|
|
||||||
proc generatePawnMovements(self: ChessBoard, moves: var MoveList) =
|
proc generatePawnMovements(self: ChessBoard, moves: var MoveList) =
|
||||||
## Helper of generatePawnMoves for generating all non-capture
|
## Helper of generatePawnMoves for generating all non-capture
|
||||||
## pawn movems
|
## and non-promotion pawn moves
|
||||||
let
|
let
|
||||||
sideToMove = self.getActiveColor()
|
sideToMove = self.getSideToMove()
|
||||||
pawns = self.getBitboard(Pawn, sideToMove)
|
pawns = self.getBitboard(Pawn, sideToMove)
|
||||||
# Can't move to these squares
|
# We can only move to squares that are *not* occupied by another piece.
|
||||||
occupancy = not self.getOccupancy()
|
# We also cannot move to the last rank, as that will result in a promotion
|
||||||
offsets = if sideToMove == White: (-8, -16) else: (8, 16)
|
# and is handled elsewhere
|
||||||
# Single pushes
|
occupancy = not (self.getOccupancy() or sideToMove.getLastRank())
|
||||||
|
# Single push
|
||||||
for square in pawns.forwardRelativeTo(sideToMove) and occupancy:
|
for square in pawns.forwardRelativeTo(sideToMove) and occupancy:
|
||||||
moves.add(createMove((square - offsets[0]), square))
|
moves.add(createMove(square.toBitboard().backwardRelativeTo(sideToMove), square))
|
||||||
# Double pushes
|
# Double push
|
||||||
for square in pawns.doubleForwardRelativeTo(sideToMove) and occupancy:
|
let rank = if sideToMove == White: getRankMask(6) else: getRankMask(1) # Only pawns on their starting rank can double push
|
||||||
moves.add(createMove((square - offsets[1]), square, DoublePush))
|
for square in (pawns and rank).doubleForwardRelativeTo(sideToMove) and occupancy:
|
||||||
|
moves.add(createMove(square.toBitboard().doubleBackwardRelativeTo(sideToMove), square, DoublePush))
|
||||||
|
|
||||||
|
|
||||||
proc generatePawnCaptures(self: ChessBoard, moves: var MoveList) =
|
proc generatePawnCaptures(self: ChessBoard, moves: var MoveList) =
|
||||||
## Helper of generatePawnMoves for generating all capture
|
## Helper of generatePawnMoves for generating all capture
|
||||||
## pawn moves
|
## pawn moves
|
||||||
let
|
let
|
||||||
sideToMove = self.getActiveColor()
|
sideToMove = self.getSideToMove()
|
||||||
nonSideToMove = sideToMove.opposite()
|
nonSideToMove = sideToMove.opposite()
|
||||||
pawns = self.getBitboard(Pawn, sideToMove)
|
pawns = self.getBitboard(Pawn, sideToMove)
|
||||||
# We can only capture enemy pieces
|
# We can only capture enemy pieces
|
||||||
enemyPieces = self.getOccupancyFor(nonSideToMove)
|
enemyPieces = self.getOccupancyFor(nonSideToMove)
|
||||||
offsets = if sideToMove == White: (9, 7) else: (-7, -9)
|
rightMovement = pawns.forwardRightRelativeTo(sideToMove)
|
||||||
rightMovement = pawns.topRightRelativeTo(sideToMove)
|
leftMovement = pawns.forwardLeftRelativeTo(sideToMove)
|
||||||
leftMovement = pawns.topLeftRelativeTo(sideToMove)
|
|
||||||
epTarget = self.getEnPassantTarget()
|
epTarget = self.getEnPassantTarget()
|
||||||
let epBitboard = if (epTarget != nullSquare()): epTarget.squareToBitboard() else: Bitboard(0)
|
let epBitboard = if (epTarget != nullSquare()): epTarget.toBitboard() else: Bitboard(0)
|
||||||
# Top right attacks
|
# Top right attacks
|
||||||
for square in rightMovement and enemyPieces:
|
for square in rightMovement and enemyPieces:
|
||||||
moves.add(createMove((square - offsets[0]), square, Capture))
|
moves.add(createMove(square.toBitboard().bottomLeftRelativeTo(sideToMove), square, Capture))
|
||||||
# Top left attacks
|
|
||||||
for square in leftMovement and enemyPieces:
|
for square in leftMovement and enemyPieces:
|
||||||
moves.add(createMove((square - offsets[1]), square, Capture))
|
moves.add(createMove(square.toBitboard().bottomRightRelativeTo(sideToMove), square, Capture))
|
||||||
# Special case for en passant
|
# Special case for en passant
|
||||||
let
|
let
|
||||||
epLeft = epBitboard and leftMovement
|
epLeft = epBitboard and leftMovement
|
||||||
epRight = epBitboard and rightMovement
|
epRight = epBitboard and rightMovement
|
||||||
if epLeft != 0:
|
if epLeft != 0:
|
||||||
moves.add(createMove(epBitboard.topLeftRelativeTo(nonSideToMove), epBitboard, EnPassant))
|
moves.add(createMove(epBitboard.forwardLeftRelativeTo(nonSideToMove), epBitboard, EnPassant))
|
||||||
elif epRight != 0:
|
elif epRight != 0:
|
||||||
moves.add(createMove(epBitboard.topRightRelativeTo(nonSideToMove), epBitboard, EnPassant))
|
moves.add(createMove(epBitboard.forwardRightRelativeTo(nonSideToMove), epBitboard, EnPassant))
|
||||||
|
|
||||||
|
|
||||||
proc generatePawnPromotions(self: ChessBoard, moves: var MoveList) =
|
proc generatePawnPromotions(self: ChessBoard, moves: var MoveList) =
|
||||||
## Helper of generatePawnMoves for generating all pawn promotion
|
## Helper of generatePawnMoves for generating all pawn promotion
|
||||||
## moves
|
## moves
|
||||||
|
let
|
||||||
|
sideToMove = self.getSideToMove()
|
||||||
|
pawns = self.getBitboard(Pawn, sideToMove)
|
||||||
|
occupancy = not self.getOccupancy()
|
||||||
|
for square in pawns.forwardRelativeTo(sideToMove) and occupancy and sideToMove.getLastRank():
|
||||||
|
for promotion in [PromoteToBishop, PromoteToKnight, PromoteToQueen, PromoteToRook]:
|
||||||
|
moves.add(createMove(square.toBitboard().backwardRelativeTo(sideToMove), square, promotion))
|
||||||
|
|
||||||
|
|
||||||
proc generatePawnMoves(self: ChessBoard, moves: var MoveList) =
|
proc generatePawnMoves(self: ChessBoard, moves: var MoveList) =
|
||||||
|
@ -597,6 +592,7 @@ proc generatePawnMoves(self: ChessBoard, moves: var MoveList) =
|
||||||
|
|
||||||
self.generatePawnMovements(moves)
|
self.generatePawnMovements(moves)
|
||||||
self.generatePawnCaptures(moves)
|
self.generatePawnCaptures(moves)
|
||||||
|
self.generatePawnPromotions(moves)
|
||||||
|
|
||||||
|
|
||||||
proc generateSlidingMoves(self: ChessBoard, square: Square): seq[Move] =
|
proc generateSlidingMoves(self: ChessBoard, square: Square): seq[Move] =
|
||||||
|
@ -882,7 +878,7 @@ proc doMove(self: ChessBoard, move: Move) =
|
||||||
inc(fullMoveCount)
|
inc(fullMoveCount)
|
||||||
|
|
||||||
if move.isDoublePush():
|
if move.isDoublePush():
|
||||||
enPassantTarget = move.targetSquare.squareToBitboard().backwardRelativeTo(piece.color).bitboardToSquare()
|
enPassantTarget = move.targetSquare.toBitboard().backwardRelativeTo(piece.color).toSquare()
|
||||||
|
|
||||||
# Castling check: have the rooks moved?
|
# Castling check: have the rooks moved?
|
||||||
if piece.kind == Rook:
|
if piece.kind == Rook:
|
||||||
|
@ -944,7 +940,7 @@ proc doMove(self: ChessBoard, move: Move) =
|
||||||
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.getActiveColor().opposite,
|
turn: self.getSideToMove().opposite,
|
||||||
castlingAvailable: castlingAvailable,
|
castlingAvailable: castlingAvailable,
|
||||||
enPassantSquare: enPassantTarget,
|
enPassantSquare: enPassantTarget,
|
||||||
pieces: self.position.pieces
|
pieces: self.position.pieces
|
||||||
|
@ -971,7 +967,7 @@ proc doMove(self: ChessBoard, move: Move) =
|
||||||
|
|
||||||
if move.isEnPassant():
|
if move.isEnPassant():
|
||||||
# Make the en passant pawn disappear
|
# Make the en passant pawn disappear
|
||||||
self.removePiece(move.targetSquare.squareToBitboard().backwardRelativeTo(piece.color).bitboardToSquare(), attack=false)
|
self.removePiece(move.targetSquare.toBitboard().backwardRelativeTo(piece.color).toSquare(), attack=false)
|
||||||
|
|
||||||
if move.isCapture():
|
if move.isCapture():
|
||||||
# Get rid of captured pieces
|
# Get rid of captured pieces
|
||||||
|
@ -1032,8 +1028,8 @@ 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.bitboardToSquare()] = Piece(color: White, kind: King)
|
self.grid[self.position.pieces.white.king.toSquare()] = Piece(color: White, kind: King)
|
||||||
self.grid[self.position.pieces.black.king.bitboardToSquare()] = Piece(color: Black, kind: King)
|
self.grid[self.position.pieces.black.king.toSquare()] = Piece(color: Black, kind: King)
|
||||||
|
|
||||||
|
|
||||||
proc unmakeMove*(self: ChessBoard) =
|
proc unmakeMove*(self: ChessBoard) =
|
||||||
|
@ -1180,7 +1176,7 @@ proc toFEN*(self: ChessBoard): string =
|
||||||
result &= "/"
|
result &= "/"
|
||||||
result &= " "
|
result &= " "
|
||||||
# Active color
|
# Active color
|
||||||
result &= (if self.getActiveColor() == White: "w" else: "b")
|
result &= (if self.getSideToMove() == White: "w" else: "b")
|
||||||
result &= " "
|
result &= " "
|
||||||
# Castling availability
|
# Castling availability
|
||||||
let castleWhite = self.position.castlingAvailable.white
|
let castleWhite = self.position.castlingAvailable.white
|
||||||
|
@ -1245,10 +1241,10 @@ proc perft*(self: ChessBoard, ply: int, verbose: bool = false, divide: bool = fa
|
||||||
|
|
||||||
for move in moves:
|
for move in moves:
|
||||||
if verbose:
|
if verbose:
|
||||||
let canCastle = self.canCastle(self.getActiveColor())
|
let canCastle = self.canCastle(self.getSideToMove())
|
||||||
echo &"Ply (from root): {self.position.plyFromRoot}"
|
echo &"Ply (from root): {self.position.plyFromRoot}"
|
||||||
echo &"Move: {move.startSquare.toAlgebraic()}{move.targetSquare.toAlgebraic()}, from ({move.startSquare.rank}, {move.startSquare.file}) to ({move.targetSquare.rank}, {move.targetSquare.file})"
|
echo &"Move: {move.startSquare.toAlgebraic()}{move.targetSquare.toAlgebraic()}, from ({move.startSquare.rank}, {move.startSquare.file}) to ({move.targetSquare.rank}, {move.targetSquare.file})"
|
||||||
echo &"Turn: {self.getActiveColor()}"
|
echo &"Turn: {self.getSideToMove()}"
|
||||||
echo &"Piece: {self.grid[move.startSquare].kind}"
|
echo &"Piece: {self.grid[move.startSquare].kind}"
|
||||||
echo &"Flags: {move.getFlags()}"
|
echo &"Flags: {move.getFlags()}"
|
||||||
echo &"In check: {(if self.inCheck(): \"yes\" else: \"no\")}"
|
echo &"In check: {(if self.inCheck(): \"yes\" else: \"no\")}"
|
||||||
|
@ -1274,7 +1270,7 @@ proc perft*(self: ChessBoard, ply: int, verbose: bool = false, divide: bool = fa
|
||||||
# Opponent king is in check
|
# Opponent king is in check
|
||||||
inc(result.checks)
|
inc(result.checks)
|
||||||
if verbose:
|
if verbose:
|
||||||
let canCastle = self.canCastle(self.getActiveColor())
|
let canCastle = self.canCastle(self.getSideToMove())
|
||||||
echo "\n"
|
echo "\n"
|
||||||
echo &"Opponent in check: {(if self.inCheck(): \"yes\" else: \"no\")}"
|
echo &"Opponent in check: {(if self.inCheck(): \"yes\" else: \"no\")}"
|
||||||
echo &"Opponent can castle:\n - King side: {(if canCastle.king: \"yes\" else: \"no\")}\n - Queen side: {(if canCastle.queen: \"yes\" else: \"no\")}"
|
echo &"Opponent can castle:\n - King side: {(if canCastle.king: \"yes\" else: \"no\")}\n - Queen side: {(if canCastle.queen: \"yes\" else: \"no\")}"
|
||||||
|
@ -1420,7 +1416,7 @@ proc handleMoveCommand(board: ChessBoard, command: seq[string]): Move {.discarda
|
||||||
|
|
||||||
var move = createMove(startSquare, targetSquare, flags)
|
var move = createMove(startSquare, targetSquare, flags)
|
||||||
let piece = board.getPiece(move.startSquare)
|
let piece = board.getPiece(move.startSquare)
|
||||||
if piece.kind == King and move.startSquare == board.getActiveColor().getKingStartingSquare():
|
if piece.kind == King and move.startSquare == board.getSideToMove().getKingStartingSquare():
|
||||||
if move.targetSquare == longCastleKing(piece.color):
|
if move.targetSquare == longCastleKing(piece.color):
|
||||||
move.flags = move.flags or CastleLong.uint16
|
move.flags = move.flags or CastleLong.uint16
|
||||||
elif move.targetSquare == shortCastleKing(piece.color):
|
elif move.targetSquare == shortCastleKing(piece.color):
|
||||||
|
@ -1582,7 +1578,7 @@ proc main: int =
|
||||||
of "undo", "u":
|
of "undo", "u":
|
||||||
board.unmakeMove()
|
board.unmakeMove()
|
||||||
of "turn":
|
of "turn":
|
||||||
echo &"Active color: {board.getActiveColor()}"
|
echo &"Active color: {board.getSideToMove()}"
|
||||||
of "ep":
|
of "ep":
|
||||||
let target = board.getEnPassantTarget()
|
let target = board.getEnPassantTarget()
|
||||||
if target != nullSquare():
|
if target != nullSquare():
|
||||||
|
@ -1600,9 +1596,9 @@ proc main: int =
|
||||||
continue
|
continue
|
||||||
#[of "castle":
|
#[of "castle":
|
||||||
let canCastle = board.canCastle()
|
let canCastle = board.canCastle()
|
||||||
echo &"Castling rights for {($board.getActiveColor()).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\")}"
|
||||||
of "check":
|
of "check":
|
||||||
echo &"{board.getActiveColor()} king in check: {(if board.inCheck(): \"yes\" else: \"no\")}"
|
echo &"{board.getSideToMove()} king in check: {(if board.inCheck(): \"yes\" else: \"no\")}"
|
||||||
]#
|
]#
|
||||||
else:
|
else:
|
||||||
echo &"Unknown command '{cmd[0]}'. Type 'help' for more information."
|
echo &"Unknown command '{cmd[0]}'. Type 'help' for more information."
|
||||||
|
@ -1719,18 +1715,18 @@ when isMainModule:
|
||||||
testPieceBitboard(blackQueens, blackQueenSquares)
|
testPieceBitboard(blackQueens, blackQueenSquares)
|
||||||
testPieceBitboard(blackKing, blackKingSquares)
|
testPieceBitboard(blackKing, blackKingSquares)
|
||||||
|
|
||||||
|
b = newChessboardFromFEN("B7/P1P1P1P1/1P1P1P1P/7k/8/8/8/3K4 w - - 0 1")
|
||||||
var m = MoveList()
|
var m = MoveList()
|
||||||
b.generatePawnMoves(m)
|
b.generatePawnMoves(m)
|
||||||
echo &"Pawn moves for {b.getActiveColor()} at {b.toFEN()}: "
|
echo &"Pawn moves for {b.getSideToMove()} at {b.toFEN()}: "
|
||||||
for move in m:
|
for move in m:
|
||||||
echo " - ", move.startSquare, move.targetSquare
|
echo " - ", move.startSquare, move.targetSquare, " ", move.getFlags()
|
||||||
b.doMove(createMove("a2", "a3"))
|
#[b.doMove(createMove("d1", "c1"))
|
||||||
m.clear()
|
m.clear()
|
||||||
b.generatePawnMoves(m)
|
b.generatePawnMoves(m)
|
||||||
echo &"Pawn moves for {b.getActiveColor()} at {b.toFEN()}: "
|
echo &"Pawn moves for {b.getSideToMove()} at {b.toFEN()}: "
|
||||||
for move in m:
|
for move in m:
|
||||||
echo " - ", move.startSquare, move.targetSquare
|
echo " - ", move.startSquare, move.targetSquare, " ", move.getFlags()
|
||||||
b.doMove(createMove("a7", "a5"))
|
echo b.pretty()]#
|
||||||
echo b.pretty()
|
|
||||||
# setControlCHook(proc () {.noconv.} = quit(0))
|
# setControlCHook(proc () {.noconv.} = quit(0))
|
||||||
# quit(main())
|
# quit(main())
|
||||||
|
|
|
@ -39,7 +39,9 @@ func `!=`*(a, b: Square): bool {.inline.} = a.int8 != b.int8
|
||||||
func `-`*(a, b: Square): Square {.inline.} = Square(a.int8 - b.int8)
|
func `-`*(a, b: Square): Square {.inline.} = Square(a.int8 - b.int8)
|
||||||
func `-`*(a: Square, b: SomeInteger): Square {.inline.} = Square(a.int8 - b.int8)
|
func `-`*(a: Square, b: SomeInteger): Square {.inline.} = Square(a.int8 - b.int8)
|
||||||
func `-`*(a: SomeInteger, b: Square): Square {.inline.} = Square(a.int8 - b.int8)
|
func `-`*(a: SomeInteger, b: Square): Square {.inline.} = Square(a.int8 - b.int8)
|
||||||
|
func `+`*(a, b: Square): Square {.inline.} = Square(a.int8 + b.int8)
|
||||||
|
func `+`*(a: Square, b: SomeInteger): Square {.inline.} = Square(a.int8 + b.int8)
|
||||||
|
func `+`*(a: SomeInteger, b: Square): Square {.inline.} = Square(a.int8 + b.int8)
|
||||||
|
|
||||||
func colFromSquare*(square: Square): int8 = square.int8 mod 8 + 1
|
func colFromSquare*(square: Square): int8 = square.int8 mod 8 + 1
|
||||||
func rowFromSquare*(square: Square): int8 = square.int8 div 8 + 1
|
func rowFromSquare*(square: Square): int8 = square.int8 div 8 + 1
|
||||||
|
|
|
@ -19,7 +19,7 @@ when isMainModule:
|
||||||
while true:
|
while true:
|
||||||
canCastle = board.canCastle()
|
canCastle = board.canCastle()
|
||||||
echo &"{board.pretty()}"
|
echo &"{board.pretty()}"
|
||||||
echo &"Turn: {board.getActiveColor()}"
|
echo &"Turn: {board.getSideToMove()}"
|
||||||
echo &"Moves: {board.getMoveCount()} full, {board.getHalfMoveCount()} half"
|
echo &"Moves: {board.getMoveCount()} full, {board.getHalfMoveCount()} half"
|
||||||
echo &"Can castle:\n - King side: {(if canCastle.king: \"yes\" else: \"no\")}\n - Queen side: {(if canCastle.queen: \"yes\" else: \"no\")}"
|
echo &"Can castle:\n - King side: {(if canCastle.king: \"yes\" else: \"no\")}\n - Queen side: {(if canCastle.queen: \"yes\" else: \"no\")}"
|
||||||
stdout.write(&"En passant target: ")
|
stdout.write(&"En passant target: ")
|
||||||
|
|
Loading…
Reference in New Issue