Add draw by 50 move rule. Initial work on draw by insufficient material (currently borked)

This commit is contained in:
Mattia Giambirtone 2024-04-13 19:59:54 +02:00
parent 4d4b12a603
commit 7a885b65a0
1 changed files with 66 additions and 1 deletions

View File

@ -124,6 +124,7 @@ func `+`*(a, b: Location): Location = (a.row + b.row, a.col + b.col)
func `-`*(a: Location): Location = (-a.row, -a.col)
func `-`*(a, b: Location): Location = (a.row - b.row, a.col - b.col)
func isValid*(a: Location): bool {.inline.} = a.row in 0..7 and a.col in 0..7
func isLightSquare(a: Location): bool {.inline.} = (a.row + a.col and 2) == 0
proc generateMoves(self: ChessBoard, location: Location): seq[Move]
proc getAttackers*(self: ChessBoard, loc: Location, color: PieceColor): seq[Location]
proc getAttackFor*(self: ChessBoard, source, target: Location): tuple[source, target, direction: Location]
@ -1063,9 +1064,74 @@ proc generateKnightMoves(self: ChessBoard, location: Location): seq[Move] =
result.add(Move(startSquare: location, targetSquare: square))
proc checkInsufficientMaterialPieceCount(self: ChessBoard, color: PieceColor): bool =
## Helper function for checkInsufficientMaterial
let
friendlyPawns = self.countPieces(Piece(kind: Pawn, color: color))
friendlyRooks = self.countPieces(Piece(kind: Rook, color: color))
friendlyQueens = self.countPieces(Piece(kind: Queen, color: color))
friendlyKnights = self.countPieces(Piece(kind: Knight, color: color))
friendlyBishops = self.countPieces(Piece(kind: Bishop, color: color))
enemyPawns = self.countPieces(Piece(kind: Pawn, color: color.opposite()))
enemyRooks = self.countPieces(Piece(kind: Rook, color: color.opposite()))
enemyQueens = self.countPieces(Piece(kind: Queen, color: color.opposite()))
enemyKnights = self.countPieces(Piece(kind: Knight, color: color.opposite()))
enemyBishops = self.countPieces(Piece(kind: Bishop, color: color.opposite()))
if friendlyPawns > 0 or friendlyRooks > 0 or friendlyQueens > 0:
return false
if friendlyKnights >= 2:
return false
if friendlyKnights + friendlyBishops >= 2:
return false
if friendlyKnights >= 1 and (enemyPawns > 0 or enemyRooks > 0 or enemyBishops > 0 or enemyKnights > 0 or enemyQueens > 0):
return false
if friendlyBishops >= 1 and (enemyKnights > 0 or enemyPawns > 0):
return false
return true
proc checkInsufficientMaterial(self: ChessBoard): bool =
## Checks if the given position has not enough material for either side to
## checkmate the enemy king. Note that the criteria as implemented here are
## not fully compliant with FIDE rules (they just define a draw by insufficient
## material as "[...] the position is such that the opponent cannot checkmate
## the players king by any possible series of legal moves.", which is really
## tricky to implement efficiently). For more info see https://www.reddit.com/r/chess/comments/se89db/a_writeup_on_definitions_of_insufficient_material/
if not (self.checkInsufficientMaterialPieceCount(White) and self.checkInsufficientMaterialPieceCount(Black)):
return false
let
whiteBishops = self.countPieces(Piece(kind: Bishop, color: White))
blackBishops = self.countPieces(Piece(kind: Bishop, color: Black))
if blackBishops + whiteBishops >= 2:
var
darkSquare = 0
lightSquare = 0
for bishop in self.position.pieces.black.bishops:
if bishop.isLightSquare():
lightSquare += 1
else:
darkSquare += 1
for bishop in self.position.pieces.white.bishops:
if bishop.isLightSquare():
lightSquare += 1
else:
darkSquare += 1
if darkSquare >= 1 and lightSquare >= 1:
return false
return true
proc generateMoves(self: ChessBoard, location: Location): seq[Move] =
## Returns the list of possible legal chess moves for the
## piece in the given location
if self.position.halfMoveClock == 100:
# Draw by 50-move rule
return @[]
# TODO: Check for draw by insufficient material
#[
if self.checkInsufficientMaterial():
return @[]
]#
let piece = self.grid[location.row, location.col]
case piece.kind:
of Queen, Bishop, Rook:
@ -1079,7 +1145,6 @@ proc generateMoves(self: ChessBoard, location: Location): seq[Move] =
else:
return @[]
proc generateAllMoves*(self: ChessBoard): seq[Move] =
## Returns the list of all possible legal moves
## in the current position