From afff1db88f950f0408c8333a3a357bc8da52c465 Mon Sep 17 00:00:00 2001 From: Mattia Giambirtone Date: Tue, 17 Oct 2023 17:27:33 +0200 Subject: [PATCH] Fixes to how moves are counted and minor style improvements --- src/Chess/board.nim | 43 +++++++++++++++++++++++++++++++++---------- src/Chess/player.nim | 14 +++++++++----- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/Chess/board.nim b/src/Chess/board.nim index 9a89b7d..7879807 100644 --- a/src/Chess/board.nim +++ b/src/Chess/board.nim @@ -212,6 +212,18 @@ proc getEnPassantTarget*(self: ChessBoard): Location = 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.} = ## Retrieves the starting row of ## the given piece inside our 8x8 @@ -467,6 +479,11 @@ func rankToColumn(rank: int): int = 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 = ## Converts a square location from algebraic ## notation to its corresponding row and column @@ -480,16 +497,16 @@ proc algebraicToLocation*(s: string): Location = if s[1] notin '1'..'8': raise newException(ValueError, &"algebraic position has invalid second character ('{s[1]}')") - let file = int(uint8(s[0]) - uint8('a')) - # Convert the rank character to a number - let rank = rankToColumn(int(uint8(s[1]) - uint8('0'))) - return (rank, file) + let rank = int(uint8(s[0]) - uint8('a')) + # Convert the file character to a number + let file = rankToColumn(int(uint8(s[1]) - uint8('0'))) + return (file, rank) proc locationToAlgebraic*(loc: Location): string = ## Converts a location from our internal row, column ## 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 = @@ -961,14 +978,18 @@ proc doMove(self: ChessBoard, move: Move) = # Final checks # Needed to detect draw by the 50 move rule - if move.piece.kind != Pawn and not self.isCapture(move): - inc(self.position.halfMoveClock) + var + halfMoveClock = self.position.halfMoveClock + fullMoveCount = self.position.fullMoveCount + if move.piece.kind == Pawn or self.isCapture(move): + halfMoveClock = 0 else: - self.position.halfMoveClock = 0 - if (self.position.halfMoveClock and 1) == 0: # Equivalent to (x mod 2) == 0, just much faster - inc(self.position.fullMoveCount) + inc(halfMoveClock) + if move.piece.color == Black: + inc(fullMoveCount) # TODO: Castling + # Record the move in the position self.position.move = move # Update position and attack metadata @@ -979,6 +1000,8 @@ proc doMove(self: ChessBoard, move: Move) = self.positions.add(self.position) # Create new position with var newPos = Position(plyFromRoot: self.position.plyFromRoot + 1, + halfMoveClock: halfMoveClock, + fullMoveCount: fullMoveCount, captured: emptyPiece(), turn: self.getActiveColor().opposite, # Inherit values from current position diff --git a/src/Chess/player.nim b/src/Chess/player.nim index f11ef01..12e4356 100644 --- a/src/Chess/player.nim +++ b/src/Chess/player.nim @@ -13,13 +13,14 @@ when isMainModule: data: string move: Move - + echo "\x1Bc" while true: echo &"{board.pretty()}" echo &"Turn: {board.getActiveColor()}" + echo &"Moves: {board.getMoveCount()} full, {board.getHalfMoveCount()} half" stdout.write(&"En passant target: ") if board.getEnPassantTarget() != emptyLocation(): - echo board.getEnPassantTarget() + echo board.getEnPassantTarget().locationToAlgebraic() else: echo "None" stdout.write(&"Check: ") @@ -34,13 +35,16 @@ when isMainModule: echo "" break if data == "undo": - echo &"Undo: {board.undoLastMove()}" + echo &"\x1BcUndo: {board.undoLastMove()}" continue if len(data) != 4: + echo "\x1BcError: invalid move" continue try: move = board.makeMove(data[0..1], data[2..3]) except ValueError: - echo &"Error: {getCurrentExceptionMsg()}" + echo &"\x1BcError: {getCurrentExceptionMsg()}" if move == emptyMove(): - echo &"Error: move is illegal" + echo &"\x1BcError: move is illegal" + else: + echo "\x1Bc"