Refactoring of Square handling, removed old code. Initial move generation work on pawns
This commit is contained in:
parent
3e35794ab9
commit
8f54603d08
|
@ -6,17 +6,30 @@ import std/strutils
|
||||||
|
|
||||||
|
|
||||||
import pieces
|
import pieces
|
||||||
|
import moves
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
Bitboard* = distinct uint64
|
Bitboard* = distinct uint64
|
||||||
## A bitboard
|
## A bitboard
|
||||||
|
|
||||||
|
Direction* = enum
|
||||||
|
## A move direction enumeration
|
||||||
|
Forward,
|
||||||
|
Backward,
|
||||||
|
Left,
|
||||||
|
Right
|
||||||
|
ForwardLeft,
|
||||||
|
ForwardRight,
|
||||||
|
BackwardLeft,
|
||||||
|
BackwardRight
|
||||||
|
|
||||||
# Overloaded operators and functions for our bitboard type
|
# Overloaded operators and functions for our bitboard type
|
||||||
func `shl`*(a: Bitboard, x: Positive): Bitboard = Bitboard(a.uint64 shl x)
|
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 `shr`*(a: Bitboard, x: Positive): Bitboard = Bitboard(a.uint64 shr x)
|
||||||
func `and`*(a, b: Bitboard): Bitboard = Bitboard(a.uint64 and b.uint64)
|
func `and`*(a, b: Bitboard): Bitboard = Bitboard(a.uint64 and b.uint64)
|
||||||
|
func `or`*(a, b: Bitboard): Bitboard = Bitboard(a.uint64 or b.uint64)
|
||||||
|
func `not`*(a: Bitboard): Bitboard = Bitboard(not a.uint64)
|
||||||
func `shr`*(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 `-`*(a, b: Bitboard): Bitboard = Bitboard(a.uint64 - b.uint64)
|
func `-`*(a, b: Bitboard): Bitboard = Bitboard(a.uint64 - b.uint64)
|
||||||
|
@ -28,14 +41,27 @@ func `div`*(a: Bitboard, b: SomeUnsignedInt): Bitboard = Bitboard(a.uint64 div b
|
||||||
func `*`*(a: Bitboard, b: SomeUnsignedInt): Bitboard = Bitboard(a.uint64 * b)
|
func `*`*(a: Bitboard, b: SomeUnsignedInt): Bitboard = Bitboard(a.uint64 * b)
|
||||||
func `==`*(a, b: Bitboard): bool {.inline.} = a.uint64 == b.uint64
|
func `==`*(a, b: Bitboard): bool {.inline.} = a.uint64 == b.uint64
|
||||||
func `==`*(a: Bitboard, b: SomeInteger): bool {.inline.} = a.uint64 == b.uint64
|
func `==`*(a: Bitboard, b: SomeInteger): bool {.inline.} = a.uint64 == b.uint64
|
||||||
|
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 getFileMask*(file: int): Bitboard = Bitboard(0x101010101010101'u64) shl file.uint64
|
||||||
func getRankMask*(rank: Positive): Bitboard = Bitboard(uint64.high()) shl Positive(8 * (rank + 1))
|
func getRankMask*(rank: int): Bitboard = Bitboard(uint64.high()) shl uint64(8 * (rank + 1))
|
||||||
func squareToBitboard*(square: SomeInteger): Bitboard = Bitboard(1'u64) shl square.uint64
|
func squareToBitboard*(square: SomeInteger): Bitboard = Bitboard(1'u64) shl square.uint64
|
||||||
func squareToBitboard*(square: Square): Bitboard = squareToBitboard(coordToIndex(square))
|
func squareToBitboard*(square: Square): Bitboard = squareToBitboard(square.int8)
|
||||||
|
|
||||||
|
proc bitboardToSquare*(b: Bitboard): Square = Square(b.uint64.countTrailingZeroBits())
|
||||||
|
func createMove*(startSquare: Bitboard, targetSquare: Square, flags: varargs[MoveFlag]): Move =
|
||||||
|
result = createMove(startSquare.bitboardToSquare(), targetSquare, flags)
|
||||||
|
|
||||||
|
|
||||||
|
func createMove*(startSquare: Square, targetSquare: Bitboard, flags: varargs[MoveFlag]): Move =
|
||||||
|
result = createMove(startSquare, targetSquare.bitboardToSquare(), flags)
|
||||||
|
|
||||||
|
|
||||||
|
func createMove*(startSquare, targetSquare: Bitboard, flags: varargs[MoveFlag]): Move =
|
||||||
|
result = createMove(startSquare.bitboardToSquare(), targetSquare.bitboardToSquare(), flags)
|
||||||
|
|
||||||
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: Bitboard, b: Positive = 64): string = toBin(BiggestInt(x), b)
|
||||||
func toBin*(x: uint64, b: Positive = 64): string = toBin(Bitboard(x), b)
|
func toBin*(x: uint64, b: Positive = 64): string = toBin(Bitboard(x), b)
|
||||||
|
@ -75,15 +101,19 @@ func pretty*(self: Bitboard): string =
|
||||||
|
|
||||||
## Returns a prettyfied version of
|
## Returns a prettyfied version of
|
||||||
## the given bitboard
|
## the given bitboard
|
||||||
|
result &= "- - - - - - - -\n"
|
||||||
for i, bit in self:
|
for i, bit in self:
|
||||||
if i > 0 and i mod 8 == 0:
|
if i > 0 and i mod 8 == 0:
|
||||||
result &= "\n"
|
result &= "\n"
|
||||||
result &= $bit
|
result &= $bit & " "
|
||||||
|
result &= "\n- - - - - - - -"
|
||||||
|
|
||||||
|
|
||||||
func computeDiagonalpieces: array[14, Bitboard] {.compileTime.} =
|
func `$`*(self: Bitboard): string = self.pretty()
|
||||||
## Precomputes all the pieces for diagonals
|
|
||||||
## at compile time
|
|
||||||
|
func computeDiagonalBitboards: array[14, Bitboard] {.compileTime.} =
|
||||||
|
## Precomputes all the bitboards for diagonals
|
||||||
result[0] = Bitboard(0x8040201008040201'u64)
|
result[0] = Bitboard(0x8040201008040201'u64)
|
||||||
var
|
var
|
||||||
col = 1
|
col = 1
|
||||||
|
@ -103,27 +133,28 @@ func computeDiagonalpieces: array[14, Bitboard] {.compileTime.} =
|
||||||
inc(col)
|
inc(col)
|
||||||
|
|
||||||
|
|
||||||
const diagonalpieces = computeDiagonalpieces()
|
const diagonalBitboards = computeDiagonalBitboards()
|
||||||
|
|
||||||
|
|
||||||
func getDirectionMask*(square: Square, color: PieceColor, direction: Direction): Bitboard =
|
func getDirectionMask*(bitboard: Bitboard, color: PieceColor, direction: Direction): Bitboard =
|
||||||
## Get a bitmask for the given direction for a piece
|
## Get a bitmask relative to the given bitboard
|
||||||
## of the given color
|
## for the given direction for a piece of the
|
||||||
|
## given color
|
||||||
case color:
|
case color:
|
||||||
of White:
|
of White:
|
||||||
case direction:
|
case direction:
|
||||||
of Forward:
|
of Forward:
|
||||||
return squareToBitboard(square) shl 8
|
return bitboard shr 8
|
||||||
of Backward:
|
of Backward:
|
||||||
return squareToBitboard(square) shr 8
|
return bitboard shl 8
|
||||||
of ForwardRight:
|
of ForwardRight:
|
||||||
return squareToBitboard(square) shl 9
|
return bitboard shr 7
|
||||||
of ForwardLeft:
|
of ForwardLeft:
|
||||||
return squareToBitboard(square) shr 9
|
return bitboard shr 9
|
||||||
of BackwardRight:
|
of BackwardRight:
|
||||||
return squareToBitboard(square) shl 17
|
return bitboard shl 9
|
||||||
of BackwardLeft:
|
of BackwardLeft:
|
||||||
return squareToBitboard(square) shr 17
|
return bitboard shr 7
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
of Black:
|
of Black:
|
||||||
|
@ -131,18 +162,51 @@ func getDirectionMask*(square: Square, color: PieceColor, direction: Direction):
|
||||||
# so we avoid duplicating any code
|
# so we avoid duplicating any code
|
||||||
case direction:
|
case direction:
|
||||||
of Forward:
|
of Forward:
|
||||||
return getDirectionMask(square, White, Backward)
|
return bitboard shl 8
|
||||||
of Backward:
|
of Backward:
|
||||||
return getDirectionMask(square, White, Forward)
|
return bitboard shr 8
|
||||||
of ForwardRight:
|
of ForwardRight:
|
||||||
return getDirectionMask(square, White, ForwardLeft)
|
return bitboard shl 7
|
||||||
of ForwardLeft:
|
of ForwardLeft:
|
||||||
return getDirectionMask(square, White, ForwardRight)
|
return bitboard shr 9
|
||||||
of BackwardRight:
|
of BackwardRight:
|
||||||
return getDirectionMask(square, White, BackwardLeft)
|
return bitboard shr 9
|
||||||
of BackwardLeft:
|
of BackwardLeft:
|
||||||
return getDirectionMask(square, White, BackwardRight)
|
return bitboard shl 7
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
||||||
|
func getDirectionMask*(square: Square, color: PieceColor, direction: Direction): Bitboard =
|
||||||
|
## Get a bitmask for the given direction for a piece
|
||||||
|
## of the given color located at the given square
|
||||||
|
result = getDirectionMask(squareToBitboard(square), color, direction)
|
||||||
|
|
||||||
|
|
||||||
|
func forwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard = getDirectionMask(self, side, Forward)
|
||||||
|
func doubleForwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard = self.forwardRelativeTo(side).forwardRelativeTo(side)
|
||||||
|
|
||||||
|
func backwardRelativeTo*(self: Bitboard, side: PieceColor): Bitboard = getDirectionMask(self, side, Backward)
|
||||||
|
|
||||||
|
|
||||||
|
# We mask off the first and last ranks/files for
|
||||||
|
# left and right movements respectively to
|
||||||
|
# avoid weird wraparounds
|
||||||
|
func topRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
||||||
|
getDirectionMask(self, side, ForwardRight) and not getFileMask(7)
|
||||||
|
|
||||||
|
|
||||||
|
func topLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
||||||
|
getDirectionMask(self, side, ForwardLeft) and not getFileMask(0)
|
||||||
|
|
||||||
|
|
||||||
|
func bottomRightRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
||||||
|
let lastRank = if side == White: getRankMask(0) else: getRankMask(7)
|
||||||
|
getDirectionMask(self, side, BackwardRight) and not lastRank
|
||||||
|
|
||||||
|
|
||||||
|
func bottomLeftRelativeTo*(self: Bitboard, side: PieceColor): Bitboard =
|
||||||
|
let lastRank = if side == White: getRankMask(0) else: getRankMask(7)
|
||||||
|
getDirectionMask(self, side, BackwardLeft) and not getRankMask(7)
|
1134
src/Chess/board.nim
1134
src/Chess/board.nim
File diff suppressed because it is too large
Load Diff
|
@ -29,6 +29,12 @@ type
|
||||||
data: array[218, Move]
|
data: array[218, Move]
|
||||||
len: int8
|
len: int8
|
||||||
|
|
||||||
|
func `[]`*(self: MoveList, i: SomeInteger): Move =
|
||||||
|
when not defined(danger):
|
||||||
|
if i >= self.len:
|
||||||
|
raise newException(IndexDefect, &"move list access out of bounds ({i} >= {self.len})")
|
||||||
|
result = self.data[i]
|
||||||
|
|
||||||
|
|
||||||
iterator items*(self: MoveList): Move =
|
iterator items*(self: MoveList): Move =
|
||||||
var i = 0
|
var i = 0
|
||||||
|
@ -48,6 +54,10 @@ func add*(self: var MoveList, move: Move) {.inline.} =
|
||||||
inc(self.len)
|
inc(self.len)
|
||||||
|
|
||||||
|
|
||||||
|
func clear*(self: var MoveList) {.inline.} =
|
||||||
|
self.len = 0
|
||||||
|
|
||||||
|
|
||||||
func contains*(self: MoveList, move: Move): bool {.inline.} =
|
func contains*(self: MoveList, move: Move): bool {.inline.} =
|
||||||
for item in self:
|
for item in self:
|
||||||
if move == item:
|
if move == item:
|
||||||
|
@ -58,17 +68,22 @@ func contains*(self: MoveList, move: Move): bool {.inline.} =
|
||||||
func len*(self: MoveList): int {.inline.} = self.len
|
func len*(self: MoveList): int {.inline.} = self.len
|
||||||
|
|
||||||
|
|
||||||
func createMove*(startSquare, targetSquare: string, flags: seq[MoveFlag] = @[]): Move =
|
# A bunch of move creation utilities
|
||||||
result = Move(startSquare: startSquare.algebraicToSquare(),
|
|
||||||
targetSquare: targetSquare.algebraicToSquare(), flags: Default.uint16)
|
|
||||||
for flag in flags:
|
|
||||||
result.flags = result.flags or flag.uint16
|
|
||||||
|
|
||||||
|
func createMove*(startSquare, targetSquare: Square, flags: varargs[MoveFlag]): Move =
|
||||||
func createMove*(startSquare, targetSquare: Square, flags: seq[MoveFlag] = @[]): Move =
|
|
||||||
result = Move(startSquare: startSquare, targetSquare: targetSquare, flags: Default.uint16)
|
result = Move(startSquare: startSquare, targetSquare: targetSquare, flags: Default.uint16)
|
||||||
for flag in flags:
|
for flag in flags:
|
||||||
result.flags = result.flags or flag.uint16
|
result.flags = result.flags or flag.uint16
|
||||||
|
|
||||||
|
proc createMove*(startSquare, targetSquare: string, flags: varargs[MoveFlag]): Move =
|
||||||
|
result = createMove(startSquare.toSquare(), targetSquare.toSquare(), flags)
|
||||||
|
|
||||||
|
func createMove*(startSquare, targetSquare: SomeInteger, flags: varargs[MoveFlag]): Move =
|
||||||
|
result = createMove(Square(startSquare.int8), Square(targetSquare.int8), flags)
|
||||||
|
|
||||||
|
|
||||||
|
func createMove*(startSquare: Square, targetSquare: SomeInteger, flags: varargs[MoveFlag]): Move =
|
||||||
|
result = createMove(startSquare, Square(targetSquare.int8), flags)
|
||||||
|
|
||||||
|
|
||||||
func nullMove*: Move {.inline.} = createMove(nullSquare(), nullSquare())
|
func nullMove*: Move {.inline.} = createMove(nullSquare(), nullSquare())
|
|
@ -4,7 +4,7 @@ import std/strformat
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
Square* = tuple[rank, file: int8]
|
Square* = distinct int8
|
||||||
## A square
|
## A square
|
||||||
|
|
||||||
PieceColor* = enum
|
PieceColor* = enum
|
||||||
|
@ -23,55 +23,33 @@ type
|
||||||
Queen = 'q',
|
Queen = 'q',
|
||||||
Rook = 'r',
|
Rook = 'r',
|
||||||
|
|
||||||
Direction* = enum
|
|
||||||
## A move direction enumeration
|
|
||||||
Forward,
|
|
||||||
Backward,
|
|
||||||
Left,
|
|
||||||
Right
|
|
||||||
ForwardLeft,
|
|
||||||
ForwardRight,
|
|
||||||
BackwardLeft,
|
|
||||||
BackwardRight
|
|
||||||
|
|
||||||
Piece* = object
|
Piece* = object
|
||||||
## A chess piece
|
## A chess piece
|
||||||
color*: PieceColor
|
color*: PieceColor
|
||||||
kind*: PieceKind
|
kind*: PieceKind
|
||||||
|
|
||||||
|
|
||||||
func coordToIndex*(row, col: SomeInteger): int {.inline.} = (row * 8) + col
|
|
||||||
func coordToIndex*(square: Square): int {.inline.} = coordToIndex(square.rank, square.file)
|
|
||||||
func indexToCoord*(index: SomeInteger): Square {.inline.} = ((index div 8).int8, (index mod 8).int8)
|
|
||||||
func nullPiece*: Piece {.inline.} = Piece(kind: Empty, color: None)
|
func nullPiece*: Piece {.inline.} = Piece(kind: Empty, color: None)
|
||||||
func nullSquare*: Square {.inline.} = (-1 , -1)
|
func nullSquare*: Square {.inline.} = Square(-1'i8)
|
||||||
func opposite*(c: PieceColor): PieceColor {.inline.} = (if c == White: Black else: White)
|
func opposite*(c: PieceColor): PieceColor {.inline.} = (if c == White: Black else: White)
|
||||||
func `+`*(a, b: Square): Square {.inline.} = (a.rank + b.rank, a.file + b.file)
|
func isValid*(a: Square): bool {.inline.} = a.int8 in 0..63
|
||||||
func `-`*(a: Square): Square {.inline.} = (-a.rank, -a.file)
|
func isLightSquare*(a: Square): bool {.inline.} = (a.int8 and 2) == 0
|
||||||
func `-`*(a, b: Square): Square{.inline.} = (a.rank - b.rank, a.file - b.file)
|
func `==`*(a, b: Square): bool {.inline.} = a.int8 == b.int8
|
||||||
func isValid*(a: Square): bool {.inline.} = a.rank in 0..7 and a.file in 0..7
|
func `!=`*(a, b: Square): bool {.inline.} = a.int8 != b.int8
|
||||||
func isLightSquare*(a: Square): bool {.inline.} = (a.rank + a.file and 2) == 0
|
func `-`*(a, b: Square): Square {.inline.} = Square(a.int8 - b.int8)
|
||||||
func makeSquare*(rank, file: SomeInteger): Square = (rank: rank.int8, file: file.int8)
|
func `-`*(a: Square, b: SomeInteger): Square {.inline.} = Square(a.int8 - b.int8)
|
||||||
|
func `-`*(a: SomeInteger, b: Square): Square {.inline.} = Square(a.int8 - b.int8)
|
||||||
|
|
||||||
|
|
||||||
func fileToColumn*(file: int): int8 {.inline.} =
|
func colFromSquare*(square: Square): int8 = square.int8 mod 8 + 1
|
||||||
## Converts a chess file (1-indexed)
|
func rowFromSquare*(square: Square): int8 = square.int8 div 8 + 1
|
||||||
## into a 0-indexed column value for our
|
|
||||||
## board. This converter is necessary because
|
|
||||||
## chess positions are indexed differently with
|
|
||||||
## respect to our internal representation
|
|
||||||
const indeces: array[8, int8] = [7, 6, 5, 4, 3, 2, 1, 0]
|
|
||||||
return indeces[file - 1]
|
|
||||||
|
|
||||||
|
|
||||||
func rowToRank*(row: int): int8 {.inline.} =
|
|
||||||
## Converts a row into our grid into
|
func makeSquare*(rank, file: SomeInteger): Square = Square(rank * 8 + file)
|
||||||
## a chess rank
|
|
||||||
const indeces: array[8, int8] = [8, 7, 6, 5, 4, 3, 2, 1]
|
|
||||||
return indeces[row]
|
|
||||||
|
|
||||||
|
|
||||||
func algebraicToSquare*(s: string): Square =
|
proc toSquare*(s: string): Square {.discardable.} =
|
||||||
## Converts a square square from algebraic
|
## Converts a square square from algebraic
|
||||||
## notation to its corresponding row and column
|
## notation to its corresponding row and column
|
||||||
## in the chess grid (0 indexed)
|
## in the chess grid (0 indexed)
|
||||||
|
@ -84,13 +62,16 @@ func algebraicToSquare*(s: string): Square =
|
||||||
if s[1] notin '1'..'8':
|
if s[1] notin '1'..'8':
|
||||||
raise newException(ValueError, &"algebraic position has invalid second character ('{s[1]}')")
|
raise newException(ValueError, &"algebraic position has invalid second character ('{s[1]}')")
|
||||||
|
|
||||||
let rank = int8(uint8(s[0]) - uint8('a'))
|
return Square((s[0].uint8 - uint8('a')) + ((s[1].uint8 - uint8('1')) xor 7) * 8)
|
||||||
# Convert the file character to a number
|
|
||||||
let file = fileToColumn(int8(uint8(s[1]) - uint8('0')))
|
|
||||||
return (file, rank)
|
|
||||||
|
|
||||||
|
|
||||||
func squareToAlgebraic*(square: Square): string {.inline.} =
|
proc toAlgebraic*(square: Square): string {.inline.} =
|
||||||
## Converts a square from our internal rank/file
|
## Converts a square from our internal rank/file
|
||||||
## notation to a square in algebraic notation
|
## notation to a square in algebraic notation
|
||||||
return &"{rowToRank(square.rank)}{char(uint8(square.file) + uint8('a'))}"
|
let
|
||||||
|
file = char('a'.uint8 + (square.uint64 and 7))
|
||||||
|
rank = char('1'.uint8 + ((square.uint64 div 8) xor 7))
|
||||||
|
return &"{file}{rank}"
|
||||||
|
|
||||||
|
|
||||||
|
proc `$`*(square: Square): string = square.toAlgebraic()
|
Loading…
Reference in New Issue