2024-04-21 11:09:12 +02:00
|
|
|
# Copyright 2024 Mattia Giambirtone & All Contributors
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
2024-04-16 15:24:31 +02:00
|
|
|
## Implements low-level bit operations
|
|
|
|
|
|
|
|
|
|
|
|
import std/bitops
|
|
|
|
import std/strutils
|
|
|
|
|
|
|
|
|
|
|
|
import pieces
|
2024-04-16 23:45:32 +02:00
|
|
|
import moves
|
2024-04-16 15:24:31 +02:00
|
|
|
|
|
|
|
|
|
|
|
type
|
|
|
|
Bitboard* = distinct uint64
|
|
|
|
## A bitboard
|
|
|
|
|
2024-04-16 23:45:32 +02:00
|
|
|
Direction* = enum
|
|
|
|
## A move direction enumeration
|
|
|
|
Forward,
|
|
|
|
Backward,
|
|
|
|
Left,
|
|
|
|
Right
|
|
|
|
ForwardLeft,
|
|
|
|
ForwardRight,
|
|
|
|
BackwardLeft,
|
|
|
|
BackwardRight
|
2024-04-16 15:24:31 +02:00
|
|
|
|
|
|
|
# Overloaded operators and functions for our bitboard type
|
2024-05-13 14:51:21 +02:00
|
|
|
func `shl`*(a: Bitboard, x: Natural): Bitboard {.borrow.}
|
|
|
|
func `shr`*(a: Bitboard, x: Natural): Bitboard {.borrow.}
|
|
|
|
func `and`*(a, b: Bitboard): Bitboard {.borrow.}
|
|
|
|
func `or`*(a, b: Bitboard): Bitboard {.borrow.}
|
|
|
|
func `not`*(a: Bitboard): Bitboard {.borrow.}
|
|
|
|
func `shr`*(a, b: Bitboard): Bitboard {.borrow.}
|
|
|
|
func `xor`*(a, b: Bitboard): Bitboard {.borrow.}
|
|
|
|
func `+`*(a, b: Bitboard): Bitboard {.borrow.}
|
|
|
|
func `-`*(a, b: Bitboard): Bitboard {.borrow.}
|
|
|
|
func `div`*(a, b: Bitboard): Bitboard {.borrow.}
|
|
|
|
func `*`*(a, b: Bitboard): Bitboard {.borrow.}
|
|
|
|
func `+`*(a: Bitboard, b: SomeUnsignedInt): Bitboard {.borrow.}
|
|
|
|
func `-`*(a: Bitboard, b: SomeUnsignedInt): Bitboard {.borrow.}
|
|
|
|
func `div`*(a: Bitboard, b: SomeUnsignedInt): Bitboard {.borrow.}
|
|
|
|
func `*`*(a: Bitboard, b: SomeUnsignedInt): Bitboard {.borrow.}
|
|
|
|
func `*`*(a: SomeUnsignedInt, b: Bitboard): Bitboard {.borrow.}
|
|
|
|
func `==`*(a, b: Bitboard): bool {.inline, borrow.}
|
2024-04-16 15:24:31 +02:00
|
|
|
func `==`*(a: Bitboard, b: SomeInteger): bool {.inline.} = a.uint64 == b.uint64
|
2024-04-16 23:45:32 +02:00
|
|
|
func `!=`*(a, b: Bitboard): bool {.inline.} = a.uint64 != b.uint64
|
|
|
|
func `!=`*(a: Bitboard, b: SomeInteger): bool {.inline.} = a.uint64 != b.uint64
|
2024-04-20 13:28:14 +02:00
|
|
|
func countSetBits*(a: Bitboard): int = a.uint64.countSetBits()
|
2024-05-13 14:51:21 +02:00
|
|
|
func countLeadingZeroBits*(a: Bitboard): int {.borrow.}
|
|
|
|
func countTrailingZeroBits*(a: Bitboard): int {.borrow.}
|
|
|
|
func clearBit*(a: var Bitboard, bit: SomeInteger) {.borrow.}
|
|
|
|
func setBit*(a: var Bitboard, bit: SomeInteger) {.borrow.}
|
|
|
|
func clearBit*(a: var Bitboard, bit: Square) {.borrow.}
|
|
|
|
func setBit*(a: var Bitboard, bit: Square) {.borrow.}
|
2024-04-20 17:48:18 +02:00
|
|
|
func removed*(a, b: Bitboard): Bitboard = a and not b
|
2024-04-16 15:24:31 +02:00
|
|
|
|
|
|
|
|
2024-04-20 14:51:50 +02:00
|
|
|
func countSquares*(self: Bitboard): int {.inline.} =
|
|
|
|
## Returns the number of active squares
|
|
|
|
## in the bitboard
|
|
|
|
result = self.countSetBits()
|
|
|
|
|
|
|
|
|
2024-04-20 23:47:57 +02:00
|
|
|
func lowestSquare*(self: Bitboard): Square {.inline.} =
|
2024-04-23 18:57:38 +02:00
|
|
|
## Returns the index of the lowest set bit
|
2024-04-20 23:47:57 +02:00
|
|
|
## in the given bitboard as a square
|
|
|
|
result = Square(self.countTrailingZeroBits().uint8)
|
|
|
|
|
|
|
|
|
2024-04-23 18:57:38 +02:00
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func getFileMask*(file: int): Bitboard {.inline.} = Bitboard(0x101010101010101'u64) shl file.uint64
|
|
|
|
func getRankMask*(rank: int): Bitboard {.inline.} = Bitboard(0xff) shl uint64(8 * rank)
|
|
|
|
func toBitboard*(square: SomeInteger): Bitboard {.inline.} = Bitboard(1'u64) shl square.uint64
|
|
|
|
func toBitboard*(square: Square): Bitboard {.inline.} = toBitboard(square.int8)
|
|
|
|
func toSquare*(b: Bitboard): Square {.inline.} = Square(b.uint64.countTrailingZeroBits())
|
2024-04-16 23:45:32 +02:00
|
|
|
|
2024-04-20 14:51:50 +02:00
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func createMove*(startSquare: Bitboard, targetSquare: Square, flags: varargs[MoveFlag]): Move {.inline.} =
|
2024-04-17 11:54:45 +02:00
|
|
|
result = createMove(startSquare.toSquare(), targetSquare, flags)
|
2024-04-16 23:45:32 +02:00
|
|
|
|
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func createMove*(startSquare: Square, targetSquare: Bitboard, flags: varargs[MoveFlag]): Move {.inline.} =
|
2024-04-17 11:54:45 +02:00
|
|
|
result = createMove(startSquare, targetSquare.toSquare(), flags)
|
2024-04-16 23:45:32 +02:00
|
|
|
|
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func createMove*(startSquare, targetSquare: Bitboard, flags: varargs[MoveFlag]): Move {.inline.} =
|
2024-04-17 11:54:45 +02:00
|
|
|
result = createMove(startSquare.toSquare(), targetSquare.toSquare(), flags)
|
2024-04-16 15:24:31 +02:00
|
|
|
|
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func toBin*(x: Bitboard, b: Positive = 64): string {.inline.} = toBin(BiggestInt(x), b)
|
|
|
|
func toBin*(x: uint64, b: Positive = 64): string {.inline.} = toBin(Bitboard(x), b)
|
|
|
|
func contains*(self: Bitboard, square: Square): bool {.inline.} = (self and square.toBitboard()) != 0
|
2024-04-19 13:40:31 +02:00
|
|
|
|
2024-04-16 15:24:31 +02:00
|
|
|
|
|
|
|
iterator items*(self: Bitboard): Square =
|
|
|
|
## Iterates ove the given bitboard
|
|
|
|
## and returns all the squares that
|
|
|
|
## are set
|
|
|
|
var bits = self
|
|
|
|
while bits != 0:
|
2024-04-17 11:54:45 +02:00
|
|
|
yield bits.toSquare()
|
2024-04-16 15:24:31 +02:00
|
|
|
bits = bits and bits - 1
|
|
|
|
|
|
|
|
|
2024-04-18 21:17:29 +02:00
|
|
|
iterator subsets*(self: Bitboard): Bitboard =
|
|
|
|
## Iterates over all the subsets of the given
|
|
|
|
## bitboard using the Carry-Rippler trick
|
|
|
|
|
|
|
|
# Thanks analog-hors :D
|
|
|
|
var subset = Bitboard(0)
|
|
|
|
while true:
|
|
|
|
subset = (subset - self) and self
|
2024-04-20 17:48:18 +02:00
|
|
|
yield subset
|
2024-04-18 21:17:29 +02:00
|
|
|
if subset == 0:
|
|
|
|
break
|
|
|
|
|
2024-04-16 15:24:31 +02:00
|
|
|
iterator pairs*(self: Bitboard): tuple[i: int, sq: Square] =
|
|
|
|
var i = 0
|
|
|
|
for item in self:
|
|
|
|
yield (i, item)
|
|
|
|
inc(i)
|
|
|
|
|
|
|
|
|
|
|
|
func pretty*(self: Bitboard): string =
|
|
|
|
|
|
|
|
iterator items(self: Bitboard): uint8 =
|
|
|
|
## Iterates over all the bits in the
|
|
|
|
## given bitboard
|
|
|
|
for i in 0..63:
|
|
|
|
yield self.uint64.bitsliced(i..i).uint8
|
|
|
|
|
|
|
|
|
|
|
|
iterator pairs(self: Bitboard): (int, uint8) =
|
|
|
|
var i = 0
|
|
|
|
for bit in self:
|
|
|
|
yield (i, bit)
|
|
|
|
inc(i)
|
|
|
|
|
|
|
|
## Returns a prettyfied version of
|
|
|
|
## the given bitboard
|
2024-04-16 23:45:32 +02:00
|
|
|
result &= "- - - - - - - -\n"
|
2024-04-16 15:24:31 +02:00
|
|
|
for i, bit in self:
|
|
|
|
if i > 0 and i mod 8 == 0:
|
|
|
|
result &= "\n"
|
2024-04-16 23:45:32 +02:00
|
|
|
result &= $bit & " "
|
|
|
|
result &= "\n- - - - - - - -"
|
|
|
|
|
2024-04-16 15:24:31 +02:00
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func `$`*(self: Bitboard): string {.inline.} = self.pretty()
|
2024-04-16 15:24:31 +02:00
|
|
|
|
2024-04-16 23:45:32 +02:00
|
|
|
|
|
|
|
func getDirectionMask*(bitboard: Bitboard, color: PieceColor, direction: Direction): Bitboard =
|
|
|
|
## Get a bitmask relative to the given bitboard
|
|
|
|
## for the given direction for a piece of the
|
|
|
|
## given color
|
2024-04-16 15:24:31 +02:00
|
|
|
case color:
|
|
|
|
of White:
|
|
|
|
case direction:
|
|
|
|
of Forward:
|
2024-04-16 23:45:32 +02:00
|
|
|
return bitboard shr 8
|
2024-04-16 15:24:31 +02:00
|
|
|
of Backward:
|
2024-04-16 23:45:32 +02:00
|
|
|
return bitboard shl 8
|
2024-04-16 15:24:31 +02:00
|
|
|
of ForwardRight:
|
2024-04-16 23:45:32 +02:00
|
|
|
return bitboard shr 7
|
2024-04-16 15:24:31 +02:00
|
|
|
of ForwardLeft:
|
2024-04-16 23:45:32 +02:00
|
|
|
return bitboard shr 9
|
2024-04-16 15:24:31 +02:00
|
|
|
of BackwardRight:
|
2024-04-16 23:45:32 +02:00
|
|
|
return bitboard shl 9
|
2024-04-16 15:24:31 +02:00
|
|
|
of BackwardLeft:
|
2024-04-17 16:50:55 +02:00
|
|
|
return bitboard shl 7
|
|
|
|
of Left:
|
|
|
|
return bitboard shr 1
|
|
|
|
of Right:
|
|
|
|
return bitboard shl 1
|
2024-04-16 15:24:31 +02:00
|
|
|
of Black:
|
|
|
|
case direction:
|
|
|
|
of Forward:
|
2024-04-16 23:45:32 +02:00
|
|
|
return bitboard shl 8
|
2024-04-16 15:24:31 +02:00
|
|
|
of Backward:
|
2024-04-16 23:45:32 +02:00
|
|
|
return bitboard shr 8
|
2024-04-17 11:54:45 +02:00
|
|
|
of ForwardLeft:
|
|
|
|
return bitboard shl 9
|
2024-04-16 15:24:31 +02:00
|
|
|
of ForwardRight:
|
2024-04-16 23:45:32 +02:00
|
|
|
return bitboard shl 7
|
2024-04-16 15:24:31 +02:00
|
|
|
of BackwardRight:
|
2024-04-16 23:45:32 +02:00
|
|
|
return bitboard shr 9
|
2024-04-16 15:24:31 +02:00
|
|
|
of BackwardLeft:
|
2024-04-17 16:50:55 +02:00
|
|
|
return bitboard shr 7
|
|
|
|
of Left:
|
|
|
|
return bitboard shl 1
|
|
|
|
of Right:
|
|
|
|
return bitboard shr 1
|
2024-04-16 15:24:31 +02:00
|
|
|
else:
|
2024-04-16 23:45:32 +02:00
|
|
|
discard
|
|
|
|
|
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func getLastRank*(color: PieceColor): Bitboard {.inline.} = (if color == White: getRankMask(0) else: getRankMask(7))
|
|
|
|
func getFirstRank*(color: PieceColor): Bitboard {.inline.} = (if color == White: getRankMask(7) else: getRankMask(0))
|
|
|
|
func getSecondLastRank*(color: PieceColor): Bitboard {.inline.} = (if color == White: getRankMask(1) else: getRankMask(6))
|
|
|
|
func getSecondRank*(color: PieceColor): Bitboard {.inline.} = (if color == White: getRankMask(6) else: getRankMask(1))
|
|
|
|
func getLeftmostFile*(color: PieceColor): Bitboard {.inline.}= (if color == White: getFileMask(0) else: getFileMask(7))
|
|
|
|
func getRightmostFile*(color: PieceColor): Bitboard {.inline.} = (if color == White: getFileMask(7) else: getFileMask(0))
|
2024-04-17 16:50:55 +02:00
|
|
|
|
2024-04-17 11:54:45 +02:00
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func getDirectionMask*(square: Square, color: PieceColor, direction: Direction): Bitboard {.inline.} =
|
2024-04-16 23:45:32 +02:00
|
|
|
## Get a bitmask for the given direction for a piece
|
|
|
|
## of the given color located at the given square
|
2024-04-17 11:54:45 +02:00
|
|
|
result = getDirectionMask(toBitboard(square), color, direction)
|
2024-04-16 23:45:32 +02:00
|
|
|
|
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func forwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = getDirectionMask(self, side, Forward)
|
|
|
|
func doubleForwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = self.forwardRelativeTo(side).forwardRelativeTo(side)
|
2024-04-16 23:45:32 +02:00
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func backwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = getDirectionMask(self, side, Backward)
|
|
|
|
func doubleBackwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = self.backwardRelativeTo(side).backwardRelativeTo(side)
|
2024-04-16 23:45:32 +02:00
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func leftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = getDirectionMask(self, side, Left) and not getRightmostFile(side)
|
|
|
|
func rightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = getDirectionMask(self, side, Right) and not getLeftmostFile(side)
|
2024-04-17 16:50:55 +02:00
|
|
|
|
2024-04-16 23:45:32 +02:00
|
|
|
|
2024-04-17 20:27:39 +02:00
|
|
|
# We mask off the opposide files to make sure there are
|
|
|
|
# no weird wraparounds when moving diagonally
|
2024-05-13 14:51:21 +02:00
|
|
|
func forwardRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} =
|
2024-04-17 20:27:39 +02:00
|
|
|
getDirectionMask(self, side, ForwardRight) and not getLeftmostFile(side)
|
2024-04-16 23:45:32 +02:00
|
|
|
|
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func forwardLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} =
|
2024-04-17 20:27:39 +02:00
|
|
|
getDirectionMask(self, side, ForwardLeft) and not getRightmostFile(side)
|
2024-04-16 23:45:32 +02:00
|
|
|
|
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func backwardRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} =
|
2024-04-17 20:27:39 +02:00
|
|
|
getDirectionMask(self, side, BackwardRight) and not getLeftmostFile(side)
|
2024-04-17 16:50:55 +02:00
|
|
|
|
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func backwardLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} =
|
2024-04-17 20:27:39 +02:00
|
|
|
getDirectionMask(self, side, BackwardLeft) and not getRightmostFile(side)
|
|
|
|
|
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func longKnightUpLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = self.doubleForwardRelativeTo(side).leftRelativeTo(side)
|
|
|
|
func longKnightUpRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = self.doubleForwardRelativeTo(side).rightRelativeTo(side)
|
|
|
|
func longKnightDownLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = self.doubleBackwardRelativeTo(side).leftRelativeTo(side)
|
|
|
|
func longKnightDownRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = self.doubleBackwardRelativeTo(side).rightRelativeTo(side)
|
2024-04-17 20:27:39 +02:00
|
|
|
|
2024-05-13 14:51:21 +02:00
|
|
|
func shortKnightUpLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = self.forwardRelativeTo(side).leftRelativeTo(side).leftRelativeTo(side)
|
|
|
|
func shortKnightUpRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = self.forwardRelativeTo(side).rightRelativeTo(side).rightRelativeTo(side)
|
|
|
|
func shortKnightDownLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = self.backwardRelativeTo(side).leftRelativeTo(side).leftRelativeTo(side)
|
|
|
|
func shortKnightDownRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard {.inline.} = self.backwardRelativeTo(side).rightRelativeTo(side).rightRelativeTo(side)
|
2024-04-17 20:27:39 +02:00
|
|
|
|
|
|
|
# We precompute as much stuff as possible: lookup tables are fast!
|
|
|
|
|
2024-04-16 23:45:32 +02:00
|
|
|
|
2024-05-01 19:46:28 +02:00
|
|
|
func computeKingBitboards: array[Square(0)..Square(63), Bitboard] {.compileTime.} =
|
2024-04-17 20:27:39 +02:00
|
|
|
## Precomputes all the movement bitboards for the king
|
2024-05-01 19:46:28 +02:00
|
|
|
for i in Square(0)..Square(63):
|
2024-04-17 20:27:39 +02:00
|
|
|
let king = i.toBitboard()
|
|
|
|
# It doesn't really matter which side we generate
|
|
|
|
# the move for, they're identical for both
|
|
|
|
var movements = king.forwardRelativeTo(White)
|
|
|
|
movements = movements or king.forwardLeftRelativeTo(White)
|
|
|
|
movements = movements or king.leftRelativeTo(White)
|
|
|
|
movements = movements or king.rightRelativeTo(White)
|
|
|
|
movements = movements or king.backwardRelativeTo(White)
|
2024-04-19 17:05:18 +02:00
|
|
|
movements = movements or king.forwardRightRelativeTo(White)
|
2024-04-17 20:27:39 +02:00
|
|
|
movements = movements or king.backwardRightRelativeTo(White)
|
|
|
|
movements = movements or king.backwardLeftRelativeTo(White)
|
|
|
|
# We don't *need* to mask the king off: the engine already masks off
|
|
|
|
# the board's occupancy when generating moves, but it may be useful for
|
|
|
|
# other parts of the movegen for this stuff not to say "the king can just
|
|
|
|
# stay still", so we do it anyway
|
|
|
|
movements = movements and not king
|
|
|
|
result[i] = movements
|
|
|
|
|
|
|
|
|
2024-05-01 19:46:28 +02:00
|
|
|
func computeKnightBitboards: array[Square(0)..Square(63), Bitboard] {.compileTime.} =
|
2024-04-17 20:27:39 +02:00
|
|
|
## Precomputes all the movement bitboards for knights
|
2024-05-01 19:46:28 +02:00
|
|
|
for i in Square(0)..Square(63):
|
2024-04-17 20:27:39 +02:00
|
|
|
let knight = i.toBitboard()
|
|
|
|
# It doesn't really matter which side we generate
|
|
|
|
# the move for, they're identical for both
|
|
|
|
var movements = knight.longKnightDownLeftRelativeTo(White)
|
|
|
|
movements = movements or knight.longKnightDownRightRelativeTo(White)
|
|
|
|
movements = movements or knight.longKnightUpLeftRelativeTo(White)
|
|
|
|
movements = movements or knight.longKnightUpRightRelativeTo(White)
|
|
|
|
movements = movements or knight.shortKnightDownLeftRelativeTo(White)
|
|
|
|
movements = movements or knight.shortKnightDownRightRelativeTo(White)
|
|
|
|
movements = movements or knight.shortKnightUpLeftRelativeTo(White)
|
|
|
|
movements = movements or knight.shortKnightUpRightRelativeTo(White)
|
2024-04-19 17:05:18 +02:00
|
|
|
movements = movements and not knight
|
2024-04-17 20:27:39 +02:00
|
|
|
result[i] = movements
|
|
|
|
|
|
|
|
|
2024-05-01 19:46:28 +02:00
|
|
|
func computePawnAttacks(color: PieceColor): array[Square(0)..Square(63), Bitboard] {.compileTime.} =
|
2024-05-01 16:30:21 +02:00
|
|
|
## Precomputes all the attack bitboards for pawns
|
|
|
|
## of the given color
|
2024-05-01 19:46:28 +02:00
|
|
|
for i in Square(0)..Square(63):
|
|
|
|
let pawn = i.toBitboard()
|
|
|
|
result[i] = pawn.backwardLeftRelativeTo(color) or pawn.backwardRightRelativeTo(color)
|
2024-05-01 16:30:21 +02:00
|
|
|
|
2024-05-07 13:40:48 +02:00
|
|
|
|
|
|
|
func computePassedPawnMasks(color: PieceColor): array[Square(0)..Square(63), Bitboard] =
|
|
|
|
## Precomputes all the masks for passed pawns of the
|
|
|
|
## given color
|
|
|
|
for square in Square(0)..Square(63):
|
|
|
|
let file = fileFromSquare(square)
|
|
|
|
let rank = rankFromSquare(square)
|
2024-05-12 14:35:52 +02:00
|
|
|
result[square] = getFileMask(file)
|
|
|
|
if file + 1 in 0..7:
|
|
|
|
result[square] = result[square] or (getFileMask(file + 1))
|
|
|
|
if file - 1 in 0..7:
|
|
|
|
result[square] = result[square] or (getFileMask(file - 1))
|
|
|
|
if color == White:
|
|
|
|
result[square] = result[square] shr (8 * (7 - rank))
|
|
|
|
else:
|
|
|
|
result[square] = result[square] shl (8 * (rank))
|
|
|
|
result[square] = result[square] and not getRankMask(0)
|
|
|
|
result[square] = result[square] and not getRankMask(7)
|
2024-05-07 13:40:48 +02:00
|
|
|
|
|
|
|
|
|
|
|
func computeIsolatedPawnMasks: array[8, Bitboard] {.compileTime.} =
|
|
|
|
## Computes all the masks for isolated pawns
|
|
|
|
for file in 0..7:
|
|
|
|
if file - 1 in 0..7:
|
|
|
|
result[file] = result[file] or getFileMask(file - 1)
|
|
|
|
if file + 1 in 0..7:
|
|
|
|
result[file] = result[file] or getFileMask(file + 1)
|
|
|
|
|
|
|
|
|
2024-04-20 14:51:50 +02:00
|
|
|
const
|
2024-04-20 17:48:18 +02:00
|
|
|
KING_BITBOARDS = computeKingBitboards()
|
|
|
|
KNIGHT_BITBOARDS = computeKnightBitboards()
|
2024-05-01 19:46:28 +02:00
|
|
|
PAWN_ATTACKS: array[PieceColor.White..PieceColor.Black, array[Square(0)..Square(63), Bitboard]] = [computePawnAttacks(White), computePawnAttacks(Black)]
|
2024-05-07 13:40:48 +02:00
|
|
|
ISOLATED_PAWNS = computeIsolatedPawnMasks()
|
|
|
|
|
|
|
|
let PASSED_PAWNS: array[PieceColor.White..PieceColor.Black, array[Square(0)..Square(63), Bitboard]] = [computePassedPawnMasks(White), computePassedPawnMasks(Black)]
|
2024-04-20 14:51:50 +02:00
|
|
|
|
|
|
|
|
2024-05-01 19:46:28 +02:00
|
|
|
func getKingAttacks*(square: Square): Bitboard {.inline.} = KING_BITBOARDS[square]
|
|
|
|
func getKnightAttacks*(square: Square): Bitboard {.inline.} = KNIGHT_BITBOARDS[square]
|
|
|
|
func getPawnAttacks*(color: PieceColor, square: Square): Bitboard {.inline.} = PAWN_ATTACKS[color][square]
|
2024-05-07 13:40:48 +02:00
|
|
|
proc getPassedPawnMask*(color: PieceColor, square: Square): Bitboard {.inline.} = PASSED_PAWNS[color][square]
|
|
|
|
func getIsolatedPawnMask*(file: int): Bitboard {.inline.} = ISOLATED_PAWNS[file]
|