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

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

Loading…
Cancel
Save