More bug fixing
This commit is contained in:
parent
f65d426ccf
commit
89a96eaf52
|
@ -315,6 +315,8 @@ proc newChessboard: ChessBoard =
|
||||||
func coordToIndex(row, col: int): int {.inline.} = (row * 8) + col
|
func coordToIndex(row, col: int): int {.inline.} = (row * 8) + col
|
||||||
func `[]`(self: seq[Piece], row, column: Natural): Piece {.inline.} = self[coordToIndex(row, column)]
|
func `[]`(self: seq[Piece], row, column: Natural): Piece {.inline.} = self[coordToIndex(row, column)]
|
||||||
proc `[]=`(self: var seq[Piece], row, column: Natural, piece: Piece) {.inline.} = self[coordToIndex(row, column)] = piece
|
proc `[]=`(self: var seq[Piece], row, column: Natural, piece: Piece) {.inline.} = self[coordToIndex(row, column)] = piece
|
||||||
|
func `[]`(self: seq[Piece], loc: Location): Piece {.inline.} = self[loc.row, loc.col]
|
||||||
|
proc `[]=`(self: var seq[Piece], loc: Location, piece: Piece) {.inline.} = self[loc.row, loc.col] = piece
|
||||||
|
|
||||||
|
|
||||||
proc newChessboardFromFEN*(fen: string): ChessBoard =
|
proc newChessboardFromFEN*(fen: string): ChessBoard =
|
||||||
|
@ -717,6 +719,15 @@ proc canCastle*(self: ChessBoard, color: PieceColor = None): tuple[queen, king:
|
||||||
of None:
|
of None:
|
||||||
# Unreachable
|
# Unreachable
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
# We only need to check for attacked squares up until
|
||||||
|
# the point where the king arrives on the target castling
|
||||||
|
# square, but we _also_ need to make sure the path is free
|
||||||
|
# of obstacles for the rook to move past the king. This variable
|
||||||
|
# becomes false once the king has arrived on its target square so
|
||||||
|
# that we don't prevent castling when it would otherwise be allowed
|
||||||
|
# (for an example see r3k2r/p1pNqpb1/bn2pnp1/3P4/1p2P3/2N2Q1p/PPPBBPPP/R3K2R b KQkq - 0 1)
|
||||||
|
var checkAttacks = true
|
||||||
|
|
||||||
if result.king:
|
if result.king:
|
||||||
# Short castle
|
# Short castle
|
||||||
|
@ -734,12 +745,19 @@ proc canCastle*(self: ChessBoard, color: PieceColor = None): tuple[queen, king:
|
||||||
if otherPiece.color != None:
|
if otherPiece.color != None:
|
||||||
result.king = false
|
result.king = false
|
||||||
break
|
break
|
||||||
if self.isAttacked(location, color.opposite()):
|
|
||||||
|
if checkAttacks and self.isAttacked(location, color.opposite()):
|
||||||
result.king = false
|
result.king = false
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# King has arrived at the target square: we no longer
|
||||||
|
# need to check whether subsequent squares are free from
|
||||||
|
# attacks
|
||||||
|
if location == shortCastleKing() + loc:
|
||||||
|
checkAttacks = false
|
||||||
|
|
||||||
if result.queen:
|
if result.queen:
|
||||||
|
checkAttacks = true
|
||||||
# Long castle
|
# Long castle
|
||||||
var
|
var
|
||||||
location = loc
|
location = loc
|
||||||
|
@ -755,10 +773,14 @@ proc canCastle*(self: ChessBoard, color: PieceColor = None): tuple[queen, king:
|
||||||
if otherPiece.color != None:
|
if otherPiece.color != None:
|
||||||
result.queen = false
|
result.queen = false
|
||||||
break
|
break
|
||||||
if self.isAttacked(location, color.opposite()):
|
|
||||||
|
if checkAttacks and self.isAttacked(location, color.opposite()):
|
||||||
result.queen = false
|
result.queen = false
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if location == longCastleKing() + loc:
|
||||||
|
checkAttacks = false
|
||||||
|
|
||||||
|
|
||||||
proc getCheckResolutions(self: ChessBoard, color: PieceColor): seq[Location] =
|
proc getCheckResolutions(self: ChessBoard, color: PieceColor): seq[Location] =
|
||||||
## Returns the squares that need to be covered to
|
## Returns the squares that need to be covered to
|
||||||
|
@ -803,31 +825,32 @@ proc generatePawnMoves(self: ChessBoard, location: Location): seq[Move] =
|
||||||
## location
|
## location
|
||||||
var
|
var
|
||||||
piece = self.grid[location.row, location.col]
|
piece = self.grid[location.row, location.col]
|
||||||
targets: seq[Location] = @[]
|
directions: seq[Location] = @[]
|
||||||
doAssert piece.kind == Pawn, &"generatePawnMoves called on a {piece.kind}"
|
doAssert piece.kind == Pawn, &"generatePawnMoves called on a {piece.kind}"
|
||||||
# Pawns can move forward one square
|
# Pawns can move forward one square
|
||||||
let forward = piece.color.topSide() + location
|
let forward = location + piece.color.topSide()
|
||||||
# Only if the square is empty though
|
# Only if the square is empty though
|
||||||
if forward.isValid() and self.grid[forward.row, forward.col].color == None:
|
if forward.isValid() and self.grid[forward].color == None:
|
||||||
targets.add(forward)
|
directions.add(piece.color.topSide())
|
||||||
# If the pawn is on its first rank, it can push two squares
|
# If the pawn is on its first rank, it can push two squares
|
||||||
if location.row == piece.getStartRow():
|
if location.row == piece.getStartRow():
|
||||||
let double = location + piece.color.doublePush()
|
let double = location + piece.color.doublePush()
|
||||||
# Check that both squares are empty
|
# Check that both squares are empty
|
||||||
if double.isValid() and self.grid[forward.row, forward.col].color == None and self.grid[double.row, double.col].color == None:
|
if double.isValid() and self.grid[forward].color == None and self.grid[double].color == None:
|
||||||
targets.add(double)
|
directions.add(piece.color.doublePush())
|
||||||
let enPassantPawn = self.getEnPassantTarget() + piece.color.opposite().topSide()
|
let enPassantPawn = self.getEnPassantTarget() + piece.color.opposite().topSide()
|
||||||
# They can also move one square on either of their
|
# They can also move one square on either of their
|
||||||
# forward diagonals, but only for captures and en passant
|
# forward diagonals, but only for captures and en passant
|
||||||
for diagonal in [location + piece.color.topRightDiagonal(), location + piece.color.topLeftDiagonal()]:
|
for diagonal in [piece.color.topRightDiagonal(), piece.color.topLeftDiagonal()]:
|
||||||
if diagonal.isValid():
|
let target = location + diagonal
|
||||||
let otherPiece = self.grid[diagonal.row, diagonal.col]
|
if target.isValid():
|
||||||
if diagonal == self.position.enPassantSquare and self.grid[enPassantPawn.row, enPassantPawn.col].color == piece.color.opposite():
|
let otherPiece = self.grid[target]
|
||||||
|
if target == self.position.enPassantSquare and self.grid[enPassantPawn].color == piece.color.opposite():
|
||||||
# Ensure en passant doesn't create a check
|
# Ensure en passant doesn't create a check
|
||||||
let king = self.getKing(piece.color)
|
let king = self.getKing(piece.color)
|
||||||
var ok = true
|
var ok = true
|
||||||
if king.row == location.row:
|
if king.row == location.row:
|
||||||
var current = location + piece.color.rightSide()
|
var current = location
|
||||||
while true:
|
while true:
|
||||||
current = current + piece.color.rightSide()
|
current = current + piece.color.rightSide()
|
||||||
if not current.isValid():
|
if not current.isValid():
|
||||||
|
@ -837,28 +860,30 @@ proc generatePawnMoves(self: ChessBoard, location: Location): seq[Move] =
|
||||||
break
|
break
|
||||||
if p.color == None:
|
if p.color == None:
|
||||||
continue
|
continue
|
||||||
# Bishops can't create checks through en passant
|
# Bishops can't create checks through en passant (neither can knights)
|
||||||
if p.color == piece.color.opposite() and p.kind in [Queen, Rook]:
|
if p.color == piece.color.opposite() and p.kind in [Queen, Rook]:
|
||||||
ok = false
|
ok = false
|
||||||
|
break
|
||||||
if ok:
|
if ok:
|
||||||
targets.add(diagonal)
|
directions.add(diagonal)
|
||||||
elif otherPiece.color == piece.color.opposite() and otherPiece.kind != King:
|
elif otherPiece.color == piece.color.opposite() and otherPiece.kind != King: # Can't capture the king!
|
||||||
targets.add(diagonal)
|
directions.add(diagonal)
|
||||||
# Check for pins
|
# Check for pins
|
||||||
let pinned = self.getPinnedDirections(location)
|
let pinned = self.getPinnedDirections(location)
|
||||||
if pinned.len() > 0:
|
if pinned.len() > 0:
|
||||||
var newTargets: seq[Location] = @[]
|
var newDirections: seq[Location] = @[]
|
||||||
for target in targets:
|
for direction in directions:
|
||||||
if target in pinned:
|
if direction in pinned:
|
||||||
newTargets.add(target)
|
newDirections.add(direction)
|
||||||
targets = newTargets
|
directions = newDirections
|
||||||
let checked = self.inCheck()
|
let checked = self.inCheck()
|
||||||
let resolutions = if not checked: @[] else: self.getCheckResolutions(piece.color)
|
let resolutions = if not checked: @[] else: self.getCheckResolutions(piece.color)
|
||||||
var targetPiece: Piece
|
var targetPiece: Piece
|
||||||
for target in targets:
|
for direction in directions:
|
||||||
|
let target = location + direction
|
||||||
if checked and target notin resolutions:
|
if checked and target notin resolutions:
|
||||||
continue
|
continue
|
||||||
targetPiece = self.grid[target.row, target.col]
|
targetPiece = self.grid[target]
|
||||||
var flags: uint16 = Default.uint16
|
var flags: uint16 = Default.uint16
|
||||||
if targetPiece.color != None:
|
if targetPiece.color != None:
|
||||||
flags = flags or Capture.uint16
|
flags = flags or Capture.uint16
|
||||||
|
@ -1557,6 +1582,7 @@ proc doMove(self: ChessBoard, move: Move) =
|
||||||
self.spawnPiece(move.targetSquare, Piece(kind: Queen, color: piece.color))
|
self.spawnPiece(move.targetSquare, Piece(kind: Queen, color: piece.color))
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
self.updateAttackedSquares()
|
||||||
|
|
||||||
if move.isCapture():
|
if move.isCapture():
|
||||||
# Get rid of captured pieces
|
# Get rid of captured pieces
|
||||||
|
@ -2079,15 +2105,11 @@ proc handlePositionCommand(board: var ChessBoard, command: seq[string]) =
|
||||||
echo board.pretty()
|
echo board.pretty()
|
||||||
|
|
||||||
|
|
||||||
proc handleUCICommand(board: var ChessBoard, command: seq[string]): bool =
|
proc handleUCICommand(board: var ChessBoard, command: seq[string]) =
|
||||||
if len(command) != 1:
|
|
||||||
echo "error: uci: invalid number of arguments"
|
|
||||||
return false
|
|
||||||
echo "id name Nimfish 0.1"
|
echo "id name Nimfish 0.1"
|
||||||
echo "id author Nocturn9x & Contributors (see LICENSE)"
|
echo "id author Nocturn9x & Contributors (see LICENSE)"
|
||||||
# TODO
|
# TODO
|
||||||
echo "uciok"
|
echo "uciok"
|
||||||
return true
|
|
||||||
|
|
||||||
|
|
||||||
const HELP_TEXT = """Nimfish help menu:
|
const HELP_TEXT = """Nimfish help menu:
|
||||||
|
@ -2117,11 +2139,12 @@ const HELP_TEXT = """Nimfish help menu:
|
||||||
- move <move>: Perform the given move in algebraic notation
|
- move <move>: Perform the given move in algebraic notation
|
||||||
- castle: Print castling rights for each side
|
- castle: Print castling rights for each side
|
||||||
- check: Print if the current side to move is in check
|
- check: Print if the current side to move is in check
|
||||||
- undo: Undoes the last move that was performed. Can be used in succession
|
- undo, u: Undoes the last move that was performed. Can be used in succession
|
||||||
- turn: Print which side is to move
|
- turn: Print which side is to move
|
||||||
- ep: Print the current en passant target
|
- ep: Print the current en passant target
|
||||||
- pretty: Shorthand for "position pretty"
|
- pretty: Shorthand for "position pretty"
|
||||||
- print: Shorthand for "position print"
|
- print: Shorthand for "position print"
|
||||||
|
- fen: Shorthand for "position fen" (print only!)
|
||||||
- get <square>: Get the piece on the given square
|
- get <square>: Get the piece on the given square
|
||||||
- uci: enter UCI mode (WIP)
|
- uci: enter UCI mode (WIP)
|
||||||
"""
|
"""
|
||||||
|
@ -2148,8 +2171,8 @@ proc main: int =
|
||||||
|
|
||||||
case cmd[0]:
|
case cmd[0]:
|
||||||
of "uci":
|
of "uci":
|
||||||
if handleUCICommand(board, cmd):
|
handleUCICommand(board, cmd)
|
||||||
uciMode = true
|
uciMode = true
|
||||||
of "clear":
|
of "clear":
|
||||||
echo "\x1Bc"
|
echo "\x1Bc"
|
||||||
of "help":
|
of "help":
|
||||||
|
@ -2160,9 +2183,9 @@ proc main: int =
|
||||||
handlePositionCommand(board, cmd)
|
handlePositionCommand(board, cmd)
|
||||||
of "move":
|
of "move":
|
||||||
handleMoveCommand(board, cmd)
|
handleMoveCommand(board, cmd)
|
||||||
of "pretty", "print":
|
of "pretty", "print", "fen":
|
||||||
handlePositionCommand(board, @["position", cmd[0]])
|
handlePositionCommand(board, @["position", cmd[0]])
|
||||||
of "undo":
|
of "undo", "u":
|
||||||
board.undoLastMove()
|
board.undoLastMove()
|
||||||
of "turn":
|
of "turn":
|
||||||
echo &"Active color: {board.getActiveColor()}"
|
echo &"Active color: {board.getActiveColor()}"
|
||||||
|
|
Loading…
Reference in New Issue