Bug fixes and huge performance improvement. Initial work on pins
This commit is contained in:
parent
4a9deb517a
commit
d5bcd15c48
|
@ -21,6 +21,7 @@ import nimfishpkg/magics
|
||||||
import nimfishpkg/pieces
|
import nimfishpkg/pieces
|
||||||
import nimfishpkg/moves
|
import nimfishpkg/moves
|
||||||
import nimfishpkg/position
|
import nimfishpkg/position
|
||||||
|
import nimfishpkg/rays
|
||||||
|
|
||||||
|
|
||||||
export bitboards, magics, pieces, moves, position
|
export bitboards, magics, pieces, moves, position
|
||||||
|
@ -248,7 +249,7 @@ func getKingAttacks(self: Chessboard, square: Square, attacker: PieceColor): Bit
|
||||||
result = Bitboard(0)
|
result = Bitboard(0)
|
||||||
let
|
let
|
||||||
king = self.getBitboard(King, attacker)
|
king = self.getBitboard(King, attacker)
|
||||||
if (getKingBitboard(square) and king) != 0:
|
if (getKingAttacks(square) and king) != 0:
|
||||||
result = result or king
|
result = result or king
|
||||||
|
|
||||||
|
|
||||||
|
@ -260,7 +261,7 @@ func getKnightAttacks(self: Chessboard, square: Square, attacker: PieceColor): B
|
||||||
result = Bitboard(0)
|
result = Bitboard(0)
|
||||||
for knight in knights:
|
for knight in knights:
|
||||||
let knightBB = knight.toBitboard()
|
let knightBB = knight.toBitboard()
|
||||||
if (getKnightBitboard(knight) and knightBB) != 0:
|
if (getKnightAttacks(knight) and knightBB) != 0:
|
||||||
result = result or knightBB
|
result = result or knightBB
|
||||||
|
|
||||||
|
|
||||||
|
@ -298,10 +299,14 @@ proc getAttacksTo*(self: Chessboard, square: Square, attacker: PieceColor): Bitb
|
||||||
proc updateChecksAndPins(self: Chessboard) =
|
proc updateChecksAndPins(self: Chessboard) =
|
||||||
## Updates internal metadata about checks and
|
## Updates internal metadata about checks and
|
||||||
## pinned pieces
|
## pinned pieces
|
||||||
|
|
||||||
|
# *Ahem*, stolen from https://github.com/Ciekce/voidstar/blob/424ac4624011271c4d1dbd743602c23f6dbda1de/src/position.rs
|
||||||
|
# Can you tell I'm a *great* coder?
|
||||||
let
|
let
|
||||||
sideToMove = self.position.sideToMove
|
sideToMove = self.position.sideToMove
|
||||||
nonSideToMove = sideToMove.opposite()
|
nonSideToMove = sideToMove.opposite()
|
||||||
friendlyKing = self.getBitboard(King, sideToMove).toSquare()
|
friendlyKingBB = self.getBitboard(King, sideToMove)
|
||||||
|
friendlyKing = friendlyKingBB.toSquare()
|
||||||
friendlyPieces = self.getOccupancyFor(sideToMove)
|
friendlyPieces = self.getOccupancyFor(sideToMove)
|
||||||
enemyPieces = self.getOccupancyFor(nonSideToMove)
|
enemyPieces = self.getOccupancyFor(nonSideToMove)
|
||||||
|
|
||||||
|
@ -311,6 +316,24 @@ proc updateChecksAndPins(self: Chessboard) =
|
||||||
self.position.diagonalPins = Bitboard(0)
|
self.position.diagonalPins = Bitboard(0)
|
||||||
self.position.orthogonalPins = Bitboard(0)
|
self.position.orthogonalPins = Bitboard(0)
|
||||||
|
|
||||||
|
let
|
||||||
|
diagonalAttackers = self.getBitboard(Queen, nonSideToMove) or self.getBitboard(Bishop, nonSideToMove)
|
||||||
|
orthogonalAttackers = self.getBitboard(Queen, nonSideToMove) or self.getBitboard(Rook, nonSideToMove)
|
||||||
|
canPinDiagonally = diagonalAttackers and getBishopMoves(friendlyKing, enemyPieces)
|
||||||
|
canPinOrthogonally = orthogonalAttackers and getRookMoves(friendlyKing, enemyPieces)
|
||||||
|
|
||||||
|
for piece in canPinDiagonally:
|
||||||
|
let pinningRay = getRayBetween(friendlyKing, piece) or piece.toBitboard()
|
||||||
|
|
||||||
|
if (pinningRay and friendlyKingBB).countSquares() > 0:
|
||||||
|
self.position.diagonalPins = self.position.diagonalPins or pinningRay
|
||||||
|
|
||||||
|
for piece in canPinOrthogonally:
|
||||||
|
let pinningRay = getRayBetween(friendlyKing, piece) or piece.toBitboard()
|
||||||
|
|
||||||
|
if (pinningRay and friendlyKingBB).countSquares() > 0:
|
||||||
|
self.position.diagonalPins = self.position.diagonalPins or pinningRay
|
||||||
|
|
||||||
|
|
||||||
func inCheck(self: Chessboard): bool {.inline.} =
|
func inCheck(self: Chessboard): bool {.inline.} =
|
||||||
## Returns if the current side to move is in check
|
## Returns if the current side to move is in check
|
||||||
|
@ -499,12 +522,13 @@ proc generatePawnMovements(self: Chessboard, moves: var MoveList) =
|
||||||
|
|
||||||
|
|
||||||
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 capturing
|
||||||
## pawn moves
|
## moves
|
||||||
let
|
let
|
||||||
sideToMove = self.position.sideToMove
|
sideToMove = self.position.sideToMove
|
||||||
nonSideToMove = sideToMove.opposite()
|
nonSideToMove = sideToMove.opposite()
|
||||||
pawns = self.getBitboard(Pawn, sideToMove)
|
pawns = self.getBitboard(Pawn, sideToMove)
|
||||||
|
occupancy = self.getOccupancy()
|
||||||
# We can only capture enemy pieces (except the king)
|
# We can only capture enemy pieces (except the king)
|
||||||
enemyPieces = self.getOccupancyFor(nonSideToMove) and not self.getBitboard(King, nonSideToMove)
|
enemyPieces = self.getOccupancyFor(nonSideToMove) and not self.getBitboard(King, nonSideToMove)
|
||||||
enemyPawns = self.getBitboard(Pawn, nonSideToMove)
|
enemyPawns = self.getBitboard(Pawn, nonSideToMove)
|
||||||
|
@ -512,7 +536,9 @@ proc generatePawnCaptures(self: Chessboard, moves: var MoveList) =
|
||||||
leftMovement = pawns.forwardLeftRelativeTo(sideToMove)
|
leftMovement = pawns.forwardLeftRelativeTo(sideToMove)
|
||||||
epTarget = self.position.enPassantSquare
|
epTarget = self.position.enPassantSquare
|
||||||
var epBitboard = if (epTarget != nullSquare()): epTarget.toBitboard() else: Bitboard(0)
|
var epBitboard = if (epTarget != nullSquare()): epTarget.toBitboard() else: Bitboard(0)
|
||||||
epBitboard = epBitboard and enemyPawns
|
# TODO: Remove this. Seems like we're not keeping track of en passant targets properly and
|
||||||
|
# trying to do en passant on top of a piece
|
||||||
|
epBitboard = epBitboard and not occupancy
|
||||||
# Top right attacks
|
# Top right attacks
|
||||||
for square in rightMovement and enemyPieces:
|
for square in rightMovement and enemyPieces:
|
||||||
moves.add(createMove(square.toBitboard().backwardLeftRelativeTo(sideToMove), square, Capture))
|
moves.add(createMove(square.toBitboard().backwardLeftRelativeTo(sideToMove), square, Capture))
|
||||||
|
@ -530,7 +556,7 @@ proc generatePawnCaptures(self: Chessboard, moves: var MoveList) =
|
||||||
|
|
||||||
|
|
||||||
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 promotion
|
||||||
## moves
|
## moves
|
||||||
let
|
let
|
||||||
sideToMove = self.position.sideToMove
|
sideToMove = self.position.sideToMove
|
||||||
|
@ -555,14 +581,26 @@ proc generateRookMoves(self: Chessboard, moves: var MoveList) =
|
||||||
occupancy = self.getOccupancy()
|
occupancy = self.getOccupancy()
|
||||||
nonSideToMove = sideToMove.opposite()
|
nonSideToMove = sideToMove.opposite()
|
||||||
enemyPieces = self.getOccupancyFor(sideToMove.opposite()) and not self.getBitboard(King, nonSideToMove)
|
enemyPieces = self.getOccupancyFor(sideToMove.opposite()) and not self.getBitboard(King, nonSideToMove)
|
||||||
rooks = self.getBitboard(Rook, sideToMove) or self.getBitboard(Queen, sideToMove)
|
rooks = self.getBitboard(Rook, sideToMove)
|
||||||
for square in rooks:
|
queens = self.getBitboard(Queen, sideToMove)
|
||||||
|
movableRooks = not self.position.diagonalPins and (queens or rooks)
|
||||||
|
pinMask = self.position.orthogonalPins
|
||||||
|
pinnedRooks = movableRooks and pinMask
|
||||||
|
unpinnedRooks = movableRooks and not pinnedRooks
|
||||||
|
for square in pinnedRooks:
|
||||||
|
let
|
||||||
|
blockers = occupancy and Rook.getRelevantBlockers(square)
|
||||||
|
moveset = getRookMoves(square, blockers)
|
||||||
|
for target in moveset and not occupancy and pinMask:
|
||||||
|
moves.add(createMove(square, target))
|
||||||
|
for target in moveset and enemyPieces and pinMask:
|
||||||
|
moves.add(createMove(square, target, Capture))
|
||||||
|
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:
|
for target in moveset and not occupancy:
|
||||||
moves.add(createMove(square, target))
|
moves.add(createMove(square, target))
|
||||||
# Captures
|
|
||||||
for target in moveset and enemyPieces:
|
for target in moveset and enemyPieces:
|
||||||
moves.add(createMove(square, target, Capture))
|
moves.add(createMove(square, target, Capture))
|
||||||
|
|
||||||
|
@ -571,11 +609,24 @@ proc generateBishopMoves(self: Chessboard, moves: var MoveList) =
|
||||||
## Helper of generateSlidingMoves to generate bishop moves
|
## Helper of generateSlidingMoves to generate bishop moves
|
||||||
let
|
let
|
||||||
sideToMove = self.position.sideToMove
|
sideToMove = self.position.sideToMove
|
||||||
|
occupancy = self.getOccupancy()
|
||||||
nonSideToMove = sideToMove.opposite()
|
nonSideToMove = sideToMove.opposite()
|
||||||
enemyPieces = self.getOccupancyFor(sideToMove.opposite()) and not self.getBitboard(King, nonSideToMove)
|
enemyPieces = self.getOccupancyFor(sideToMove.opposite()) and not self.getBitboard(King, nonSideToMove)
|
||||||
occupancy = self.getOccupancy()
|
bishops = self.getBitboard(Bishop, sideToMove)
|
||||||
bishops = self.getBitboard(Bishop, sideToMove) or self.getBitboard(Queen, sideToMove)
|
queens = self.getBitboard(Queen, sideToMove)
|
||||||
for square in bishops:
|
movableBishops = not self.position.orthogonalPins and (queens or bishops)
|
||||||
|
pinMask = self.position.diagonalPins
|
||||||
|
pinnedBishops = movableBishops and pinMask
|
||||||
|
unpinnedBishops = movableBishops and not pinnedBishops
|
||||||
|
for square in pinnedBishops:
|
||||||
|
let
|
||||||
|
blockers = occupancy and Bishop.getRelevantBlockers(square)
|
||||||
|
moveset = getBishopMoves(square, blockers)
|
||||||
|
for target in moveset and pinMask and not occupancy:
|
||||||
|
moves.add(createMove(square, target))
|
||||||
|
for target in moveset and enemyPieces and pinMask:
|
||||||
|
moves.add(createMove(square, target, Capture))
|
||||||
|
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)
|
||||||
|
@ -597,15 +648,13 @@ proc generateKingMoves(self: Chessboard, moves: var MoveList) =
|
||||||
let
|
let
|
||||||
sideToMove = self.position.sideToMove
|
sideToMove = self.position.sideToMove
|
||||||
king = self.getBitboard(King, sideToMove)
|
king = self.getBitboard(King, sideToMove)
|
||||||
moveIdx = king.toSquare().uint64
|
|
||||||
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) and not self.getBitboard(King, nonSideToMove)
|
||||||
# Regular moves
|
bitboard = getKingAttacks(king.toSquare())
|
||||||
for square in KING_BITBOARDS[moveIdx] and not occupancy:
|
for square in bitboard and not occupancy:
|
||||||
moves.add(createMove(king, square))
|
moves.add(createMove(king, square))
|
||||||
# Captures
|
for square in bitboard and enemyPieces:
|
||||||
for square in KING_BITBOARDS[moveIdx] and enemyPieces:
|
|
||||||
moves.add(createMove(king, square, Capture))
|
moves.add(createMove(king, square, Capture))
|
||||||
|
|
||||||
|
|
||||||
|
@ -616,13 +665,14 @@ proc generateKnightMoves(self: Chessboard, moves: var MoveList)=
|
||||||
knights = self.getBitboard(Knight, sideToMove)
|
knights = self.getBitboard(Knight, sideToMove)
|
||||||
occupancy = self.getOccupancy()
|
occupancy = self.getOccupancy()
|
||||||
nonSideToMove = sideToMove.opposite()
|
nonSideToMove = sideToMove.opposite()
|
||||||
|
pinned = self.position.diagonalPins or self.position.orthogonalPins
|
||||||
|
unpinnedKnights = knights and not pinned
|
||||||
enemyPieces = self.getOccupancyFor(nonSideToMove) and not self.getBitboard(King, nonSideToMove)
|
enemyPieces = self.getOccupancyFor(nonSideToMove) and not self.getBitboard(King, nonSideToMove)
|
||||||
for square in knights:
|
for square in unpinnedKnights:
|
||||||
# Regular moves
|
let bitboard = getKnightAttacks(square)
|
||||||
for target in KNIGHT_BITBOARDS[square.uint64] and not occupancy:
|
for target in bitboard and not occupancy:
|
||||||
moves.add(createMove(square, target))
|
moves.add(createMove(square, target))
|
||||||
# Captures
|
for target in bitboard and enemyPieces:
|
||||||
for target in KNIGHT_BITBOARDS[square.uint64] and enemyPieces:
|
|
||||||
moves.add(createMove(square, target, Capture))
|
moves.add(createMove(square, target, Capture))
|
||||||
|
|
||||||
|
|
||||||
|
@ -635,6 +685,14 @@ proc generateMoves*(self: Chessboard, moves: var MoveList) =
|
||||||
# TODO: Check for draw by insufficient material
|
# TODO: Check for draw by insufficient material
|
||||||
# TODO: Check for repetitions (requires zobrist hashing + table)
|
# TODO: Check for repetitions (requires zobrist hashing + table)
|
||||||
self.generateKingMoves(moves)
|
self.generateKingMoves(moves)
|
||||||
|
if self.position.checkers.countSquares() > 1:
|
||||||
|
# King is in double check: no need to generate any more
|
||||||
|
# moves
|
||||||
|
return
|
||||||
|
if not self.inCheck():
|
||||||
|
# TODO: Castling
|
||||||
|
discard
|
||||||
|
|
||||||
self.generatePawnMoves(moves)
|
self.generatePawnMoves(moves)
|
||||||
self.generateKnightMoves(moves)
|
self.generateKnightMoves(moves)
|
||||||
self.generateSlidingMoves(moves)
|
self.generateSlidingMoves(moves)
|
||||||
|
|
|
@ -52,6 +52,7 @@ func clearBit*(a: var Bitboard, bit: SomeInteger) = a.uint64.clearBit(bit)
|
||||||
func setBit*(a: var Bitboard, bit: SomeInteger) = a.uint64.setBit(bit)
|
func setBit*(a: var Bitboard, bit: SomeInteger) = a.uint64.setBit(bit)
|
||||||
func clearBit*(a: var Bitboard, bit: Square) = a.uint64.clearBit(bit.int)
|
func clearBit*(a: var Bitboard, bit: Square) = a.uint64.clearBit(bit.int)
|
||||||
func setBit*(a: var Bitboard, bit: Square) = a.uint64.setBit(bit.int)
|
func setBit*(a: var Bitboard, bit: Square) = a.uint64.setBit(bit.int)
|
||||||
|
func removed*(a, b: Bitboard): Bitboard = a and not b
|
||||||
|
|
||||||
|
|
||||||
func countSquares*(self: Bitboard): int {.inline.} =
|
func countSquares*(self: Bitboard): int {.inline.} =
|
||||||
|
@ -103,10 +104,9 @@ iterator subsets*(self: Bitboard): Bitboard =
|
||||||
var subset = Bitboard(0)
|
var subset = Bitboard(0)
|
||||||
while true:
|
while true:
|
||||||
subset = (subset - self) and self
|
subset = (subset - self) and self
|
||||||
|
yield subset
|
||||||
if subset == 0:
|
if subset == 0:
|
||||||
break
|
break
|
||||||
yield subset
|
|
||||||
|
|
||||||
|
|
||||||
iterator pairs*(self: Bitboard): tuple[i: int, sq: Square] =
|
iterator pairs*(self: Bitboard): tuple[i: int, sq: Square] =
|
||||||
var i = 0
|
var i = 0
|
||||||
|
@ -167,8 +167,6 @@ func getDirectionMask*(bitboard: Bitboard, color: PieceColor, direction: Directi
|
||||||
of Right:
|
of Right:
|
||||||
return bitboard shl 1
|
return bitboard shl 1
|
||||||
of Black:
|
of Black:
|
||||||
# The directions for black are just the opposite of those for white,
|
|
||||||
# so we avoid duplicating any code
|
|
||||||
case direction:
|
case direction:
|
||||||
of Forward:
|
of Forward:
|
||||||
return bitboard shl 8
|
return bitboard shl 8
|
||||||
|
@ -284,9 +282,9 @@ func computeKnightBitboards: array[64, Bitboard] {.compileTime.} =
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
KING_BITBOARDS* = computeKingBitboards()
|
KING_BITBOARDS = computeKingBitboards()
|
||||||
KNIGHT_BITBOARDS* = computeKnightBitboards()
|
KNIGHT_BITBOARDS = computeKnightBitboards()
|
||||||
|
|
||||||
|
|
||||||
func getKingBitboard*(square: Square): Bitboard {.inline.} = KING_BITBOARDS[square.int]
|
func getKingAttacks*(square: Square): Bitboard {.inline.} = KING_BITBOARDS[square.int]
|
||||||
func getKnightBitboard*(square: Square): Bitboard {.inline.} = KNIGHT_BITBOARDS[square.int]
|
func getKnightAttacks*(square: Square): Bitboard {.inline.} = KNIGHT_BITBOARDS[square.int]
|
||||||
|
|
|
@ -137,8 +137,8 @@ proc getRookMoves*(square: Square, blockers: Bitboard): Bitboard =
|
||||||
## square with the given blockers bitboard
|
## square with the given blockers bitboard
|
||||||
let
|
let
|
||||||
magic = ROOK_MAGICS[square.uint]
|
magic = ROOK_MAGICS[square.uint]
|
||||||
moves = ROOK_MOVES[square.uint]
|
movesAddr = addr ROOK_MOVES[square.uint]
|
||||||
return moves[getIndex(magic, blockers)]
|
return movesAddr[][getIndex(magic, blockers)]
|
||||||
|
|
||||||
|
|
||||||
proc getBishopMoves*(square: Square, blockers: Bitboard): Bitboard =
|
proc getBishopMoves*(square: Square, blockers: Bitboard): Bitboard =
|
||||||
|
@ -146,8 +146,20 @@ proc getBishopMoves*(square: Square, blockers: Bitboard): Bitboard =
|
||||||
## square with the given blockers bitboard
|
## square with the given blockers bitboard
|
||||||
let
|
let
|
||||||
magic = BISHOP_MAGICS[square.uint]
|
magic = BISHOP_MAGICS[square.uint]
|
||||||
moves = BISHOP_MOVES[square.uint]
|
movesAddr = addr BISHOP_MOVES[square.uint]
|
||||||
return moves[getIndex(magic, blockers)]
|
return movesAddr[][getIndex(magic, blockers)]
|
||||||
|
|
||||||
|
|
||||||
|
proc getRookMagic*(square: Square): MagicEntry =
|
||||||
|
## Returns the magic entry for a rook
|
||||||
|
## on the given square
|
||||||
|
return ROOK_MAGICS[square.uint]
|
||||||
|
|
||||||
|
|
||||||
|
proc getBishopMagic*(square: Square): MagicEntry =
|
||||||
|
## Returns the magic entry for a bishop
|
||||||
|
## on the given square
|
||||||
|
return BISHOP_MAGICS[square.uint]
|
||||||
|
|
||||||
|
|
||||||
# Precomputed blocker masks. Only pieces on these bitboards
|
# Precomputed blocker masks. Only pieces on these bitboards
|
||||||
|
@ -188,7 +200,7 @@ func tryOffset(square: Square, df, dr: SomeInteger): Square =
|
||||||
return makeSquare(rank + dr, file + df)
|
return makeSquare(rank + dr, file + df)
|
||||||
|
|
||||||
|
|
||||||
proc getMoveSet*(kind: PieceKind, square: Square, blocker: Bitboard): Bitboard =
|
proc getMoveset*(kind: PieceKind, square: Square, blocker: Bitboard): Bitboard =
|
||||||
## A naive implementation of sliding attacks. Returns the moves that can
|
## A naive implementation of sliding attacks. Returns the moves that can
|
||||||
## be performed from the given piece at the given square with the given
|
## be performed from the given piece at the given square with the given
|
||||||
## blocker mask
|
## blocker mask
|
||||||
|
@ -223,8 +235,8 @@ proc attemptMagicTableCreation(kind: PieceKind, square: Square, entry: MagicEntr
|
||||||
# for several different blocker configurations, as
|
# for several different blocker configurations, as
|
||||||
# many of them (while different) produce the same
|
# many of them (while different) produce the same
|
||||||
# results
|
# results
|
||||||
var moves = kind.getMoveSet(square, blocker)
|
var moves = kind.getMoveset(square, blocker)
|
||||||
if result.table[index] == 0:
|
if result.table[index] == Bitboard(0):
|
||||||
# No entry here, yet, so no problem!
|
# No entry here, yet, so no problem!
|
||||||
result.table[index] = moves
|
result.table[index] = moves
|
||||||
elif result.table[index] != moves:
|
elif result.table[index] != moves:
|
||||||
|
@ -265,7 +277,7 @@ proc findMagic(kind: PieceKind, square: Square, indexBits: uint8): tuple[entry:
|
||||||
# Again, this is stolen from the article. A magic number
|
# Again, this is stolen from the article. A magic number
|
||||||
# is only useful if it has high bit sparsity, so we AND
|
# is only useful if it has high bit sparsity, so we AND
|
||||||
# together a bunch of random values to get a number that's
|
# together a bunch of random values to get a number that's
|
||||||
# hopefully better
|
# hopefully better than a single one
|
||||||
let
|
let
|
||||||
magic = rand.next() and rand.next() and rand.next()
|
magic = rand.next() and rand.next() and rand.next()
|
||||||
entry = MagicEntry(mask: mask, value: magic, indexBits: indexBits)
|
entry = MagicEntry(mask: mask, value: magic, indexBits: indexBits)
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
import std/strutils
|
|
||||||
import std/strformat
|
|
||||||
|
|
||||||
|
|
||||||
import bitboards
|
import bitboards
|
||||||
import magics
|
import magics
|
||||||
import pieces
|
import pieces
|
||||||
import moves
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import bitboards
|
||||||
|
import magics
|
||||||
|
|
||||||
|
# Stolen from https://github.com/Ciekce/voidstar/blob/main/src/rays.rs :D
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proc computeRaysBetweenSquares: array[64, array[64, Bitboard]] =
|
||||||
|
## Computes all sliding rays between each pair of squares
|
||||||
|
## in the chessboard
|
||||||
|
for i in 0..63:
|
||||||
|
let
|
||||||
|
source = Square(i)
|
||||||
|
sourceBitboard = source.toBitboard()
|
||||||
|
rooks = getRookMoves(source, Bitboard(0))
|
||||||
|
bishops = getBishopMoves(source, Bitboard(0))
|
||||||
|
for j in 0..63:
|
||||||
|
let target = Square(j)
|
||||||
|
if target == source:
|
||||||
|
result[i][j] = Bitboard(0)
|
||||||
|
else:
|
||||||
|
let targetBitboard = target.toBitboard()
|
||||||
|
if rooks.contains(target):
|
||||||
|
result[i][j] = getRookMoves(source, targetBitboard) and getRookMoves(target, sourceBitboard)
|
||||||
|
elif bishops.contains(target):
|
||||||
|
result[i][j] = getBishopMoves(source, targetBitboard) and getBishopMoves(target, sourceBitboard)
|
||||||
|
else:
|
||||||
|
result[i][j] = Bitboard(0)
|
||||||
|
|
||||||
|
|
||||||
|
let BETWEEN_RAYS = computeRaysBetweenSquares()
|
||||||
|
|
||||||
|
|
||||||
|
proc getRayBetween*(source, target: Square): Bitboard {.inline.} = BETWEEN_RAYS[source.int][target.int]
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue