Fixes to how moves are counted and minor style improvements

This commit is contained in:
Mattia Giambirtone 2023-10-17 17:27:33 +02:00
parent a52783fa15
commit 36e9b7d620
2 changed files with 42 additions and 15 deletions

View File

@ -212,6 +212,18 @@ proc getEnPassantTarget*(self: ChessBoard): Location =
return self.position.enPassantSquare.targetSquare return self.position.enPassantSquare.targetSquare
proc getMoveCount*(self: ChessBoard): int =
## Returns the number of full moves that
## have been played
return self.position.fullMoveCount
proc getHalfMoveCount*(self: ChessBoard): int =
## Returns the current number of half-moves
## since the last irreversible move
return self.position.halfMoveClock
func getStartRow(piece: Piece): int {.inline.} = func getStartRow(piece: Piece): int {.inline.} =
## Retrieves the starting row of ## Retrieves the starting row of
## the given piece inside our 8x8 ## the given piece inside our 8x8
@ -467,6 +479,11 @@ func rankToColumn(rank: int): int =
return indeces[rank - 1] return indeces[rank - 1]
func rowToRank(row: int): int =
const indeces = [8, 7, 6, 5, 4, 3, 2, 1]
return indeces[row]
proc algebraicToLocation*(s: string): Location = proc algebraicToLocation*(s: string): Location =
## Converts a square location from algebraic ## Converts a square location from algebraic
## notation to its corresponding row and column ## notation to its corresponding row and column
@ -480,16 +497,16 @@ proc algebraicToLocation*(s: string): Location =
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 file = int(uint8(s[0]) - uint8('a')) let rank = int(uint8(s[0]) - uint8('a'))
# Convert the rank character to a number # Convert the file character to a number
let rank = rankToColumn(int(uint8(s[1]) - uint8('0'))) let file = rankToColumn(int(uint8(s[1]) - uint8('0')))
return (rank, file) return (file, rank)
proc locationToAlgebraic*(loc: Location): string = proc locationToAlgebraic*(loc: Location): string =
## Converts a location from our internal row, column ## Converts a location from our internal row, column
## notation to a square in algebraic notation ## notation to a square in algebraic notation
return &"{char(uint8(loc.col) + uint8('a'))}{char(uint8(loc.row) + uint8('0'))}" return &"{char(uint8(loc.col) + uint8('a'))}{rowToRank(loc.row)}"
proc getPiece*(self: ChessBoard, square: string): Piece = proc getPiece*(self: ChessBoard, square: string): Piece =
@ -961,14 +978,18 @@ proc doMove(self: ChessBoard, move: Move) =
# Final checks # Final checks
# Needed to detect draw by the 50 move rule # Needed to detect draw by the 50 move rule
if move.piece.kind != Pawn and not self.isCapture(move): var
inc(self.position.halfMoveClock) halfMoveClock = self.position.halfMoveClock
fullMoveCount = self.position.fullMoveCount
if move.piece.kind == Pawn or self.isCapture(move):
halfMoveClock = 0
else: else:
self.position.halfMoveClock = 0 inc(halfMoveClock)
if (self.position.halfMoveClock and 1) == 0: # Equivalent to (x mod 2) == 0, just much faster if move.piece.color == Black:
inc(self.position.fullMoveCount) inc(fullMoveCount)
# TODO: Castling # TODO: Castling
# Record the move in the position
self.position.move = move self.position.move = move
# Update position and attack metadata # Update position and attack metadata
@ -979,6 +1000,8 @@ proc doMove(self: ChessBoard, move: Move) =
self.positions.add(self.position) self.positions.add(self.position)
# Create new position with # Create new position with
var newPos = Position(plyFromRoot: self.position.plyFromRoot + 1, var newPos = Position(plyFromRoot: self.position.plyFromRoot + 1,
halfMoveClock: halfMoveClock,
fullMoveCount: fullMoveCount,
captured: emptyPiece(), captured: emptyPiece(),
turn: self.getActiveColor().opposite, turn: self.getActiveColor().opposite,
# Inherit values from current position # Inherit values from current position

View File

@ -13,13 +13,14 @@ when isMainModule:
data: string data: string
move: Move move: Move
echo "\x1Bc"
while true: while true:
echo &"{board.pretty()}" echo &"{board.pretty()}"
echo &"Turn: {board.getActiveColor()}" echo &"Turn: {board.getActiveColor()}"
echo &"Moves: {board.getMoveCount()} full, {board.getHalfMoveCount()} half"
stdout.write(&"En passant target: ") stdout.write(&"En passant target: ")
if board.getEnPassantTarget() != emptyLocation(): if board.getEnPassantTarget() != emptyLocation():
echo board.getEnPassantTarget() echo board.getEnPassantTarget().locationToAlgebraic()
else: else:
echo "None" echo "None"
stdout.write(&"Check: ") stdout.write(&"Check: ")
@ -34,13 +35,16 @@ when isMainModule:
echo "" echo ""
break break
if data == "undo": if data == "undo":
echo &"Undo: {board.undoLastMove()}" echo &"\x1BcUndo: {board.undoLastMove()}"
continue continue
if len(data) != 4: if len(data) != 4:
echo "\x1BcError: invalid move"
continue continue
try: try:
move = board.makeMove(data[0..1], data[2..3]) move = board.makeMove(data[0..1], data[2..3])
except ValueError: except ValueError:
echo &"Error: {getCurrentExceptionMsg()}" echo &"\x1BcError: {getCurrentExceptionMsg()}"
if move == emptyMove(): if move == emptyMove():
echo &"Error: move is illegal" echo &"\x1BcError: move is illegal"
else:
echo "\x1Bc"