diff --git a/src/Chess/board.nim b/src/Chess/board.nim index ffc27c7..087a3f5 100644 --- a/src/Chess/board.nim +++ b/src/Chess/board.nim @@ -107,6 +107,9 @@ func `+`*(a, b: Location): Location = (a.row + b.row, a.col + b.col) func isValid*(a: Location): bool = a.row in 0..7 and a.col in 0..7 proc generateMoves(self: ChessBoard, location: Location): seq[Move] +# Due to our board layout, directions of movement are reversed for white/black so +# we need these helpers to avoid going mad with integer tuples and minus signs +# everywhere func topLeftDiagonal(piece: Piece): Location {.inline.} = (if piece.color == White: (-1, -1) else: (1, 1)) func topRightDiagonal(piece: Piece): Location {.inline.} = (if piece.color == White: (-1, 1) else: (1, -1)) func bottomLeftDiagonal(piece: Piece): Location {.inline.} = (if piece.color == White: (1, -1) else: (-1, 1)) @@ -115,8 +118,60 @@ func leftSide(piece: Piece): Location {.inline.} = (if piece.color == White: (0, func rightSide(piece: Piece): Location {.inline.} = (if piece.color == White: (0, 1) else: (0, -1)) func topSide(piece: Piece): Location {.inline.} = (if piece.color == White: (-1, 0) else: (1, 0)) func bottomSide(piece: Piece): Location {.inline.} = (if piece.color == White: (1, 0) else: (-1, 0)) -func forward(piece: Piece): Location {.inline.} = (if piece.color == Black: (1, 0) else: (-1, 0)) -func doublePush(piece: Piece): Location {.inline.} = (if piece.color == Black: (2, 0) else: (-2, 0)) +func forward(piece: Piece): Location {.inline.} = (if piece.color == White: (-1, 0) else: (1, 0)) +func doublePush(piece: Piece): Location {.inline.} = (if piece.color == White: (-2, 0) else: (2, 0)) + + +func bottomLeftKnightMove(piece: Piece, long: bool = true): Location {.inline.} = + if piece.color == White: + if long: + return (-2, 1) + else: + return (1, -2) + elif piece.color == Black: + if long: + return (2, -1) + else: + return (1, -2) + + +func bottomRightKnightMove(piece: Piece, long: bool = true): Location {.inline.} = + if piece.color == White: + if long: + return (2, -1) + else: + return (1, 2) + elif piece.color == Black: + if long: + return (2, 1) + else: + return (1, 2) + + +func topLeftKnightMove(piece: Piece, long: bool = true): Location {.inline.} = + if piece.color == White: + if long: + return (-2, -1) + else: + return (-1, -2) + elif piece.color == Black: + if long: + return (2, 1) + else: + return (1, 2) + + +func topRightKnightMove(piece: Piece, long: bool = true): Location {.inline.} = + if piece.color == White: + if long: + return (-2, 1) + else: + return (-1, 2) + elif piece.color == Black: + if long: + return (2, -1) + else: + return (-1, 2) proc getActiveColor*(self: ChessBoard): PieceColor = @@ -556,7 +611,39 @@ proc generateKingMoves(self: ChessBoard, location: Location): seq[Move] = continue # Target square is empty result.add(Move(startSquare: location, targetSquare: square, piece: piece)) - + + +proc generateKnightMoves(self: ChessBoard, location: Location): seq[Move] = + ## Generates moves for the knight in the given location + var + piece = self.grid[location.row, location.col] + doAssert piece.kind == Knight, &"generateKnightMoves called on a {piece.kind}" + var directions: seq[Location] = @[piece.bottomLeftKnightMove(), + piece.bottomRightKnightMove(), + piece.topLeftKnightMove(), + piece.topRightKnightMove(), + piece.bottomLeftKnightMove(long=false), + piece.bottomRightKnightMove(long=false), + piece.topLeftKnightMove(long=false), + piece.topRightKnightMove(long=false)] + for direction in directions: + # Jump to this square + let square: Location = location + direction + # End of board reached + if not square.isValid(): + continue + let otherPiece = self.grid[square.row, square.col] + # A friendly piece is in the way + if otherPiece.color == piece.color: + continue + if otherPiece.color == piece.color.opposite: + # Target square contains an enemy piece: capture + # it + result.add(Move(startSquare: location, targetSquare: square, piece: piece)) + continue + # Target square is empty + result.add(Move(startSquare: location, targetSquare: square, piece: piece)) + proc generateMoves(self: ChessBoard, location: Location): seq[Move] = ## Returns the list of possible legal chess moves for the @@ -569,6 +656,8 @@ proc generateMoves(self: ChessBoard, location: Location): seq[Move] = return self.generatePawnMoves(location) of King: return self.generateKingMoves(location) + of Knight: + return self.generateKnightMoves(location) else: return @[] diff --git a/src/Chess/player.nim b/src/Chess/player.nim index f4cb7c5..eeb3537 100644 --- a/src/Chess/player.nim +++ b/src/Chess/player.nim @@ -35,3 +35,5 @@ when isMainModule: move = board.makeMove(startSquare, targetSquare) except ValueError: echo &"Error: {getCurrentExceptionMsg()}" + if move == emptyMove(): + echo &"Error: move is illegal"