Drop old attack tracking system in preparation for bitboards
This commit is contained in:
parent
c9988cd939
commit
e1ccdc728e
|
@ -104,12 +104,7 @@ type
|
|||
fullMoveCount: int8
|
||||
# En passant target square (see https://en.wikipedia.org/wiki/En_passant)
|
||||
enPassantSquare*: Square
|
||||
# Squares of all pieces
|
||||
pieces: tuple[white, black: Pieces]
|
||||
# Squares attacked by both sides
|
||||
attacked: tuple[white, black: Attacked]
|
||||
# Pieces pinned by both sides (only absolute pins)
|
||||
pinned: tuple[white, black: Attacked]
|
||||
|
||||
# Active color
|
||||
turn: PieceColor
|
||||
|
||||
|
@ -144,18 +139,18 @@ func `-`*(a, b: Square): Square{.inline.} = (a.rank - b.rank, a.file - b.file)
|
|||
func isValid*(a: Square): bool {.inline.} = a.rank in 0..7 and a.file in 0..7
|
||||
func isLightSquare(a: Square): bool {.inline.} = (a.rank + a.file and 2) == 0
|
||||
proc generateMoves(self: ChessBoard, square: Square): seq[Move]
|
||||
proc getAttackers*(self: ChessBoard, square: Square, color: PieceColor): seq[Square]
|
||||
proc getAttackFor*(self: ChessBoard, source, target: Square): tuple[source, target, direction: Square]
|
||||
proc isAttacked*(self: ChessBoard, square: Square, color: PieceColor = None): bool
|
||||
# proc getAttackers*(self: ChessBoard, square: Square, color: PieceColor): seq[Square]
|
||||
# proc getAttackFor*(self: ChessBoard, source, target: Square): tuple[source, target, direction: Square]
|
||||
# proc isAttacked*(self: ChessBoard, square: Square, color: PieceColor = None): bool
|
||||
proc isLegal(self: ChessBoard, move: Move): bool {.inline.}
|
||||
proc doMove(self: ChessBoard, move: Move)
|
||||
proc pretty*(self: ChessBoard): string
|
||||
proc spawnPiece(self: ChessBoard, square: Square, piece: Piece)
|
||||
proc updateAttackedSquares(self: ChessBoard)
|
||||
proc updateSlidingAttacks(self: ChessBoard)
|
||||
proc getPinnedDirections(self: ChessBoard, square: Square): seq[Square]
|
||||
proc getAttacks*(self: ChessBoard, square: Square): Attacked
|
||||
proc getSlidingAttacks(self: ChessBoard, square: Square): tuple[attacks: Attacked, pins: Attacked]
|
||||
# proc updateAttackedSquares(self: ChessBoard)
|
||||
# proc updateSlidingAttacks(self: ChessBoard)
|
||||
# proc getPinnedDirections(self: ChessBoard, square: Square): seq[Square]
|
||||
# proc getAttacks*(self: ChessBoard, square: Square): Attacked
|
||||
# proc getSlidingAttacks(self: ChessBoard, square: Square): tuple[attacks: Attacked, pins: Attacked]
|
||||
proc inCheck*(self: ChessBoard, color: PieceColor = None): bool
|
||||
proc toFEN*(self: ChessBoard): string
|
||||
proc undoLastMove*(self: ChessBoard)
|
||||
|
@ -325,22 +320,8 @@ proc newChessboard: ChessBoard =
|
|||
new(result)
|
||||
for i in 0..63:
|
||||
result.grid[i] = emptyPiece()
|
||||
result.position = Position(attacked: (@[], @[]),
|
||||
enPassantSquare: emptySquare(),
|
||||
turn: White,
|
||||
fullMoveCount: 1,
|
||||
pieces: (white: (king: emptySquare(),
|
||||
queens: @[],
|
||||
rooks: @[],
|
||||
bishops: @[],
|
||||
knights: @[],
|
||||
pawns: @[]),
|
||||
black: (king: emptySquare(),
|
||||
queens: @[],
|
||||
rooks: @[],
|
||||
bishops: @[],
|
||||
knights: @[],
|
||||
pawns: @[])))
|
||||
result.position = Position(enPassantSquare: emptySquare(), turn: White)
|
||||
|
||||
|
||||
# Handy wrappers and utilities for handling low-level stuff
|
||||
func coordToIndex(row, col: SomeInteger): int {.inline.} = (row * 8) + col
|
||||
|
@ -358,6 +339,14 @@ 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
|
||||
|
||||
|
@ -367,6 +356,8 @@ func getRankMask(rank: Positive): Bitboard = Bitboard(uint64.high()) shl Positiv
|
|||
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)
|
||||
|
||||
|
@ -375,9 +366,9 @@ iterator items(self: Bitboard): Square =
|
|||
## Iterates ove the given bitboard
|
||||
## and returns all the squares that
|
||||
## are set
|
||||
var bits = self.uint64
|
||||
var bits = self
|
||||
while bits != 0:
|
||||
yield Square(bits.countTrailingZeroBits().indexToCoord())
|
||||
yield bits.bitboardToSquare()
|
||||
bits = bits and bits - 1
|
||||
|
||||
|
||||
|
@ -668,10 +659,10 @@ proc newChessboardFromFEN*(fen: string): ChessBoard =
|
|||
else:
|
||||
raise newException(ValueError, "invalid FEN: too many fields in FEN string")
|
||||
inc(index)
|
||||
result.updateAttackedSquares()
|
||||
if result.inCheck(result.getActiveColor().opposite):
|
||||
# result.updateAttackedSquares()
|
||||
#[if result.inCheck(result.getActiveColor().opposite):
|
||||
# Opponent king cannot be captured on the next move
|
||||
raise newException(ValueError, "invalid position: opponent king can be captured")
|
||||
raise newException(ValueError, "invalid position: opponent king can be captured")]#
|
||||
if result.position.bitboards.white.king == Bitboard(0) or result.position.bitboards.black.king == Bitboard(0):
|
||||
# Both kings must be on the board
|
||||
raise newException(ValueError, "invalid position: exactly one king of each color must be present")
|
||||
|
@ -854,13 +845,17 @@ func getKing(self: ChessBoard, color: PieceColor = None): Square {.inline.} =
|
|||
color = self.getActiveColor()
|
||||
case color:
|
||||
of White:
|
||||
return self.position.pieces.white.king
|
||||
return self.position.bitboards.white.king.uint64.countTrailingZeroBits().indexToCoord()
|
||||
of Black:
|
||||
return self.position.pieces.black.king
|
||||
return self.position.bitboards.black.king.uint64.countTrailingZeroBits().indexToCoord()
|
||||
else:
|
||||
discard
|
||||
|
||||
# TODO
|
||||
proc inCheck*(self: ChessBoard, color: PieceColor = None): bool = false
|
||||
proc canCastle*(self: ChessBoard, color: PieceColor = None): tuple[queen, king: bool] {.inline.} = (false, false)
|
||||
|
||||
#[
|
||||
proc inCheck*(self: ChessBoard, color: PieceColor = None): bool =
|
||||
## Returns whether the given color's
|
||||
## king is in check. If the color is
|
||||
|
@ -869,7 +864,7 @@ proc inCheck*(self: ChessBoard, color: PieceColor = None): bool =
|
|||
var color = color
|
||||
if color == None:
|
||||
color = self.getActiveColor()
|
||||
case color:
|
||||
#[case color:
|
||||
of White:
|
||||
result = self.isAttacked(self.position.pieces.white.king, Black)
|
||||
of Black:
|
||||
|
@ -877,6 +872,7 @@ proc inCheck*(self: ChessBoard, color: PieceColor = None): bool =
|
|||
else:
|
||||
# Unreachable
|
||||
discard
|
||||
]#
|
||||
|
||||
|
||||
proc inDoubleCheck*(self: ChessBoard, color: PieceColor = None): bool =
|
||||
|
@ -935,11 +931,11 @@ proc canCastle*(self: ChessBoard, color: PieceColor = None): tuple[queen, king:
|
|||
# is temporarily prohibited on that side
|
||||
case color:
|
||||
of White:
|
||||
square = self.position.pieces.white.king
|
||||
square = self.position.bitboards.white.king.bitboardToSquare()
|
||||
queenSide = color.leftSide()
|
||||
kingSide = color.rightSide()
|
||||
of Black:
|
||||
square = self.position.pieces.black.king
|
||||
square = self.position.bitboards.black.king.bitboardToSquare()
|
||||
queenSide = color.rightSide()
|
||||
kingSide = color.leftSide()
|
||||
of None:
|
||||
|
@ -1049,12 +1045,13 @@ proc getCheckResolutions(self: ChessBoard, color: PieceColor): seq[Square] =
|
|||
if not square.isValid():
|
||||
break
|
||||
result.add(square)
|
||||
|
||||
]#
|
||||
|
||||
proc generatePawnMoves(self: ChessBoard, square: Square): seq[Move] =
|
||||
## Generates the possible moves for the pawn in the given
|
||||
## square
|
||||
var
|
||||
|
||||
#[var
|
||||
piece = self.grid[square.rank, square.file]
|
||||
directions: seq[Square] = @[]
|
||||
assert piece.kind == Pawn, &"generatePawnMoves called on a {piece.kind}"
|
||||
|
@ -1136,10 +1133,12 @@ proc generatePawnMoves(self: ChessBoard, square: Square): seq[Move] =
|
|||
result.add(Move(startSquare: square, targetSquare: target, flags: promotionType.uint16 or flags))
|
||||
continue
|
||||
result.add(Move(startSquare: square, targetSquare: target, flags: flags))
|
||||
]#
|
||||
|
||||
|
||||
proc generateSlidingMoves(self: ChessBoard, square: Square): seq[Move] =
|
||||
## Generates moves for the sliding piece in the given square
|
||||
#[
|
||||
let piece = self.grid[square.rank, square.file]
|
||||
assert piece.kind in [Bishop, Rook, Queen], &"generateSlidingMoves called on a {piece.kind}"
|
||||
var directions: seq[Square] = @[]
|
||||
|
@ -1198,10 +1197,12 @@ proc generateSlidingMoves(self: ChessBoard, square: Square): seq[Move] =
|
|||
break
|
||||
# Target square is empty, keep going
|
||||
result.add(Move(startSquare: square, targetSquare: square))
|
||||
]#
|
||||
|
||||
|
||||
proc generateKingMoves(self: ChessBoard, square: Square): seq[Move] =
|
||||
## Generates moves for the king in the given square
|
||||
#[
|
||||
var
|
||||
piece = self.grid[square.rank, square.file]
|
||||
assert piece.kind == King, &"generateKingMoves called on a {piece.kind}"
|
||||
|
@ -1243,10 +1244,12 @@ proc generateKingMoves(self: ChessBoard, square: Square): seq[Move] =
|
|||
# Target square is empty or contains an enemy piece:
|
||||
# All good for us!
|
||||
result.add(Move(startSquare: square, targetSquare: square, flags: flag.uint16))
|
||||
]#
|
||||
|
||||
|
||||
proc generateKnightMoves(self: ChessBoard, square: Square): seq[Move] =
|
||||
## Generates moves for the knight in the given square
|
||||
#[
|
||||
var
|
||||
piece = self.grid[square.rank, square.file]
|
||||
assert piece.kind == Knight, &"generateKnightMoves called on a {piece.kind}"
|
||||
|
@ -1283,6 +1286,7 @@ proc generateKnightMoves(self: ChessBoard, square: Square): seq[Move] =
|
|||
else:
|
||||
# Target square is empty
|
||||
result.add(Move(startSquare: square, targetSquare: square))
|
||||
]#
|
||||
|
||||
|
||||
proc checkInsufficientMaterialPieceCount(self: ChessBoard, color: PieceColor): bool =
|
||||
|
@ -1327,12 +1331,12 @@ proc checkInsufficientMaterial(self: ChessBoard): bool =
|
|||
var
|
||||
darkSquare = 0
|
||||
lightSquare = 0
|
||||
for bishop in self.position.pieces.black.bishops:
|
||||
for bishop in self.position.bitboards.black.bishops:
|
||||
if bishop.isLightSquare():
|
||||
lightSquare += 1
|
||||
else:
|
||||
darkSquare += 1
|
||||
for bishop in self.position.pieces.white.bishops:
|
||||
for bishop in self.position.bitboards.white.bishops:
|
||||
if bishop.isLightSquare():
|
||||
lightSquare += 1
|
||||
else:
|
||||
|
@ -1376,7 +1380,7 @@ proc generateAllMoves*(self: ChessBoard): seq[Move] =
|
|||
for move in self.generateMoves((int8(i), int8(j))):
|
||||
result.add(move)
|
||||
|
||||
|
||||
#[
|
||||
proc isAttacked*(self: ChessBoard, square: Square, color: PieceColor = None): bool =
|
||||
## Returns whether the given square is attacked
|
||||
## by the given color
|
||||
|
@ -1662,7 +1666,7 @@ proc updateAttackedSquares(self: ChessBoard) =
|
|||
self.updateKnightAttacks()
|
||||
# Kings
|
||||
self.updateKingAttacks()
|
||||
|
||||
]#
|
||||
|
||||
proc removePieceFromBitboard(self: ChessBoard, square: Square) =
|
||||
## Removes a piece at the given square in the chessboard from
|
||||
|
@ -1751,8 +1755,8 @@ proc removePiece(self: ChessBoard, square: Square, attack: bool = true) =
|
|||
var piece = self.grid[square]
|
||||
self.grid[square] = emptyPiece()
|
||||
self.removePieceFromBitboard(square)
|
||||
if attack:
|
||||
self.updateAttackedSquares()
|
||||
#[if attack:
|
||||
self.updateAttackedSquares()]#
|
||||
|
||||
|
||||
proc updateMoveBitboards(self: ChessBoard, move: Move) =
|
||||
|
@ -1826,8 +1830,8 @@ proc movePiece(self: ChessBoard, move: Move, attack: bool = true) =
|
|||
self.grid[move.startSquare] = emptyPiece()
|
||||
# Actually move the piece on the board
|
||||
self.grid[move.targetSquare] = piece
|
||||
if attack:
|
||||
self.updateAttackedSquares()
|
||||
#[if attack:
|
||||
self.updateAttackedSquares()]#
|
||||
|
||||
|
||||
proc movePiece(self: ChessBoard, startSquare, targetSquare: Square, attack: bool = true) =
|
||||
|
@ -1925,7 +1929,6 @@ proc doMove(self: ChessBoard, move: Move) =
|
|||
fullMoveCount: fullMoveCount,
|
||||
turn: self.getActiveColor().opposite,
|
||||
castlingAvailable: castlingAvailable,
|
||||
pieces: self.position.pieces,
|
||||
enPassantSquare: enPassantTarget,
|
||||
bitboards: self.position.bitboards
|
||||
)
|
||||
|
@ -1975,7 +1978,7 @@ proc doMove(self: ChessBoard, move: Move) =
|
|||
else:
|
||||
# Unreachable
|
||||
discard
|
||||
self.updateAttackedSquares()
|
||||
#self.updateAttackedSquares()
|
||||
|
||||
|
||||
proc spawnPiece(self: ChessBoard, square: Square, piece: Piece) =
|
||||
|
@ -1993,28 +1996,28 @@ proc updateBoard*(self: ChessBoard) =
|
|||
## in the chessboard
|
||||
for i in 0..63:
|
||||
self.grid[i] = emptyPiece()
|
||||
for sq in self.position.pieces.white.pawns:
|
||||
for sq in self.position.bitboards.white.pawns:
|
||||
self.grid[sq] = Piece(color: White, kind: Pawn)
|
||||
for sq in self.position.pieces.black.pawns:
|
||||
for sq in self.position.bitboards.black.pawns:
|
||||
self.grid[sq] = Piece(color: Black, kind: Pawn)
|
||||
for sq in self.position.pieces.white.bishops:
|
||||
for sq in self.position.bitboards.white.bishops:
|
||||
self.grid[sq] = Piece(color: White, kind: Bishop)
|
||||
for sq in self.position.pieces.black.bishops:
|
||||
for sq in self.position.bitboards.black.bishops:
|
||||
self.grid[sq] = Piece(color: Black, kind: Bishop)
|
||||
for sq in self.position.pieces.white.knights:
|
||||
for sq in self.position.bitboards.white.knights:
|
||||
self.grid[sq] = Piece(color: White, kind: Knight)
|
||||
for sq in self.position.pieces.black.knights:
|
||||
for sq in self.position.bitboards.black.knights:
|
||||
self.grid[sq] = Piece(color: Black, kind: Knight)
|
||||
for sq in self.position.pieces.white.rooks:
|
||||
for sq in self.position.bitboards.white.rooks:
|
||||
self.grid[sq] = Piece(color: White, kind: Rook)
|
||||
for sq in self.position.pieces.black.rooks:
|
||||
for sq in self.position.bitboards.black.rooks:
|
||||
self.grid[sq] = Piece(color: Black, kind: Rook)
|
||||
for sq in self.position.pieces.white.queens:
|
||||
for sq in self.position.bitboards.white.queens:
|
||||
self.grid[sq] = Piece(color: White, kind: Queen)
|
||||
for sq in self.position.pieces.black.queens:
|
||||
for sq in self.position.bitboards.black.queens:
|
||||
self.grid[sq] = Piece(color: Black, kind: Queen)
|
||||
self.grid[self.position.pieces.white.king] = Piece(color: White, kind: King)
|
||||
self.grid[self.position.pieces.black.king] = Piece(color: Black, kind: King)
|
||||
self.grid[self.position.bitboards.white.king.bitboardToSquare()] = Piece(color: White, kind: King)
|
||||
self.grid[self.position.bitboards.black.king.bitboardToSquare()] = Piece(color: Black, kind: King)
|
||||
|
||||
|
||||
proc undoLastMove*(self: ChessBoard) =
|
||||
|
|
Loading…
Reference in New Issue