Fixes to move handling
This commit is contained in:
parent
f1c09e302e
commit
25ebe7f409
|
@ -47,19 +47,29 @@ type
|
||||||
## A chess piece
|
## A chess piece
|
||||||
color*: PieceColor
|
color*: PieceColor
|
||||||
kind*: PieceKind
|
kind*: PieceKind
|
||||||
|
|
||||||
|
|
||||||
Move* = ref object
|
MoveFlag* = enum
|
||||||
|
## An enumeration of move flags
|
||||||
|
Default, # Move is a regular move
|
||||||
|
XRay, # Move is an X-ray attack
|
||||||
|
# Move is a pawn promotion
|
||||||
|
PromoteToQueen,
|
||||||
|
PromoteToRook,
|
||||||
|
PromoteToBishop,
|
||||||
|
PromoteToKnight
|
||||||
|
|
||||||
|
Move* = object
|
||||||
## A chess move
|
## A chess move
|
||||||
piece*: Piece
|
piece*: Piece
|
||||||
startSquare*: Location
|
startSquare*: Location
|
||||||
targetSquare*: Location
|
targetSquare*: Location
|
||||||
|
flag*: MoveFlag
|
||||||
|
|
||||||
ChessBoard* = ref object
|
ChessBoard* = ref object
|
||||||
## A chess board object
|
## A chess board object
|
||||||
grid: Matrix[Piece]
|
grid: Matrix[Piece]
|
||||||
# Currently active color
|
# Currently active color
|
||||||
turn: PieceColor
|
turn*: PieceColor
|
||||||
# Number of half moves since
|
# Number of half moves since
|
||||||
# last piece capture or pawn movement.
|
# last piece capture or pawn movement.
|
||||||
# Used for the 50-move rule
|
# Used for the 50-move rule
|
||||||
|
@ -72,12 +82,12 @@ type
|
||||||
# En passant target square (see https://en.wikipedia.org/wiki/En_passant)
|
# En passant target square (see https://en.wikipedia.org/wiki/En_passant)
|
||||||
# If en passant is not possible, both the row and
|
# If en passant is not possible, both the row and
|
||||||
# column of the position will be set to -1
|
# column of the position will be set to -1
|
||||||
enPassantSquare: Move
|
enPassantSquare*: Move
|
||||||
# Locations of all pieces
|
# Locations of all pieces
|
||||||
pieces: tuple[white: Pieces, black: Pieces]
|
pieces: tuple[white: Pieces, black: Pieces]
|
||||||
# Locations of all attacked squares and their
|
# Locations of all attacked squares and their
|
||||||
# respective attackers
|
# respective attackers
|
||||||
attacked: tuple[white: seq[tuple[attacker: Piece, loc: Location]], black: seq[tuple[attacker: Piece, loc: Location]]]
|
attacked*: tuple[white: seq[tuple[attacker: Piece, loc: Location]], black: seq[tuple[attacker: Piece, loc: Location]]]
|
||||||
|
|
||||||
|
|
||||||
# Initialized only once, copied every time
|
# Initialized only once, copied every time
|
||||||
|
@ -90,12 +100,110 @@ func emptyPiece*: Piece {.inline.} = Piece(kind: Empty, color: None)
|
||||||
func emptyLocation*: Location {.inline.} = (-1 , -1)
|
func emptyLocation*: Location {.inline.} = (-1 , -1)
|
||||||
func opposite*(c: PieceColor): PieceColor {.inline.} = (if c == White: Black else: White)
|
func opposite*(c: PieceColor): PieceColor {.inline.} = (if c == White: Black else: White)
|
||||||
proc algebraicToPosition*(s: string): Location {.inline.}
|
proc algebraicToPosition*(s: string): Location {.inline.}
|
||||||
func `==`(a, b: Location): bool {.inline.} = a.row == b.row and a.col == b.col
|
|
||||||
proc getCapture*(self: ChessBoard, move: Move): Location
|
proc getCapture*(self: ChessBoard, move: Move): Location
|
||||||
|
func emptyMove*: Move {.inline.} = Move(startSquare: emptyLocation(), targetSquare: emptyLocation(), piece: emptyPiece())
|
||||||
|
|
||||||
var emptyMove = Move(startSquare: emptyLocation(), targetSquare: emptyLocation(), piece: emptyPiece())
|
# Movement offsets for the various pieces. They are
|
||||||
|
# different for each color because the board is an 8x8
|
||||||
|
# grid indexed at 0, which means that white is at the
|
||||||
|
# bottom of the grid going up (indexes are decreasing)
|
||||||
|
# and black is at the top of the grid going down (indeces
|
||||||
|
# are increasing). These offsets are needed to take that
|
||||||
|
# into account when doing move generation or checking for
|
||||||
|
# captures
|
||||||
|
proc getMovementOffsets(self: ChessBoard, location: Location): seq[Location] =
|
||||||
|
let piece = self.grid[location.row, location.col]
|
||||||
|
case piece.color:
|
||||||
|
of White:
|
||||||
|
case piece.kind:
|
||||||
|
of Pawn:
|
||||||
|
# Pawns can move forward one square. In our flipped
|
||||||
|
# board configuration, that means moving up one row
|
||||||
|
# while keeping the column the same
|
||||||
|
if location.row in 1..6 and self.grid[location.row - 1, location.col].color == None:
|
||||||
|
result.add((location.row - 1, location.col))
|
||||||
|
if self.enPassantSquare.piece.color == piece.color.opposite:
|
||||||
|
if abs(self.enPassantSquare.targetSquare.col - location.col) == 1 and abs(self.enPassantSquare.targetSquare.row - location.row) == 1:
|
||||||
|
# Only viable if the piece is on the diagonal of the target
|
||||||
|
result.add(self.enPassantSquare.targetSquare)
|
||||||
|
# They can also move on either diagonal one
|
||||||
|
# square, but only to capture
|
||||||
|
if location.col in 1..6 and location.row in 1..6:
|
||||||
|
if self.grid[location.row + 1, location.col + 1].color == Black:
|
||||||
|
# Top right diagonal (white side)
|
||||||
|
result.add((location.row + 1, location.col + 1))
|
||||||
|
if self.grid[location.row - 1, location.col - 1].color == Black:
|
||||||
|
# Top left diagonal
|
||||||
|
result.add((location.row + 1, location.col + 1))
|
||||||
|
# Pawn is at the right side, can only capture
|
||||||
|
# on the left one
|
||||||
|
elif location.col == 0 and location.row < 7 and self.grid[location.row + 1, location.col + 1].color == Black:
|
||||||
|
result.add((location.row + 1, location.col + 1))
|
||||||
|
# Pawn is at the left side, can only capture
|
||||||
|
# on the right one
|
||||||
|
elif location.col == 7 and location.row < 7 and self.grid[location.row + 1, location.col - 1].color == Black:
|
||||||
|
result.add((location.row - 1, location.col - 1))
|
||||||
|
of Bishop:
|
||||||
|
return @[]
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
of Black:
|
||||||
|
case piece.kind:
|
||||||
|
of Pawn:
|
||||||
|
# Pawns can move forward one square. In our flipped
|
||||||
|
# board configuration, that means moving down one row
|
||||||
|
# while keeping the column the same
|
||||||
|
if location.row in 1..6 and self.grid[location.row - 1, location.col].color == None:
|
||||||
|
result.add((1, 0))
|
||||||
|
if self.enPassantSquare.piece.color == piece.color.opposite:
|
||||||
|
if abs(self.enPassantSquare.targetSquare.col - location.col) == 1 and abs(self.enPassantSquare.targetSquare.row - location.row) == 1:
|
||||||
|
# Only viable if the piece is on the diagonal of the target
|
||||||
|
result.add(self.enPassantSquare.targetSquare)
|
||||||
|
# They can also move on either diagonal one
|
||||||
|
# square, but only to capture
|
||||||
|
if location.col in 1..6 and location.row in 1..6:
|
||||||
|
if self.grid[location.row - 1, location.col - 1].color == White:
|
||||||
|
# Top right diagonal (black side)
|
||||||
|
result.add((1, 1))
|
||||||
|
if self.grid[location.row + 1, location.col + 1].color == White:
|
||||||
|
# Top left diagonal
|
||||||
|
result.add((-1, -1))
|
||||||
|
# Pawn is at the right side, can only capture
|
||||||
|
# on the left one
|
||||||
|
elif location.col > 0 and location.row > 0 and self.grid[location.row - 1, location.col + 1].color == White:
|
||||||
|
result.add((-1, -1))
|
||||||
|
# Pawn is at the left side, can only capture
|
||||||
|
# on the right one
|
||||||
|
elif location.col == 7 and location.row > 0 and self.grid[location.row + 1, location.col + 1].color == White:
|
||||||
|
result.add((1, 1))
|
||||||
|
of Bishop:
|
||||||
|
return @[]
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
|
||||||
|
func getStartRow(piece: Piece): int {.inline.} =
|
||||||
|
## Retrieves the starting row of
|
||||||
|
## the given piece inside our 8x8
|
||||||
|
## grid
|
||||||
|
case piece.color:
|
||||||
|
of None:
|
||||||
|
return -1
|
||||||
|
of White:
|
||||||
|
case piece.kind:
|
||||||
|
of Pawn:
|
||||||
|
return 6
|
||||||
|
else:
|
||||||
|
return 5
|
||||||
|
of Black:
|
||||||
|
case piece.kind:
|
||||||
|
of Pawn:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
proc newChessboard: ChessBoard =
|
proc newChessboard: ChessBoard =
|
||||||
## Returns a new, empty chessboard
|
## Returns a new, empty chessboard
|
||||||
|
@ -103,7 +211,7 @@ proc newChessboard: ChessBoard =
|
||||||
# Turns our flat sequence into an 8x8 grid
|
# Turns our flat sequence into an 8x8 grid
|
||||||
result.grid = newMatrixFromSeq[Piece](empty, (8, 8))
|
result.grid = newMatrixFromSeq[Piece](empty, (8, 8))
|
||||||
result.attacked = (@[], @[])
|
result.attacked = (@[], @[])
|
||||||
result.enPassantSquare = emptyMove
|
result.enPassantSquare = emptyMove()
|
||||||
result.turn = White
|
result.turn = White
|
||||||
|
|
||||||
|
|
||||||
|
@ -293,6 +401,7 @@ proc countPieces*(self: ChessBoard, kind: PieceKind, color: PieceColor): int =
|
||||||
of Queen:
|
of Queen:
|
||||||
return self.pieces.black.queens.len()
|
return self.pieces.black.queens.len()
|
||||||
of King:
|
of King:
|
||||||
|
# In perpetuity
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
@ -342,6 +451,70 @@ proc getPiece*(self: ChessBoard, square: string): Piece =
|
||||||
return self.grid[loc.row, loc.col]
|
return self.grid[loc.row, loc.col]
|
||||||
|
|
||||||
|
|
||||||
|
proc generatePawnMoves(self: ChessBoard, location: Location): seq[Move] =
|
||||||
|
## Generates pawn moves
|
||||||
|
var
|
||||||
|
piece = self.grid[location.row, location.col]
|
||||||
|
doAssert piece.kind == Pawn, &"generatePawnMoves called on a {piece.kind}"
|
||||||
|
for offset in self.getMovementOffsets(location):
|
||||||
|
result.add(Move(startSquare: location, targetSquare: offset, piece: self.grid[location.row, location.col]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proc generateSlidingMoves(self: ChessBoard, location: Location): seq[Move] =
|
||||||
|
## Generates sliding moves
|
||||||
|
var
|
||||||
|
square: Piece
|
||||||
|
piece = self.grid[location.row, location.col]
|
||||||
|
newLocation: Location
|
||||||
|
doAssert piece.kind in [Bishop, Rook, Queen], &"generateSlidingMoves called on a {piece.kind}"
|
||||||
|
for offset in self.getMovementOffsets(location):
|
||||||
|
newLocation = (location.row + offset.row, location.col + offset.col)
|
||||||
|
# Keep sliding until there is a friendly piece or a capture in the way
|
||||||
|
while true:
|
||||||
|
square = self.grid[newLocation.row, newLocation.col]
|
||||||
|
# Friendly piece: cannot move any further
|
||||||
|
if square.color == piece.color:
|
||||||
|
break
|
||||||
|
# Empty square or capture: can do!
|
||||||
|
if square.color == None or square.color == piece.color.opposite():
|
||||||
|
result.add(Move(startSquare: location, targetSquare: newLocation, piece: piece))
|
||||||
|
# Continue in this direction
|
||||||
|
newLocation.row += offset.row
|
||||||
|
# Check if we reached the end of the board
|
||||||
|
if newLocation.row < 0 or newLocation.row > 7:
|
||||||
|
break
|
||||||
|
newLocation.col += offset.col
|
||||||
|
if newLocation.col < 0 or newLocation.col > 7:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proc generateMoves(self: ChessBoard, location: Location): seq[Move] =
|
||||||
|
## Returns the list of possible moves for the
|
||||||
|
## piece in the given location
|
||||||
|
let piece = self.grid[location.row, location.col]
|
||||||
|
case piece.color:
|
||||||
|
of White:
|
||||||
|
case piece.kind:
|
||||||
|
of Pawn:
|
||||||
|
return self.generatePawnMoves(location)
|
||||||
|
of Bishop:
|
||||||
|
return self.generateSlidingMoves(location)
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
of Black:
|
||||||
|
case piece.kind:
|
||||||
|
of Pawn:
|
||||||
|
return self.generatePawnMoves(location)
|
||||||
|
of Bishop:
|
||||||
|
return self.generateSlidingMoves(location)
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
else:
|
||||||
|
return @[]
|
||||||
|
|
||||||
|
|
||||||
proc getCapture*(self: ChessBoard, move: Move): Location =
|
proc getCapture*(self: ChessBoard, move: Move): Location =
|
||||||
## Returns the location that would be captured if this
|
## Returns the location that would be captured if this
|
||||||
## move were played on the board, taking en passant and
|
## move were played on the board, taking en passant and
|
||||||
|
@ -353,9 +526,8 @@ proc getCapture*(self: ChessBoard, move: Move): Location =
|
||||||
if move.targetSquare != self.enPassantSquare.targetSquare:
|
if move.targetSquare != self.enPassantSquare.targetSquare:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
return (self.enPassantSquare.targetSquare.row + 1,
|
return ((if move.piece.color == White: move.targetSquare.row + 1 else: move.targetSquare.row - 1), move.targetSquare.col)
|
||||||
self.enPassantSquare.targetSquare.col)
|
if target.color == move.piece.color.opposite() and move in self.generateMoves(move.startSquare):
|
||||||
if target.color == move.piece.color.opposite():
|
|
||||||
return move.targetSquare
|
return move.targetSquare
|
||||||
|
|
||||||
|
|
||||||
|
@ -379,7 +551,7 @@ proc testMoveOffsets(self: ChessBoard, move: Move): bool =
|
||||||
of Pawn:
|
of Pawn:
|
||||||
if move.targetSquare.col != move.startSquare.col:
|
if move.targetSquare.col != move.startSquare.col:
|
||||||
# Pawn can only change column in case of capture or en passant
|
# Pawn can only change column in case of capture or en passant
|
||||||
if self.enPassantSquare == emptyMove:
|
if self.enPassantSquare == emptyMove():
|
||||||
# No en passant possible, only possibility
|
# No en passant possible, only possibility
|
||||||
# is a capture
|
# is a capture
|
||||||
return self.isCapture(move)
|
return self.isCapture(move)
|
||||||
|
@ -403,15 +575,18 @@ proc testMoveOffsets(self: ChessBoard, move: Move): bool =
|
||||||
if rows == 2:
|
if rows == 2:
|
||||||
# Check if double pawn pushing is possible (only the first
|
# Check if double pawn pushing is possible (only the first
|
||||||
# move for each pawn)
|
# move for each pawn)
|
||||||
let startRow = if move.piece.color == White: 6 else: 1
|
if move.startSquare.row != move.piece.getStartRow():
|
||||||
if move.startSquare.row != startRow:
|
|
||||||
# Pawn has already moved more than once, double push
|
# Pawn has already moved more than once, double push
|
||||||
# is not allowed
|
# is not allowed
|
||||||
return false
|
return false
|
||||||
# En passant is now possible
|
# En passant is now possible
|
||||||
self.enPassantSquare = Move(piece: move.piece, startSquare: move.startSquare,
|
let targetSquare: Location = ((if move.piece.color == White: move.targetSquare.row + 1 else: move.targetSquare.row - 1), move.targetSquare.col)
|
||||||
targetSquare: (move.targetSquare.row - 1, move.targetSquare.col))
|
self.enPassantSquare = Move(piece: move.piece, startSquare: move.startSquare, targetSquare: targetSquare)
|
||||||
return true
|
# Captures are checked earlier, so we only need to make sure we aren't blocked by
|
||||||
|
# a piece
|
||||||
|
return self.grid[move.targetSquare.row, move.targetSquare.col].kind == Empty
|
||||||
|
of Bishop:
|
||||||
|
discard
|
||||||
else:
|
else:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
@ -420,10 +595,70 @@ proc updateAttackedSquares(self: ChessBoard) =
|
||||||
## Updates internal metadata about which squares
|
## Updates internal metadata about which squares
|
||||||
## are attacked. Called internally by doMove
|
## are attacked. Called internally by doMove
|
||||||
|
|
||||||
|
# We refresh the attack metadata at every move. This is an
|
||||||
|
# O(1) operation, because we're only updating the length
|
||||||
|
# field without deallocating the memory, which will promptly
|
||||||
|
# be reused by us again. Neat!
|
||||||
|
self.attacked.white.setLen(0)
|
||||||
|
self.attacked.black.setLen(0)
|
||||||
# Go over each piece one by one and see which squares
|
# Go over each piece one by one and see which squares
|
||||||
# it currently attacks
|
# it currently attacks
|
||||||
for piece in self.pieces.white.pawns:
|
|
||||||
discard
|
# White pawns
|
||||||
|
for loc in self.pieces.white.pawns:
|
||||||
|
for move in self.generateMoves(loc):
|
||||||
|
self.attacked.white.add((move.piece, move.targetSquare))
|
||||||
|
# Black pawns
|
||||||
|
for loc in self.pieces.black.pawns:
|
||||||
|
for move in self.generateMoves(loc):
|
||||||
|
self.attacked.black.add((move.piece, move.targetSquare))
|
||||||
|
# White bishops
|
||||||
|
for loc in self.pieces.white.bishops:
|
||||||
|
for move in self.generateMoves(loc):
|
||||||
|
self.attacked.white.add((move.piece, move.targetSquare))
|
||||||
|
# Black bishops
|
||||||
|
for loc in self.pieces.black.bishops:
|
||||||
|
for move in self.generateMoves(loc):
|
||||||
|
self.attacked.black.add((move.piece, move.targetSquare))
|
||||||
|
|
||||||
|
|
||||||
|
proc getAttackers*(self: ChessBoard, square: string): seq[Piece] =
|
||||||
|
## Returns the attackers of the given square.
|
||||||
|
## If the square has no attackers, an empty
|
||||||
|
## seq is returned
|
||||||
|
let loc = square.algebraicToPosition()
|
||||||
|
case self.turn:
|
||||||
|
of White:
|
||||||
|
for (attacker, location) in self.attacked.black:
|
||||||
|
if location == loc:
|
||||||
|
result.add(attacker)
|
||||||
|
of Black:
|
||||||
|
for (attacker, location) in self.attacked.white:
|
||||||
|
if location == loc:
|
||||||
|
result.add(attacker)
|
||||||
|
else:
|
||||||
|
return @[]
|
||||||
|
|
||||||
|
# We don't use getAttackers because this one only cares about whether
|
||||||
|
# the square is attacked or not (and can therefore exit earlier than
|
||||||
|
# getAttackers)
|
||||||
|
proc isAttacked*(self: ChessBoard, square: string): bool =
|
||||||
|
## Returns whether the given square is attacked
|
||||||
|
## by one of the enemy pieces
|
||||||
|
let loc = square.algebraicToPosition()
|
||||||
|
case self.turn:
|
||||||
|
of White:
|
||||||
|
for (attacker, location) in self.attacked.black:
|
||||||
|
if location == loc:
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
of Black:
|
||||||
|
for (attacker, location) in self.attacked.white:
|
||||||
|
if location == loc:
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
|
||||||
proc removePiece(self: ChessBoard, location: Location) =
|
proc removePiece(self: ChessBoard, location: Location) =
|
||||||
|
@ -472,8 +707,6 @@ proc updatePositions(self: ChessBoard, move: Move) =
|
||||||
## Internal helper to update the position of
|
## Internal helper to update the position of
|
||||||
## the pieces on the board after a move
|
## the pieces on the board after a move
|
||||||
|
|
||||||
# Empty out the starting square
|
|
||||||
self.grid[move.startSquare.row, move.startSquare.col] = emptyPiece()
|
|
||||||
let capture = self.getCapture(move)
|
let capture = self.getCapture(move)
|
||||||
if capture != emptyLocation():
|
if capture != emptyLocation():
|
||||||
# Move has captured a piece: remove the destination square's piece as well.
|
# Move has captured a piece: remove the destination square's piece as well.
|
||||||
|
@ -505,7 +738,7 @@ proc updatePositions(self: ChessBoard, move: Move) =
|
||||||
of King:
|
of King:
|
||||||
self.pieces.white.king = move.targetSquare
|
self.pieces.white.king = move.targetSquare
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
of Black:
|
of Black:
|
||||||
case move.piece.kind:
|
case move.piece.kind:
|
||||||
of Pawn:
|
of Pawn:
|
||||||
|
@ -528,7 +761,9 @@ proc updatePositions(self: ChessBoard, move: Move) =
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
|
# Empty out the starting square
|
||||||
|
self.grid[move.startSquare.row, move.startSquare.col] = emptyPiece()
|
||||||
# Actually move the piece
|
# Actually move the piece
|
||||||
self.grid[move.targetSquare.row, move.targetSquare.col] = move.piece
|
self.grid[move.targetSquare.row, move.targetSquare.col] = move.piece
|
||||||
|
|
||||||
|
@ -542,8 +777,8 @@ proc doMove(self: ChessBoard, move: Move) =
|
||||||
self.updateAttackedSquares()
|
self.updateAttackedSquares()
|
||||||
# En passant is possible only immediately after the
|
# En passant is possible only immediately after the
|
||||||
# pawn has moved
|
# pawn has moved
|
||||||
if self.enPassantSquare != emptyMove and self.enPassantSquare.piece.color == self.turn.opposite():
|
if self.enPassantSquare != emptyMove() and self.enPassantSquare.piece.color == self.turn.opposite():
|
||||||
self.enPassantSquare = emptyMove
|
self.enPassantSquare = emptyMove()
|
||||||
self.turn = self.turn.opposite()
|
self.turn = self.turn.opposite()
|
||||||
|
|
||||||
|
|
||||||
|
@ -554,12 +789,12 @@ proc checkMove(self: ChessBoard, startSquare, targetSquare: string): Move =
|
||||||
# Start square doesn't contain a piece (and it isn't the en passant square)
|
# Start square doesn't contain a piece (and it isn't the en passant square)
|
||||||
# or it is of the wrong color for which turn it is to move
|
# or it is of the wrong color for which turn it is to move
|
||||||
if pieceToMove.kind == Empty or pieceToMove.color != self.turn:
|
if pieceToMove.kind == Empty or pieceToMove.color != self.turn:
|
||||||
return emptyMove
|
return emptyMove()
|
||||||
var destination = self.getPiece(targetSquare)
|
var destination = self.getPiece(targetSquare)
|
||||||
# Destination square is occupied by a piece of the same color as the piece
|
# Destination square is occupied by a piece of the same color as the piece
|
||||||
# being moved: illegal!
|
# being moved: illegal!
|
||||||
if destination.kind != Empty and destination.color == self.turn:
|
if destination.kind != Empty and destination.color == self.turn:
|
||||||
return emptyMove
|
return emptyMove()
|
||||||
var
|
var
|
||||||
startLocation = startSquare.algebraicToPosition()
|
startLocation = startSquare.algebraicToPosition()
|
||||||
targetLocation = targetSquare.algebraicToPosition()
|
targetLocation = targetSquare.algebraicToPosition()
|
||||||
|
@ -568,7 +803,7 @@ proc checkMove(self: ChessBoard, startSquare, targetSquare: string): Move =
|
||||||
# Piece cannot arrive to destination (either
|
# Piece cannot arrive to destination (either
|
||||||
# because it is blocked or because the moving
|
# because it is blocked or because the moving
|
||||||
# pattern is incorrect)
|
# pattern is incorrect)
|
||||||
return emptyMove
|
return emptyMove()
|
||||||
# TODO: Check for checks and pins (moves are currently pseudo-legal)
|
# TODO: Check for checks and pins (moves are currently pseudo-legal)
|
||||||
|
|
||||||
|
|
||||||
|
@ -583,7 +818,7 @@ proc makeMove*(self: ChessBoard, startSquare, targetSquare: string): Move {.disc
|
||||||
## too) and the locations will both be set to the tuple (-1, -1)
|
## too) and the locations will both be set to the tuple (-1, -1)
|
||||||
|
|
||||||
result = self.checkMove(startSquare, targetSquare)
|
result = self.checkMove(startSquare, targetSquare)
|
||||||
if result == emptyMove:
|
if result == emptyMove():
|
||||||
return
|
return
|
||||||
self.doMove(result)
|
self.doMove(result)
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
import board as chess
|
import board as chess
|
||||||
|
|
||||||
# En passant my beloved
|
|
||||||
var board = newDefaultChessboard()
|
var board = newDefaultChessboard()
|
||||||
board.makeMove("a2", "a4")
|
|
||||||
echo board.pretty()
|
|
||||||
board.makeMove("h7", "h5")
|
|
||||||
echo board.pretty()
|
|
||||||
board.makeMove("a4", "a5")
|
|
||||||
echo board.pretty()
|
|
||||||
board.makeMove("b7", "b5")
|
|
||||||
echo board.pretty()
|
|
||||||
board.makeMove("a5", "b6")
|
|
||||||
echo board.pretty()
|
echo board.pretty()
|
||||||
|
|
Loading…
Reference in New Issue