CPG/src/Chess/bitboards.nim

148 lines
5.0 KiB
Nim

## 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