Add move generation for bishops and queens as well as attack tracking
This commit is contained in:
parent
82cef11cc4
commit
19ad46bbda
|
@ -149,6 +149,8 @@ func shortCastleKing(color: PieceColor): Square {.inline.} = (if color == White:
|
||||||
func longCastleRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 3) else: makeSquare(7, 5))
|
func longCastleRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(7, 3) else: makeSquare(7, 5))
|
||||||
func shortCastleRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(0, 0) else: makeSquare(0, 2))
|
func shortCastleRook(color: PieceColor): Square {.inline.} = (if color == White: makeSquare(0, 0) else: makeSquare(0, 2))
|
||||||
|
|
||||||
|
proc inCheck(self: ChessBoard, side: PieceColor): bool
|
||||||
|
|
||||||
|
|
||||||
proc newChessboard: ChessBoard =
|
proc newChessboard: ChessBoard =
|
||||||
## Returns a new, empty chessboard
|
## Returns a new, empty chessboard
|
||||||
|
@ -358,10 +360,9 @@ 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.updateAttackedSquares()
|
if result.inCheck(result.getSideToMove().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 == 0 or result.position.pieces.black.king == 0:
|
if result.position.pieces.white.king == 0 or result.position.pieces.black.king == 0:
|
||||||
# Both kings must be on the board
|
# Both kings must be on the board
|
||||||
raise newException(ValueError, "invalid position: exactly one king of each color must be present")
|
raise newException(ValueError, "invalid position: exactly one king of each color must be present")
|
||||||
|
@ -548,7 +549,7 @@ proc getKingAttacks(self: ChessBoard, square: Square, attacker: PieceColor): Bit
|
||||||
let
|
let
|
||||||
sq = square.toBitboard()
|
sq = square.toBitboard()
|
||||||
king = self.getBitboard(King, attacker)
|
king = self.getBitboard(King, attacker)
|
||||||
if (sq and KING_BITBOARDS[square.uint64]) != 0:
|
if (KING_BITBOARDS[square.uint] and king) != 0:
|
||||||
result = result or sq
|
result = result or sq
|
||||||
|
|
||||||
|
|
||||||
|
@ -560,10 +561,37 @@ proc getKnightAttacks(self: ChessBoard, square: Square, attacker: PieceColor): B
|
||||||
knights = self.getBitboard(Knight, attacker)
|
knights = self.getBitboard(Knight, attacker)
|
||||||
result = Bitboard(0)
|
result = Bitboard(0)
|
||||||
for knight in knights:
|
for knight in knights:
|
||||||
if (sq and KNIGHT_BITBOARDS[knight.uint64]) != 0:
|
if (KNIGHT_BITBOARDS[square.uint] and knight.toBitboard()) != 0:
|
||||||
result = result or knight.toBitboard()
|
result = result or knight.toBitboard()
|
||||||
|
|
||||||
|
|
||||||
|
proc getSlidingAttacks(self: ChessBoard, square: Square, attacker: PieceColor): Bitboard =
|
||||||
|
## Returns the attack bitboard for the given square from
|
||||||
|
## the sliding pieces of the given side
|
||||||
|
let
|
||||||
|
sq = square.toBitboard()
|
||||||
|
queens = self.getBitboard(Queen, attacker)
|
||||||
|
rooks = self.getBitboard(Rook, attacker)
|
||||||
|
bishops = self.getBitboard(Bishop, attacker)
|
||||||
|
occupancy = self.getOccupancy()
|
||||||
|
result = Bitboard(0)
|
||||||
|
for rook in rooks:
|
||||||
|
let blockers = Rook.getRelevantBlockers(square)
|
||||||
|
if (getRookMoves(square, blockers) and rook.toBitboard()) != 0:
|
||||||
|
result = result or rook.toBitboard()
|
||||||
|
for bishop in bishops:
|
||||||
|
let blockers = Bishop.getRelevantBlockers(square)
|
||||||
|
if (getBishopMoves(square, blockers) and bishop.toBitboard()) != 0:
|
||||||
|
result = result or bishop.toBitboard()
|
||||||
|
for queen in queens:
|
||||||
|
let rookBlockers = Rook.getRelevantBlockers(square)
|
||||||
|
if (getRookMoves(square, rookBlockers) and queen.toBitboard()) != 0:
|
||||||
|
result = result or queen.toBitboard()
|
||||||
|
let bishopBlockers = Bishop.getRelevantBlockers(square)
|
||||||
|
if (getBishopMoves(square, bishopBlockers) and queen.toBitboard()) != 0:
|
||||||
|
result = result or queen.toBitboard()
|
||||||
|
|
||||||
|
|
||||||
proc getAttacksTo(self: ChessBoard, square: Square, attacker: PieceColor): Bitboard =
|
proc getAttacksTo(self: ChessBoard, square: Square, attacker: PieceColor): Bitboard =
|
||||||
## Computes the attack bitboard for the given square from
|
## Computes the attack bitboard for the given square from
|
||||||
## the given side
|
## the given side
|
||||||
|
@ -573,6 +601,17 @@ proc getAttacksTo(self: ChessBoard, square: Square, attacker: PieceColor): Bitbo
|
||||||
result = result or self.getPawnAttacks(square, attacker)
|
result = result or self.getPawnAttacks(square, attacker)
|
||||||
result = result or self.getKingAttacks(square, attacker)
|
result = result or self.getKingAttacks(square, attacker)
|
||||||
result = result or self.getKnightAttacks(square, attacker)
|
result = result or self.getKnightAttacks(square, attacker)
|
||||||
|
result = result or self.getSlidingAttacks(square, attacker)
|
||||||
|
|
||||||
|
|
||||||
|
proc inCheck(self: ChessBoard, side: PieceColor): bool =
|
||||||
|
## Returns if the current side to move is in check
|
||||||
|
return self.getAttacksTo(self.getKingSquare(side), side.opposite()) != 0
|
||||||
|
|
||||||
|
|
||||||
|
proc canCastle(self: ChessBoard, side: PieceColor): tuple[king, queen: bool] =
|
||||||
|
## Returns if the current side to move can castle
|
||||||
|
return (false, false) # TODO
|
||||||
|
|
||||||
|
|
||||||
proc getCapturablePieces(self: ChessBoard, side: PieceColor): Bitboard {.inline.} =
|
proc getCapturablePieces(self: ChessBoard, side: PieceColor): Bitboard {.inline.} =
|
||||||
|
@ -597,7 +636,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 = if sideToMove == White: getRankMask(6) else: getRankMask(1) # Only pawns on their starting rank can double push
|
let rank = sideToMove.getFirstRank() # 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))
|
||||||
|
|
||||||
|
@ -661,7 +700,7 @@ proc generateRookMovements(self: ChessBoard, moves: var MoveList) =
|
||||||
for square in rooks:
|
for square in rooks:
|
||||||
let blockers = occupancy and Rook.getRelevantBlockers(square)
|
let blockers = occupancy and Rook.getRelevantBlockers(square)
|
||||||
var moveset = getRookMoves(square, blockers)
|
var moveset = getRookMoves(square, blockers)
|
||||||
# Can't capture our own pieces
|
# Can't move over our own pieces
|
||||||
moveset = moveset and not friendlyPieces
|
moveset = moveset and not friendlyPieces
|
||||||
for target in moveset:
|
for target in moveset:
|
||||||
moves.add(createMove(square, target))
|
moves.add(createMove(square, target))
|
||||||
|
@ -679,9 +718,10 @@ proc generateRookCaptures(self: ChessBoard, moves: var MoveList) =
|
||||||
let blockers = occupancy and Rook.getRelevantBlockers(square)
|
let blockers = occupancy and Rook.getRelevantBlockers(square)
|
||||||
var moveset = getRookMoves(square, blockers)
|
var moveset = getRookMoves(square, blockers)
|
||||||
# Can only cature enemy pieces
|
# Can only cature enemy pieces
|
||||||
moveset = moveset and not enemyPieces
|
moveset = moveset and enemyPieces
|
||||||
for target in moveset:
|
for target in moveset:
|
||||||
moves.add(createMove(square, target))
|
moves.add(createMove(square, target, Capture))
|
||||||
|
|
||||||
|
|
||||||
proc generateRookMoves(self: ChessBoard, moves: var MoveList) =
|
proc generateRookMoves(self: ChessBoard, moves: var MoveList) =
|
||||||
## Helper of generateSlidingMoves to generate rook moves
|
## Helper of generateSlidingMoves to generate rook moves
|
||||||
|
@ -689,9 +729,103 @@ proc generateRookMoves(self: ChessBoard, moves: var MoveList) =
|
||||||
self.generateRookCaptures(moves)
|
self.generateRookCaptures(moves)
|
||||||
|
|
||||||
|
|
||||||
|
proc generateBishopMovements(self: ChessBoard, moves: var MoveList) =
|
||||||
|
## Helper of generateBishopMoves to generate all non-capture
|
||||||
|
## bishop moves
|
||||||
|
let
|
||||||
|
sideToMove = self.getSideToMove()
|
||||||
|
occupancy = self.getOccupancy()
|
||||||
|
friendlyPieces = self.getOccupancyFor(sideToMove)
|
||||||
|
bishops = self.getBitboard(Bishop, sideToMove)
|
||||||
|
for square in bishops:
|
||||||
|
let blockers = occupancy and Bishop.getRelevantBlockers(square)
|
||||||
|
var moveset = getBishopMoves(square, blockers)
|
||||||
|
# Can't move over our own pieces
|
||||||
|
moveset = moveset and not friendlyPieces
|
||||||
|
for target in moveset:
|
||||||
|
moves.add(createMove(square, target))
|
||||||
|
|
||||||
|
|
||||||
|
proc generateBishopCaptures(self: ChessBoard, moves: var MoveList) =
|
||||||
|
## Helper of generateBishopMoves to generate all capture
|
||||||
|
## bishop moves
|
||||||
|
let
|
||||||
|
sideToMove = self.getSideToMove()
|
||||||
|
occupancy = self.getOccupancy()
|
||||||
|
enemyPieces = self.getCapturablePieces(sideToMove.opposite())
|
||||||
|
bishops = self.getBitboard(Bishop, sideToMove)
|
||||||
|
for square in bishops:
|
||||||
|
let blockers = occupancy and Bishop.getRelevantBlockers(square)
|
||||||
|
var moveset = getRookMoves(square, blockers)
|
||||||
|
# Can only cature enemy pieces
|
||||||
|
moveset = moveset and enemyPieces
|
||||||
|
for target in moveset:
|
||||||
|
moves.add(createMove(square, target, Capture))
|
||||||
|
|
||||||
|
|
||||||
|
proc generateBishopMoves(self: ChessBoard, moves: var MoveList) =
|
||||||
|
## Helper of generateSlidingMoves to generate bishop moves
|
||||||
|
self.generateBishopMovements(moves)
|
||||||
|
self.generateBishopCaptures(moves)
|
||||||
|
|
||||||
|
|
||||||
|
proc generateQueenMovements(self: ChessBoard, moves: var MoveList) =
|
||||||
|
## Helper of generateQueenMoves to generate all non-capture
|
||||||
|
## bishop moves
|
||||||
|
let
|
||||||
|
sideToMove = self.getSideToMove()
|
||||||
|
occupancy = self.getOccupancy()
|
||||||
|
friendlyPieces = self.getOccupancyFor(sideToMove)
|
||||||
|
queens = self.getBitboard(Queen, sideToMove)
|
||||||
|
for square in queens:
|
||||||
|
# A queen is just a rook plus a bishop in terms of move
|
||||||
|
# generation
|
||||||
|
let
|
||||||
|
rookBlockers = Rook.getRelevantBlockers(square) and occupancy
|
||||||
|
bishopBlockers = Bishop.getRelevantBlockers(square) and occupancy
|
||||||
|
rookMoves = getRookMoves(square, rookBlockers)
|
||||||
|
bishopMoves = getBishopMoves(square, bishopBlockers)
|
||||||
|
var moveset = rookMoves or bishopMoves
|
||||||
|
# Can't move over our own pieces
|
||||||
|
moveset = moveset and not friendlyPieces
|
||||||
|
for target in moveset:
|
||||||
|
moves.add(createMove(square, target))
|
||||||
|
|
||||||
|
|
||||||
|
proc generateQueenCaptures(self: ChessBoard, moves: var MoveList) =
|
||||||
|
## Helper of generateQueenMoves to generate all capture
|
||||||
|
## queen moves
|
||||||
|
let
|
||||||
|
sideToMove = self.getSideToMove()
|
||||||
|
occupancy = self.getOccupancy()
|
||||||
|
enemyPieces = self.getCapturablePieces(sideToMove.opposite())
|
||||||
|
queens = self.getBitboard(Queen, sideToMove)
|
||||||
|
for square in queens:
|
||||||
|
# A queen is just a rook plus a bishop in terms of move
|
||||||
|
# generation
|
||||||
|
let
|
||||||
|
rookBlockers = Rook.getRelevantBlockers(square) and occupancy
|
||||||
|
bishopBlockers = Bishop.getRelevantBlockers(square) and occupancy
|
||||||
|
rookMoves = getRookMoves(square, rookBlockers)
|
||||||
|
bishopMoves = getBishopMoves(square, bishopBlockers)
|
||||||
|
var moveset = rookMoves or bishopMoves
|
||||||
|
# Can only capture the enemy pieces
|
||||||
|
moveset = moveset and enemyPieces
|
||||||
|
for target in moveset:
|
||||||
|
moves.add(createMove(square, target, Capture))
|
||||||
|
|
||||||
|
|
||||||
|
proc generateQueenMoves(self: ChessBoard, moves: var MoveList) =
|
||||||
|
## Helper of generateSlidingMoves to generate queen moves
|
||||||
|
self.generateQueenMovements(moves)
|
||||||
|
self.generateQueenCaptures(moves)
|
||||||
|
|
||||||
|
|
||||||
proc generateSlidingMoves(self: ChessBoard, moves: var MoveList) =
|
proc generateSlidingMoves(self: ChessBoard, moves: var MoveList) =
|
||||||
## Generates all legal sliding moves for the side to move
|
## Generates all legal sliding moves for the side to move
|
||||||
self.generateRookMoves(moves)
|
self.generateRookMoves(moves)
|
||||||
|
self.generateBishopMoves(moves)
|
||||||
|
self.generateQueenMoves(moves)
|
||||||
|
|
||||||
|
|
||||||
proc generateKingMoves(self: ChessBoard, moves: var MoveList) =
|
proc generateKingMoves(self: ChessBoard, moves: var MoveList) =
|
||||||
|
@ -800,8 +934,7 @@ proc generateMoves*(self: ChessBoard, moves: var MoveList) =
|
||||||
self.generatePawnMoves(moves)
|
self.generatePawnMoves(moves)
|
||||||
self.generateKingMoves(moves)
|
self.generateKingMoves(moves)
|
||||||
self.generateKnightMoves(moves)
|
self.generateKnightMoves(moves)
|
||||||
self.generateRookMoves(moves)
|
self.generateSlidingMoves(moves)
|
||||||
# TODO: all pieces
|
|
||||||
|
|
||||||
|
|
||||||
proc removePieceFromBitboard(self: ChessBoard, square: Square) =
|
proc removePieceFromBitboard(self: ChessBoard, square: Square) =
|
||||||
|
@ -1329,7 +1462,7 @@ proc toFEN*(self: ChessBoard): string =
|
||||||
# Fullmove number
|
# Fullmove number
|
||||||
result &= $self.getMoveCount()
|
result &= $self.getMoveCount()
|
||||||
|
|
||||||
#[
|
|
||||||
proc perft*(self: ChessBoard, ply: int, verbose: bool = false, divide: bool = false, bulk: bool = false): CountData =
|
proc perft*(self: ChessBoard, ply: int, verbose: bool = false, divide: bool = false, bulk: bool = false): CountData =
|
||||||
## Counts (and debugs) the number of legal positions reached after
|
## Counts (and debugs) the number of legal positions reached after
|
||||||
## the given number of ply
|
## the given number of ply
|
||||||
|
@ -1337,7 +1470,7 @@ proc perft*(self: ChessBoard, ply: int, verbose: bool = false, divide: bool = fa
|
||||||
var moves = MoveList()
|
var moves = MoveList()
|
||||||
self.generateMoves(moves)
|
self.generateMoves(moves)
|
||||||
if not bulk:
|
if not bulk:
|
||||||
if len(moves) == 0 and self.inCheck():
|
if len(moves) == 0 and self.inCheck(self.getSideToMove()):
|
||||||
result.checkmates = 1
|
result.checkmates = 1
|
||||||
# TODO: Should we count stalemates/draws?
|
# TODO: Should we count stalemates/draws?
|
||||||
if ply == 0:
|
if ply == 0:
|
||||||
|
@ -1367,11 +1500,11 @@ proc perft*(self: ChessBoard, ply: int, verbose: bool = false, divide: bool = fa
|
||||||
if verbose:
|
if verbose:
|
||||||
let canCastle = self.canCastle(self.getSideToMove())
|
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()}"
|
||||||
echo &"Turn: {self.getSideToMove()}"
|
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(self.getSideToMove()): \"yes\" else: \"no\")}"
|
||||||
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\")}"
|
||||||
echo &"Position before move: {self.toFEN()}"
|
echo &"Position before move: {self.toFEN()}"
|
||||||
stdout.write("En Passant target: ")
|
stdout.write("En Passant target: ")
|
||||||
|
@ -1390,13 +1523,13 @@ proc perft*(self: ChessBoard, ply: int, verbose: bool = false, divide: bool = fa
|
||||||
inc(result.promotions)
|
inc(result.promotions)
|
||||||
if move.isEnPassant():
|
if move.isEnPassant():
|
||||||
inc(result.enPassant)
|
inc(result.enPassant)
|
||||||
if self.inCheck():
|
if self.inCheck(self.getSideToMove()):
|
||||||
# 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.getSideToMove())
|
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(self.getSideToMove()): \"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\")}"
|
||||||
echo &"Position after move: {self.toFEN()}"
|
echo &"Position after move: {self.toFEN()}"
|
||||||
echo "\n", self.pretty()
|
echo "\n", self.pretty()
|
||||||
|
@ -1433,7 +1566,7 @@ proc perft*(self: ChessBoard, ply: int, verbose: bool = false, divide: bool = fa
|
||||||
result.castles += next.castles
|
result.castles += next.castles
|
||||||
result.enPassant += next.enPassant
|
result.enPassant += next.enPassant
|
||||||
result.checkmates += next.checkmates
|
result.checkmates += next.checkmates
|
||||||
]#
|
|
||||||
|
|
||||||
proc handleGoCommand(board: ChessBoard, command: seq[string]) =
|
proc handleGoCommand(board: ChessBoard, command: seq[string]) =
|
||||||
if len(command) < 2:
|
if len(command) < 2:
|
||||||
|
@ -1462,7 +1595,7 @@ proc handleGoCommand(board: ChessBoard, command: seq[string]) =
|
||||||
break
|
break
|
||||||
if not ok:
|
if not ok:
|
||||||
return
|
return
|
||||||
#[try:
|
try:
|
||||||
let ply = parseInt(args[0])
|
let ply = parseInt(args[0])
|
||||||
if bulk:
|
if bulk:
|
||||||
let t = cpuTime()
|
let t = cpuTime()
|
||||||
|
@ -1485,7 +1618,6 @@ proc handleGoCommand(board: ChessBoard, command: seq[string]) =
|
||||||
echo "Error: go: perft: invalid depth"
|
echo "Error: go: perft: invalid depth"
|
||||||
else:
|
else:
|
||||||
echo &"Error: go: unknown subcommand '{command[1]}'"
|
echo &"Error: go: unknown subcommand '{command[1]}'"
|
||||||
]#
|
|
||||||
|
|
||||||
|
|
||||||
proc handleMoveCommand(board: ChessBoard, command: seq[string]): Move {.discardable.} =
|
proc handleMoveCommand(board: ChessBoard, command: seq[string]): Move {.discardable.} =
|
||||||
|
@ -1660,6 +1792,7 @@ const HELP_TEXT = """Nimfish help menu:
|
||||||
- fen: Shorthand for "position fen"
|
- fen: Shorthand for "position fen"
|
||||||
- pos <args>: Shorthand for "position <args>"
|
- pos <args>: Shorthand for "position <args>"
|
||||||
- get <square>: Get the piece on the given square
|
- get <square>: Get the piece on the given square
|
||||||
|
- atk: Print the attack bitboard of the given square for the side to move
|
||||||
- uci: enter UCI mode (WIP)
|
- uci: enter UCI mode (WIP)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -1703,6 +1836,15 @@ proc main: int =
|
||||||
board.unmakeMove()
|
board.unmakeMove()
|
||||||
of "turn":
|
of "turn":
|
||||||
echo &"Active color: {board.getSideToMove()}"
|
echo &"Active color: {board.getSideToMove()}"
|
||||||
|
of "atk":
|
||||||
|
if len(cmd) != 2:
|
||||||
|
echo "error: atk: invalid number of arguments"
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
echo board.getAttacksTo(cmd[1].toSquare(), board.getSideToMove())
|
||||||
|
except ValueError:
|
||||||
|
echo "error: atk: invalid square"
|
||||||
|
continue
|
||||||
of "ep":
|
of "ep":
|
||||||
let target = board.getEnPassantTarget()
|
let target = board.getEnPassantTarget()
|
||||||
if target != nullSquare():
|
if target != nullSquare():
|
||||||
|
@ -1718,12 +1860,11 @@ proc main: int =
|
||||||
except ValueError:
|
except ValueError:
|
||||||
echo "error: get: invalid square"
|
echo "error: get: invalid square"
|
||||||
continue
|
continue
|
||||||
#[of "castle":
|
of "castle":
|
||||||
let canCastle = board.canCastle()
|
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\")}"
|
||||||
of "check":
|
of "check":
|
||||||
echo &"{board.getSideToMove()} king in check: {(if board.inCheck(): \"yes\" else: \"no\")}"
|
echo &"{board.getSideToMove()} king in check: {(if board.inCheck(board.getSideToMove()): \"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."
|
||||||
except IOError:
|
except IOError:
|
||||||
|
@ -1839,14 +1980,5 @@ when isMainModule:
|
||||||
testPieceBitboard(blackQueens, blackQueenSquares)
|
testPieceBitboard(blackQueens, blackQueenSquares)
|
||||||
testPieceBitboard(blackKing, blackKingSquares)
|
testPieceBitboard(blackKing, blackKingSquares)
|
||||||
|
|
||||||
|
setControlCHook(proc () {.noconv.} = quit(0))
|
||||||
b = newChessboardFromFEN("8/5R2/8/8/7k/8/5K2/8 w - - 0 1")
|
quit(main())
|
||||||
var m = MoveList()
|
|
||||||
b.generateRookMovements(m)
|
|
||||||
echo &"There are {len(m)} legal moves for {b.getSideToMove()} at {b.toFEN()}: "
|
|
||||||
for move in m:
|
|
||||||
echo " - ", move.startSquare, move.targetSquare, " ", move.getFlags()
|
|
||||||
echo b.pretty()
|
|
||||||
|
|
||||||
# setControlCHook(proc () {.noconv.} = quit(0))
|
|
||||||
# quit(main())
|
|
||||||
|
|
|
@ -342,9 +342,10 @@ else:
|
||||||
var path = joinPath(getCurrentDir(), "src/resources")
|
var path = joinPath(getCurrentDir(), "src/resources")
|
||||||
if path.lastPathPart() == "nimfish":
|
if path.lastPathPart() == "nimfish":
|
||||||
path = joinPath("src", path)
|
path = joinPath("src", path)
|
||||||
|
echo "Loading magic bitboards"
|
||||||
var magics = readFile(joinPath(path, "magics.json")).fromJson(TableRef[string, array[64, MagicEntry]])
|
var magics = readFile(joinPath(path, "magics.json")).fromJson(TableRef[string, array[64, MagicEntry]])
|
||||||
var moves = readFile(joinPath(path, "movesets.json")).fromJson(TableRef[string, array[64, seq[Bitboard]]])
|
var moves = readFile(joinPath(path, "movesets.json")).fromJson(TableRef[string, array[64, seq[Bitboard]]])
|
||||||
ROOK_MAGICS = magics["rooks"]
|
ROOK_MAGICS = magics["rooks"]
|
||||||
BISHOP_MAGICS = magics["bishops"]
|
BISHOP_MAGICS = magics["bishops"]
|
||||||
ROOK_MOVES = moves["rooks"]
|
ROOK_MOVES = moves["rooks"]
|
||||||
BISHOP_MOVES = moves["bishops"]
|
BISHOP_MOVES = moves["bishops"]
|
||||||
|
|
Loading…
Reference in New Issue