Refactored piece location storage and added test for it
This commit is contained in:
parent
9af32e5e40
commit
d3cc7bddde
|
@ -21,15 +21,15 @@ import std/strformat
|
||||||
|
|
||||||
type
|
type
|
||||||
Location = tuple[row, col: int]
|
Location = tuple[row, col: int]
|
||||||
Pieces = tuple[king: Location, queen: Location, rooks: array[2, Location],
|
Pieces = tuple[king: Location, queen: Location, rooks: seq[Location],
|
||||||
bishops: array[2, Location], knights: array[2, Location],
|
bishops: seq[Location], knights: seq[Location],
|
||||||
pawns: array[8, Location]]
|
pawns: seq[Location]]
|
||||||
PieceColor* = enum
|
PieceColor* = enum
|
||||||
None = 0,
|
None = 0,
|
||||||
White,
|
White,
|
||||||
Black
|
Black
|
||||||
PieceKind* = enum
|
PieceKind* = enum
|
||||||
Empty = 0, # No piece
|
Empty = '\0', # No piece
|
||||||
Bishop = 'b',
|
Bishop = 'b',
|
||||||
King = 'k'
|
King = 'k'
|
||||||
Knight = 'n',
|
Knight = 'n',
|
||||||
|
@ -39,12 +39,13 @@ type
|
||||||
Piece* = object
|
Piece* = object
|
||||||
color*: PieceColor
|
color*: PieceColor
|
||||||
kind*: PieceKind
|
kind*: PieceKind
|
||||||
|
captured*: bool
|
||||||
Position* = object
|
Position* = object
|
||||||
piece*: Piece
|
piece*: Piece
|
||||||
location*: Location
|
location*: Location
|
||||||
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
|
||||||
|
@ -72,6 +73,53 @@ for _ in countup(0, 63):
|
||||||
empty.add(Piece(kind: Empty, color: None))
|
empty.add(Piece(kind: Empty, color: None))
|
||||||
|
|
||||||
|
|
||||||
|
proc countPieces*(self: ChessBoard, kind: PieceKind, color: PieceColor): int =
|
||||||
|
## Counts the number of pieces with
|
||||||
|
## the given color and type
|
||||||
|
case color:
|
||||||
|
of White:
|
||||||
|
case kind:
|
||||||
|
of Pawn:
|
||||||
|
return self.pieces.white.pawns.len()
|
||||||
|
of Bishop:
|
||||||
|
return self.pieces.white.bishops.len()
|
||||||
|
of Knight:
|
||||||
|
return self.pieces.white.knights.len()
|
||||||
|
of Rook:
|
||||||
|
return self.pieces.white.rooks.len()
|
||||||
|
of Queen:
|
||||||
|
return int(self.pieces.white.queen != (-1, -1))
|
||||||
|
of King:
|
||||||
|
# There shall be only one, forever
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
of Black:
|
||||||
|
case kind:
|
||||||
|
of Pawn:
|
||||||
|
return self.pieces.black.pawns.len()
|
||||||
|
of Bishop:
|
||||||
|
return self.pieces.black.bishops.len()
|
||||||
|
of Knight:
|
||||||
|
return self.pieces.black.knights.len()
|
||||||
|
of Rook:
|
||||||
|
return self.pieces.black.rooks.len()
|
||||||
|
of Queen:
|
||||||
|
return int(self.pieces.black.queen != (-1, -1))
|
||||||
|
of King:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
of None:
|
||||||
|
raise newException(ValueError, "invalid piece type")
|
||||||
|
|
||||||
|
|
||||||
|
proc countPieces*(self: ChessBoard, piece: Piece): int =
|
||||||
|
## Returns the number of pieces on the board that
|
||||||
|
## are of the same type and color of the given piece
|
||||||
|
return self.countPieces(piece.kind, piece.color)
|
||||||
|
|
||||||
|
|
||||||
func rankToColumn(rank: int): int =
|
func rankToColumn(rank: int): int =
|
||||||
## Converts a chess rank (1-indexed)
|
## Converts a chess rank (1-indexed)
|
||||||
## into a 0-indexed column value for our
|
## into a 0-indexed column value for our
|
||||||
|
@ -110,7 +158,6 @@ proc getPiece*(self: ChessBoard, square: string): Piece =
|
||||||
|
|
||||||
proc `$`*(self: ChessBoard): string =
|
proc `$`*(self: ChessBoard): string =
|
||||||
result &= "- - - - - - - -"
|
result &= "- - - - - - - -"
|
||||||
#const indeces = [7, 6, 5, 4, 3, 2, 1, 0]
|
|
||||||
for i, row in self.grid:
|
for i, row in self.grid:
|
||||||
result &= "\n"
|
result &= "\n"
|
||||||
for piece in row:
|
for piece in row:
|
||||||
|
@ -129,20 +176,6 @@ proc `$`*(self: ChessBoard): string =
|
||||||
proc newChessboard: ChessBoard =
|
proc newChessboard: ChessBoard =
|
||||||
## Returns a new, empty chessboard
|
## Returns a new, empty chessboard
|
||||||
new(result)
|
new(result)
|
||||||
# Initialize all positions to a known default state.
|
|
||||||
# This is useful in newChessBoardFromFEN
|
|
||||||
result.pieces.black.king = (-1, -1)
|
|
||||||
result.pieces.white.king = (-1, -1)
|
|
||||||
result.pieces.black.queen = (-1, -1)
|
|
||||||
result.pieces.white.queen = (-1, -1)
|
|
||||||
result.pieces.black.rooks = [(-1, -1), (-1, -1)]
|
|
||||||
result.pieces.white.rooks = [(-1, -1), (-1, -1)]
|
|
||||||
result.pieces.black.bishops = [(-1, -1), (-1, -1)]
|
|
||||||
result.pieces.white.bishops = [(-1, -1), (-1, -1)]
|
|
||||||
result.pieces.black.knights = [(-1, -1), (-1, -1)]
|
|
||||||
result.pieces.white.knights = [(-1, -1), (-1, -1)]
|
|
||||||
result.pieces.black.pawns = [(-1, -1), (-1, -1), (-1, -1), (-1, -1), (-1, -1), (-1, -1), (-1, -1), (-1, -1)]
|
|
||||||
result.pieces.white.pawns = [(-1, -1), (-1, -1), (-1, -1), (-1, -1), (-1, -1), (-1, -1), (-1, -1), (-1, -1)]
|
|
||||||
# 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 = (@[], @[])
|
||||||
|
@ -187,26 +220,13 @@ proc newChessboardFromFEN*(state: string): ChessBoard =
|
||||||
of Black:
|
of Black:
|
||||||
case piece.kind:
|
case piece.kind:
|
||||||
of Pawn:
|
of Pawn:
|
||||||
# Find first empty slot in the pieces array
|
result.pieces.black.pawns.add((row, column))
|
||||||
for i, e in result.pieces.black.pawns:
|
|
||||||
if e == (-1, -1):
|
|
||||||
result.pieces.black.pawns[i] = (row, column)
|
|
||||||
break
|
|
||||||
of Bishop:
|
of Bishop:
|
||||||
if result.pieces.black.bishops[0] == (-1, -1):
|
result.pieces.black.bishops.add((row, column))
|
||||||
result.pieces.black.bishops[0] = (row, column)
|
|
||||||
else:
|
|
||||||
result.pieces.black.bishops[1] = (row, column)
|
|
||||||
of Knight:
|
of Knight:
|
||||||
if result.pieces.black.knights[0] == (-1, -1):
|
result.pieces.black.knights.add((row, column))
|
||||||
result.pieces.black.knights[0] = (row, column)
|
|
||||||
else:
|
|
||||||
result.pieces.black.knights[1] = (row, column)
|
|
||||||
of Rook:
|
of Rook:
|
||||||
if result.pieces.black.rooks[0] == (-1, -1):
|
result.pieces.black.rooks.add((row, column))
|
||||||
result.pieces.black.rooks[0] = (row, column)
|
|
||||||
else:
|
|
||||||
result.pieces.black.rooks[1] = (row, column)
|
|
||||||
of Queen:
|
of Queen:
|
||||||
result.pieces.black.queen = (row, column)
|
result.pieces.black.queen = (row, column)
|
||||||
of King:
|
of King:
|
||||||
|
@ -216,25 +236,13 @@ proc newChessboardFromFEN*(state: string): ChessBoard =
|
||||||
of White:
|
of White:
|
||||||
case piece.kind:
|
case piece.kind:
|
||||||
of Pawn:
|
of Pawn:
|
||||||
for i, e in result.pieces.white.pawns:
|
result.pieces.white.pawns.add((row, column))
|
||||||
if e == (-1, -1):
|
|
||||||
result.pieces.white.pawns[i] = (row, column)
|
|
||||||
break
|
|
||||||
of Bishop:
|
of Bishop:
|
||||||
if result.pieces.white.bishops[0] == (-1, -1):
|
result.pieces.white.bishops.add((row, column))
|
||||||
result.pieces.white.bishops[0] = (row, column)
|
|
||||||
else:
|
|
||||||
result.pieces.white.bishops[1] = (row, column)
|
|
||||||
of Knight:
|
of Knight:
|
||||||
if result.pieces.white.knights[0] == (-1, -1):
|
result.pieces.white.knights.add((row, column))
|
||||||
result.pieces.white.knights[0] = (row, column)
|
|
||||||
else:
|
|
||||||
result.pieces.white.knights[1] = (row, column)
|
|
||||||
of Rook:
|
of Rook:
|
||||||
if result.pieces.white.rooks[0] == (-1, -1):
|
result.pieces.white.rooks.add((row, column))
|
||||||
result.pieces.white.rooks[0] = (row, column)
|
|
||||||
else:
|
|
||||||
result.pieces.white.rooks[1] = (row, column)
|
|
||||||
of Queen:
|
of Queen:
|
||||||
result.pieces.white.queen = (row, column)
|
result.pieces.white.queen = (row, column)
|
||||||
of King:
|
of King:
|
||||||
|
@ -330,9 +338,30 @@ when isMainModule:
|
||||||
proc testPiece(piece: Piece, kind: PieceKind, color: PieceColor) =
|
proc testPiece(piece: Piece, kind: PieceKind, color: PieceColor) =
|
||||||
doAssert piece.kind == kind and piece.color == color, &"expected piece of kind {kind} and color {color}, got {piece.kind} / {piece.color} instead"
|
doAssert piece.kind == kind and piece.color == color, &"expected piece of kind {kind} and color {color}, got {piece.kind} / {piece.color} instead"
|
||||||
|
|
||||||
|
proc testPieceCount(board: ChessBoard, kind: PieceKind, color: PieceColor, count: int) =
|
||||||
|
let pieces = board.countPieces(kind, color)
|
||||||
|
doAssert pieces == count, &"expected {count} pieces of kind {kind} and color {color}, got {pieces} instead"
|
||||||
|
|
||||||
echo "Running tests"
|
echo "Running tests"
|
||||||
var b = newDefaultChessboard()
|
var b = newDefaultChessboard()
|
||||||
# Ensure pawns are in the correct location
|
# Ensure correct number of pieces
|
||||||
|
testPieceCount(b, Pawn, White, 8)
|
||||||
|
testPieceCount(b, Pawn, Black, 8)
|
||||||
|
testPieceCount(b, Knight, White, 2)
|
||||||
|
testPieceCount(b, Knight, Black, 2)
|
||||||
|
testPieceCount(b, Bishop, White, 2)
|
||||||
|
testPieceCount(b, Bishop, Black, 2)
|
||||||
|
testPieceCount(b, Rook, White, 2)
|
||||||
|
testPieceCount(b, Rook, Black, 2)
|
||||||
|
testPieceCount(b, Queen, White, 1)
|
||||||
|
testPieceCount(b, Queen, Black, 1)
|
||||||
|
testPieceCount(b, King, White, 1)
|
||||||
|
testPieceCount(b, King, Black, 1)
|
||||||
|
|
||||||
|
|
||||||
|
# Ensure pieces are in the correct location
|
||||||
|
|
||||||
|
# Pawns
|
||||||
for loc in ["a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2"]:
|
for loc in ["a2", "b2", "c2", "d2", "e2", "f2", "g2", "h2"]:
|
||||||
testPiece(b.getPiece(loc), Pawn, White)
|
testPiece(b.getPiece(loc), Pawn, White)
|
||||||
for loc in ["a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7"]:
|
for loc in ["a7", "b7", "c7", "d7", "e7", "f7", "g7", "h7"]:
|
||||||
|
|
Loading…
Reference in New Issue