chess bugfix: castle and convertToFen

Castling was bugged in the previous version.
The pieces moved on the wrong squares due to W and E being set wrongly.
convertToFen didnt record empty squares if located
at the end of the fen string.
master
TiynGER 4 years ago
parent 23a97ae9fe
commit f6787eedd3

@ -78,8 +78,8 @@ const
## `BKing` is the value assigned to a square in a board with a black king. ## `BKing` is the value assigned to a square in a board with a black king.
N = 10 ## `N` describes a move a field up the board from whites perspective. N = 10 ## `N` describes a move a field up the board from whites perspective.
S = -N ## `S` describes a move a field down the board from whites perspective. S = -N ## `S` describes a move a field down the board from whites perspective.
E = 1 ## `E` describes a move a field to the right from whites perspective. W = 1 ## `W` describes a move a field to the left from whites perspective.
W = -E ## `W` describes a move a field to the left from whites perspective. E = -W ## `E` describes a move a field to the right from whites perspective.
# Directions for the pieces. Special moves are in separate arrays. # Directions for the pieces. Special moves are in separate arrays.
Knight_Moves = @[N+N+E, N+N+W, E+E+N, E+E+S, S+S+E, S+S+W, W+W+N, W+W+S] ## \ Knight_Moves = @[N+N+E, N+N+W, E+E+N, E+E+S, S+S+E, S+S+W, W+W+N, W+W+S] ## \
## `Knight_Moves` describes the possible knight moves. ## `Knight_Moves` describes the possible knight moves.
@ -176,6 +176,8 @@ proc notationToMove*(notation: string, color: Color): Move =
## Convert and return simplified algebraic chess `notation` to a move object, ## Convert and return simplified algebraic chess `notation` to a move object,
## color of player is `color`. ## color of player is `color`.
var move: Move var move: Move
if notation.len < 4:
return getMove(-1, -1, -1, color)
var start = fieldToInd(notation[0..1]) var start = fieldToInd(notation[0..1])
var dest = fieldToInd(notation[2..3]) var dest = fieldToInd(notation[2..3])
move = getMove(start, dest, color) move = getMove(start, dest, color)
@ -183,13 +185,13 @@ proc notationToMove*(notation: string, color: Color): Move =
var promStr = $notation[4] var promStr = $notation[4]
let prom = case promStr: let prom = case promStr:
of "R": of "R":
WRook * ord(color) WRook
of "B": of "B":
WBishop * ord(color) WBishop
of "N": of "N":
WKnight * ord(color) WKnight
else: else:
WQueen * ord(color) WQueen
move = getMove(start, dest, prom, color) move = getMove(start, dest, prom, color)
return move return move
@ -302,7 +304,7 @@ proc convertToFen*(chess: Chess): string =
var fen: string var fen: string
var spaceOcc: int var spaceOcc: int
var fileCounter = 0 var fileCounter = 0
for piece in chess.board.reversed: for i, piece in chess.board.reversed:
if not (piece == Block): if not (piece == Block):
if fileCounter == 8: if fileCounter == 8:
if spaceOcc != 0: if spaceOcc != 0:
@ -318,6 +320,8 @@ proc convertToFen*(chess: Chess): string =
spaceOcc = 0 spaceOcc = 0
pieces &= PieceChar[piece] pieces &= PieceChar[piece]
fileCounter += 1 fileCounter += 1
if i == chess.board.reversed.high and spaceOcc > 0:
pieces &= $spaceOcc
fen &= pieces & " " fen &= pieces & " "
if chess.toMove == Color.White: if chess.toMove == Color.White:
fen &= "w " fen &= "w "
@ -577,30 +581,18 @@ proc uncheckedMove(chess: var Chess, start: int, dest: int): bool {.discardable.
chess.board[start] = 0 chess.board[start] = 0
chess.board[dest] = piece chess.board[dest] = piece
if start == fieldToInd("e1"): if start == fieldToInd("e1"):
if chess.castleRights.wk or chess.castleRights.wq:
chess.previousBoard = @[]
chess.castleRights.wk = false chess.castleRights.wk = false
chess.castleRights.wq = false chess.castleRights.wq = false
elif start == fieldToInd("h1"): elif start == fieldToInd("h1"):
if chess.castleRights.wk:
chess.previousBoard = @[]
chess.castleRights.wk = false chess.castleRights.wk = false
elif start == fieldToInd("a1"): elif start == fieldToInd("a1"):
if chess.castleRights.wq:
chess.previousBoard = @[]
chess.castleRights.wq = false chess.castleRights.wq = false
elif start == fieldToInd("e8"): elif start == fieldToInd("e8"):
if chess.castleRights.bk or chess.castleRights.bq:
chess.previousBoard = @[]
chess.castleRights.bk = false chess.castleRights.bk = false
chess.castleRights.bq = false chess.castleRights.bq = false
elif start == fieldToInd("h8"): elif start == fieldToInd("h8"):
if chess.castleRights.bk:
chess.previousBoard = @[]
chess.castleRights.bk = false chess.castleRights.bk = false
elif start == fieldToInd("a8"): elif start == fieldToInd("a8"):
if chess.castleRights.bq:
chess.previousBoard = @[]
chess.castleRights.bq = false chess.castleRights.bq = false
return true return true
@ -726,37 +718,37 @@ proc castling(chess: var Chess, kstart: int, dest_kingside: bool,
var rdest: int var rdest: int
var rights: bool var rights: bool
if (dest_kingside): if (dest_kingside):
kdest = kstart + (E+E) kdest = kstart + E + E
rstart = kstart + (E+E+E) rstart = kstart + E + E + E
rdest = rstart + (W+W) rdest = rstart + W + W
if (color == Color.White): if (color == Color.White):
rights = chess.castleRights.wk rights = chess.castleRights.wk
else: else:
rights = chess.castleRights.bk rights = chess.castleRights.bk
else: else:
rstart = kstart + (W+W+W+W) kdest = kstart + W + W
rdest = rstart + (E+E+E) rstart = kstart + W + W + W + W
kdest = kstart + (W+W) rdest = rstart + E + E + E
if (color == Color.White): if (color == Color.White):
rights = chess.castleRights.bq rights = chess.castleRights.wq
else: else:
rights = chess.castleRights.bq rights = chess.castleRights.bq
if (rights): if (rights):
var check: bool
if (dest_kingside): if (dest_kingside):
check = check or chess.isAttacked(kstart, color) if chess.isAttacked(kstart, color) or chess.isAttacked(kstart+E, color) or
check = check or chess.isAttacked(kstart+(E), color) chess.isAttacked(kstart+E+E, color) or chess.board[kstart+E] != 0 or
check = check or chess.isAttacked(kstart+(E+E), color) chess.board[kstart+E+E] != 0:
return false
else: else:
check = check or chess.isAttacked(kstart, color) if chess.isAttacked(kstart, color) or chess.isAttacked(kstart+W, color) or
check = check or chess.isAttacked(kstart+(W), color) chess.isAttacked(kstart+W+W, color) or chess.board[kstart+W] != 0 or
check = check or chess.isAttacked(kstart+(W+W), color) chess.board[kstart+W+W] != 0 or chess.board[kstart+W+W+W] != 0:
if check:
return false return false
chess.uncheckedMove(kstart, kdest) chess.uncheckedMove(kstart, kdest)
chess.uncheckedMove(rstart, rdest) chess.uncheckedMove(rstart, rdest)
chess.previousBoard = @[] chess.previousBoard = @[chess.board]
chess.toMove = Color(ord(chess.toMove) * (-1)) chess.toMove = Color(ord(chess.toMove) * (-1))
chess.enPassantSquare = -1
return true return true
return false return false
@ -776,6 +768,10 @@ proc checkedMove*(chess: var Chess, move: Move): bool {.discardable.} =
var fiftyMoveRuleReset: bool var fiftyMoveRuleReset: bool
var move: Move var move: Move
move = getMove(start, dest, color) move = getMove(start, dest, color)
if (piece == WKing * ord(color) and (start - dest == (W+W))):
return chess.castling(start, true, color)
elif (piece == WKing * ord(color) and (start - dest == (E+E))):
return chess.castling(start, false, color)
if (piece == WPawn * ord(color)): if (piece == WPawn * ord(color)):
createEnPassant = dest in chess.genPawnDoubleDests(start, color) createEnPassant = dest in chess.genPawnDoubleDests(start, color)
capturedEnPassant = (dest == chess.enPassantSquare) capturedEnPassant = (dest == chess.enPassantSquare)
@ -784,22 +780,13 @@ proc checkedMove*(chess: var Chess, move: Move): bool {.discardable.} =
fiftyMoveRuleReset = true fiftyMoveRuleReset = true
if (move in chess.genLegalMoves(start, color)): if (move in chess.genLegalMoves(start, color)):
chess.enPassantSquare = -1 chess.enPassantSquare = -1
if (piece == WKing * ord(color) and (start - dest == (W+W))):
return chess.castling(start, true, color)
elif (piece == WKing * ord(color) and (start - dest == (E+E))):
return chess.castling(start, false, color)
else:
chess.uncheckedMove(start, dest) chess.uncheckedMove(start, dest)
chess.toMove = Color(ord(chess.toMove)*(-1)) chess.toMove = Color(ord(chess.toMove)*(-1))
if createEnPassant:
if chess.board[dest + E] == BPawn * ord(color) or
chess.board[dest + W] == BPawn * ord(color):
chess.enPassantSquare = dest - (N * ord(color))
if capturedEnPassant: if capturedEnPassant:
chess.board[dest - (N * ord(color))] = 0 chess.board[dest - (N * ord(color))] = 0
if ((fieldToInd("h8") < dest and dest < fieldToInd("a8")) or if ((fieldToInd("h8") <= dest and dest <= fieldToInd("a8")) or
(fieldToInd("h1") < dest and dest < fieldToInd("a1"))) and (fieldToInd("h1") <= dest and dest <= fieldToInd("a1"))) and
chess.board[dest] == WPawn * ord(color): piece == WPawn * ord(color):
chess.board[dest] = prom chess.board[dest] = prom
chess.previousBoard.add(chess.board) chess.previousBoard.add(chess.board)
chess.halfMoveClock = chess.halfMoveClock + 1 chess.halfMoveClock = chess.halfMoveClock + 1
@ -807,6 +794,10 @@ proc checkedMove*(chess: var Chess, move: Move): bool {.discardable.} =
chess.fullMoveCounter += 1 chess.fullMoveCounter += 1
if fiftyMoveRuleReset: if fiftyMoveRuleReset:
chess.halfMoveClock = 0 chess.halfMoveClock = 0
chess.previousBoard = @[chess.board]
if createEnPassant and (chess.board[dest + E] == BPawn * ord(color) or
chess.board[dest + W] == BPawn * ord(color)):
chess.enPassantSquare = dest - (N * ord(color))
chess.previousBoard = @[] chess.previousBoard = @[]
return true return true

@ -804,9 +804,13 @@ testSuite ChessTest of TestSuite:
self.chess = pos self.chess = pos
test = self.chess.checkedMove(notationToMove("e1c1", Color.White)) test = self.chess.checkedMove(notationToMove("e1c1", Color.White))
self.check(test) self.check(test)
self.check(self.chess.board[fieldToInd("c1")] == WKing)
self.check(self.chess.board[fieldToInd("d1")] == WRook)
self.chess = pos self.chess = pos
self.chess.checkedMove(notationToMove("e1g1", Color.White)) test = self.chess.checkedMove(notationToMove("e1g1", Color.White))
self.check(test) self.check(test)
self.check(self.chess.board[fieldToInd("g1")] == WKing)
self.check(self.chess.board[fieldToInd("f1")] == WRook)
method testCheckedMoveKingCastleTrueBlack() = method testCheckedMoveKingCastleTrueBlack() =
var test: bool var test: bool
@ -814,9 +818,13 @@ testSuite ChessTest of TestSuite:
self.chess = pos self.chess = pos
test = self.chess.checkedMove(notationToMove("e8c8", Color.Black)) test = self.chess.checkedMove(notationToMove("e8c8", Color.Black))
self.check(test) self.check(test)
self.check(self.chess.board[fieldToInd("c8")] == BKing)
self.check(self.chess.board[fieldToInd("d8")] == BRook)
self.chess = pos self.chess = pos
test = self.chess.checkedMove(notationToMove("e8g8", Color.Black)) test = self.chess.checkedMove(notationToMove("e8g8", Color.Black))
self.check(test) self.check(test)
self.check(self.chess.board[fieldToInd("g8")] == BKing)
self.check(self.chess.board[fieldToInd("f8")] == BRook)
method testCheckedMoveKingCastleFalseAlreadyMovedKing() = method testCheckedMoveKingCastleFalseAlreadyMovedKing() =
var test: bool var test: bool

Loading…
Cancel
Save