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 b4ef8b4a2e
commit afff1db88f
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
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

View File

@ -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"