## Implements low-level bit operations import std/bitops import std/strutils import pieces type Bitboard* = distinct uint64 ## A bitboard # Overloaded operators and functions for our bitboard type func `shl`*(a: Bitboard, x: Positive): Bitboard = Bitboard(a.uint64 shl x) func `shr`*(a: Bitboard, x: Positive): Bitboard = Bitboard(a.uint64 shr x) func `and`*(a, b: Bitboard): Bitboard = Bitboard(a.uint64 and b.uint64) func `shr`*(a, b: Bitboard): Bitboard = Bitboard(a.uint64 and b.uint64) func `+`*(a, b: Bitboard): Bitboard = Bitboard(a.uint64 + b.uint64) func `-`*(a, b: Bitboard): Bitboard = Bitboard(a.uint64 - b.uint64) func `div`*(a, b: Bitboard): Bitboard = Bitboard(a.uint64 div b.uint64) func `*`*(a, b: Bitboard): Bitboard = Bitboard(a.uint64 * b.uint64) func `+`*(a: Bitboard, b: SomeUnsignedInt): Bitboard = Bitboard(a.uint64 + b) func `-`*(a: Bitboard, b: SomeUnsignedInt): Bitboard = Bitboard(a.uint64 - b.uint64) func `div`*(a: Bitboard, b: SomeUnsignedInt): Bitboard = Bitboard(a.uint64 div b) func `*`*(a: Bitboard, b: SomeUnsignedInt): Bitboard = Bitboard(a.uint64 * b) func `==`*(a, b: Bitboard): bool {.inline.} = a.uint64 == b.uint64 func `==`*(a: Bitboard, b: SomeInteger): bool {.inline.} = a.uint64 == b.uint64 func getFileMask*(file: Positive): Bitboard = Bitboard(0x101010101010101'u64) shl file func getRankMask*(rank: Positive): Bitboard = Bitboard(uint64.high()) shl Positive(8 * (rank + 1)) func squareToBitboard*(square: SomeInteger): Bitboard = Bitboard(1'u64) shl square.uint64 func squareToBitboard*(square: Square): Bitboard = squareToBitboard(coordToIndex(square)) proc bitboardToSquare*(b: Bitboard): Square = Square(b.uint64.countTrailingZeroBits().indexToCoord()) func toBin*(x: Bitboard, b: Positive = 64): string = toBin(BiggestInt(x), b) func toBin*(x: uint64, b: Positive = 64): string = toBin(Bitboard(x), b) iterator items*(self: Bitboard): Square = ## Iterates ove the given bitboard ## and returns all the squares that ## are set var bits = self while bits != 0: yield bits.bitboardToSquare() bits = bits and bits - 1 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 for i, bit in self: if i > 0 and i mod 8 == 0: result &= "\n" result &= $bit func computeDiagonalpieces: array[14, Bitboard] {.compileTime.} = ## Precomputes all the pieces for diagonals ## at compile time result[0] = Bitboard(0x8040201008040201'u64) var col = 1 i = 0 # Left to right while col < 8: result[col] = Bitboard(0x8040201008040201'u64) shl (8 * col) inc(col) inc(i) result[i] = Bitboard(0x102040810204080'u64) inc(i) col = 1 # Right to left while col < 7: result[i] = Bitboard(0x102040810204080'u64) shr (8 * col) inc(i) inc(col) const diagonalpieces = computeDiagonalpieces() func getDirectionMask*(square: Square, color: PieceColor, direction: Direction): Bitboard = ## Get a bitmask for the given direction for a piece ## of the given color case color: of White: case direction: of Forward: return squareToBitboard(square) shl 8 of Backward: return squareToBitboard(square) shr 8 of ForwardRight: return squareToBitboard(square) shl 9 of ForwardLeft: return squareToBitboard(square) shr 9 of BackwardRight: return squareToBitboard(square) shl 17 of BackwardLeft: return squareToBitboard(square) shr 17 else: discard of Black: # The directions for black are just the opposite of those for white, # so we avoid duplicating any code case direction: of Forward: return getDirectionMask(square, White, Backward) of Backward: return getDirectionMask(square, White, Forward) of ForwardRight: return getDirectionMask(square, White, ForwardLeft) of ForwardLeft: return getDirectionMask(square, White, ForwardRight) of BackwardRight: return getDirectionMask(square, White, BackwardLeft) of BackwardLeft: return getDirectionMask(square, White, BackwardRight) else: discard else: discard