This commit is contained in:
Mattia Giambirtone 2024-04-19 21:43:56 +02:00
parent 64c30b8a90
commit 6fbcd4ff74
2 changed files with 33 additions and 100 deletions

View File

@ -721,109 +721,45 @@ proc generatePawnMoves(self: ChessBoard, moves: var MoveList) =
self.generatePawnPromotions(moves)
proc generateRookMovements(self: ChessBoard, moves: var MoveList) =
## Helper of generateRookMoves to generate all non-capture
## rook moves
let
sideToMove = self.getSideToMove()
occupancy = self.getOccupancy()
rooks = self.getBitboard(Rook, sideToMove)
for square in rooks:
let blockers = occupancy and Rook.getRelevantBlockers(square)
# Can't move over other pieces (captures are handled elsewhere)
let moveset = getRookMoves(square, blockers) and not occupancy
for target in moveset:
moves.add(createMove(square, target))
proc generateRookCaptures(self: ChessBoard, moves: var MoveList) =
## Helper of generateRookMoves to generate all capture
## rook moves
let
sideToMove = self.getSideToMove()
occupancy = self.getOccupancy()
enemyPieces = self.getCapturablePieces(sideToMove.opposite())
rooks = self.getBitboard(Rook, sideToMove)
for square in rooks:
let blockers = occupancy and Rook.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 generateRookMoves(self: ChessBoard, moves: var MoveList) =
## Helper of generateSlidingMoves to generate rook moves
self.generateRookMovements(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()
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 other pieces (captures are handled elsewhere)
moveset = moveset and not occupancy
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)
rooks = self.getBitboard(Rook, sideToMove)
for square in rooks:
let blockers = occupancy and Rook.getRelevantBlockers(square)
# Quiet moves
var moveset = getRookMoves(square, blockers)
# Can only cature enemy pieces
moveset = moveset and enemyPieces
for target in moveset:
for target in moveset and not occupancy:
moves.add(createMove(square, target))
# Captures
for target in moveset and enemyPieces:
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
# self.generateBishopMovements(moves)
# self.generateBishopCaptures(moves)
let
sideToMove = self.getSideToMove()
enemyPieces = self.getOccupancyFor(sideToMove.opposite())
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 other pieces (captures are handled elsewhere)
moveset = moveset and not occupancy
for target in moveset:
bishops = self.getBitboard(Bishop, sideToMove)
for square in bishops:
let blockers = occupancy and Bishop.getRelevantBlockers(square)
let moveset = getBishopMoves(square, blockers)
# Can't move over other pieces
for target in moveset and not occupancy:
moves.add(createMove(square, target))
for target in moveset and enemyPieces:
moves.add(createMove(square, target, Capture))
proc generateQueenCaptures(self: ChessBoard, moves: var MoveList) =
## Helper of generateQueenMoves to generate all capture
## queen moves
proc generateQueenMoves(self: ChessBoard, moves: var MoveList) =
## Helper of generateSlidingMoves to generate queen moves
let
sideToMove = self.getSideToMove()
occupancy = self.getOccupancy()
@ -837,17 +773,12 @@ proc generateQueenCaptures(self: ChessBoard, moves: var MoveList) =
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)
let moveset = rookMoves or bishopMoves
# Can't move over other pieces
for target in moveset and not occupancy:
moves.add(createMove(square, target))
for target in moveset and enemyPieces:
moves.add(createMove(square, target))
proc generateSlidingMoves(self: ChessBoard, moves: var MoveList) =
@ -894,7 +825,6 @@ proc generateKnightMoves(self: ChessBoard, moves: var MoveList)=
proc generateMoves*(self: ChessBoard, moves: var MoveList) =
## Generates the list of all possible legal moves
## in the current position
moves.clear()
if self.position.halfMoveClock >= 100:
# Draw by 50-move rule
return
@ -1084,7 +1014,6 @@ proc doMove*(self: ChessBoard, move: Move) =
else:
# Unreachable
discard
self.updateCheckers()
proc spawnPiece(self: ChessBoard, square: Square, piece: Piece) =

View File

@ -6,6 +6,8 @@ import std/strutils
import std/times
import std/math
from std/lenientops import `/`
type
CountData = tuple[nodes: uint64, captures: uint64, castles: uint64, checks: uint64, promotions: uint64, enPassant: uint64, checkmates: uint64]
@ -148,11 +150,13 @@ proc handleGoCommand(board: ChessBoard, command: seq[string]) =
if bulk:
let t = cpuTime()
let nodes = board.perft(ply, divide=true, bulk=true, verbose=verbose).nodes
let tot = cpuTime() - t
echo &"\nNodes searched (bulk-counting: on): {nodes}"
echo &"Time taken: {round(cpuTime() - t, 3)} seconds\n"
echo &"Time taken: {round(tot, 3)} seconds\nNodes per second: {round(nodes / tot).uint64}"
else:
let t = cpuTime()
let data = board.perft(ply, divide=true, verbose=verbose)
let tot = cpuTime()
echo &"\nNodes searched (bulk-counting: off): {data.nodes}"
echo &" - Captures: {data.captures}"
echo &" - Checks: {data.checks}"
@ -161,7 +165,7 @@ proc handleGoCommand(board: ChessBoard, command: seq[string]) =
echo &" - Castles: {data.castles}"
echo &" - Promotions: {data.promotions}"
echo ""
echo &"Time taken: {round(cpuTime() - t, 3)} seconds"
echo &"Time taken: {round(t, 3)} seconds\nNodes per second: {round(data.nodes / tot).uint64}"
except ValueError:
echo "Error: go: perft: invalid depth"
else: