1
0
mirror of https://github.com/tiyn/yeschess.git synced 2026-02-22 10:34:47 +01:00

Compare commits

..

2 Commits

Author SHA1 Message Date
TiynGER
0a0accb3d0 chess: Moved replaced with CastleRights
Moved was a 10x12 1-d array, that stored bools.
It was only used for checking if a pawn moved (especially important for
the double move of the pawns) and if the other pieces moved (important
for checking if the player can castle or not).
The pawn moves are now checked by the starting position (pawns on the
second rank cant be already moved).
The castle rights of a game are expressed as CastleRights, a tuple with 4 bools.
This saves basically 116 boolean values.
2020-12-18 01:01:58 +01:00
TiynGER
c91bf64047 chess restructuring: changed order of functions 2020-12-18 00:25:22 +01:00
3 changed files with 258 additions and 238 deletions

View File

@@ -8,8 +8,6 @@ type
White = 1 White = 1
Board* = array[0..119, int] ## \ Board* = array[0..119, int] ## \
## `Board` saves the position of the chess pieces. ## `Board` saves the position of the chess pieces.
Moved* = array[0..119, bool] ## \
## `Moved` saves the position of squares a piece moved on or from.
CastleRights = tuple CastleRights = tuple
## `CastleRights` contains the rights to castling for each player. ## `CastleRights` contains the rights to castling for each player.
wk: bool # `wk` describes White kingside castle wk: bool # `wk` describes White kingside castle
@@ -19,11 +17,11 @@ type
Game* = object Game* = object
## `Game` stores all important information of a chess game. ## `Game` stores all important information of a chess game.
board*: Board board*: Board
moved: Moved
toMove*: Color toMove*: Color
previousBoard: seq[Board] previousBoard: seq[Board]
previousCastleRights: seq[CastleRights] previousCastleRights: seq[CastleRights]
fiftyMoveCounter: int fiftyMoveCounter: int
castleRights: CastleRights
Move* = object Move* = object
## `Move` stores all important information for a move. ## `Move` stores all important information for a move.
start: int start: int
@@ -109,8 +107,7 @@ const
(0, 1, 0, 0, 0), # bishop only (0, 1, 0, 0, 0), # bishop only
(0, 2, 0, 0, 0) # 2 knights (0, 2, 0, 0, 0) # 2 knights
] ## `InsufficientMaterial` describes the pieces where no checkmate can be ] ## `InsufficientMaterial` describes the pieces where no checkmate can be
## forced. ## forced
let let
PieceChar = { PieceChar = {
@@ -144,47 +141,65 @@ let
# `FileChar` maps the files of the chessboard to numbers for better # `FileChar` maps the files of the chessboard to numbers for better
# conversion. # conversion.
proc checkInsufficientMaterial(board: Board): bool = proc fieldToInd*(file: string, line: int): int =
## Checks for combinations of pieces on a `board`, where no checkmate can be ## Calculate and return board index from `file` and `line` of a chess board.
## forced. ## Returns -1 if the `field` was not input correct.
## Returns true if no player can force a checkmate to the other. try:
var wp = 0 return 1+(line+1)*10+FileChar[file]
var wn = 0 except IndexDefect, ValueError:
var wb = 0 return -1
var wr = 0
var wq = 0 proc fieldToInd*(field: string): int =
var bp = 0 ## Calculate and return board index from `field` of a chess board.
var bn = 0 ## Returns -1 if the `field` was not input correct.
var bb = 0 try:
var br = 0 return fieldToInd($field[0], parseInt($field[1]))
var bq = 0 except IndexDefect, ValueError:
for field in board.low..board.high: return -1
case board[field]:
of WPawn: proc indToField*(ind: int): string =
wp = wp + 1 ## Calculate and returns field name from board index `ind`.
of BPawn: let line = (int)ind/10-1
bp = bp + 1 let file_ind = (ind)%%10-1
of WKnight: for file, i in FileChar:
wn = wn + 1 if FileChar[file] == file_ind:
of BKnight: return $file & $line
bn = bn + 1
of WBishop: proc getMove*(start: int, dest: int, prom: int, color: Color): Move =
wb = wb + 1 ## Get a move object of the `color` player from `start` to `dest` with an
of BBishop: ## eventual promition to `prom`.
bb = bb + 1 var move = Move(start: start, dest: dest, prom: prom * ord(color), color: color)
of WRook: if (WKnight > prom or WQueen < prom):
wr = wr + 1 move.prom = WQueen
of BRook: return move
br = br + 1
of WQueen: proc getMove*(start: int, dest: int, color: Color): Move =
wq = wq + 1 ## Get a move object of the `color` player from `start` to `dest` with
of BQueen: ## automatic promition to queen.
bq = bq + 1 var move = Move(start: start, dest: dest, prom: WQueen * ord(color), color: color)
else: return move
continue
let wpieces: PieceAmount = (wp, wn, wb, wr, wq) proc notationToMove*(notation: string, color: Color): Move =
let bpieces: PieceAmount = (bp, bn, bb, br, bq) ## Convert and return simplified algebraic chess `notation` to a move object,
return (wpieces in InsufficientMaterial) and (bpieces in InsufficientMaterial) ## color of player is `color`.
var move: Move
var start = fieldToInd(notation[0..1])
var dest = fieldToInd(notation[2..3])
move = getMove(start, dest, color)
if (len(notation) > 4):
var promStr = $notation[4]
var prom: int
case promStr:
of "Q":
prom = WQueen * ord(color)
of "R":
prom = WRook * ord(color)
of "B":
prom = WBishop * ord(color)
of "N":
prom = WKnight * ord(color)
move = getMove(start, dest, prom, color)
return move
proc initBoard(): Board = proc initBoard(): Board =
## Create and return a board with pieces in starting position. ## Create and return a board with pieces in starting position.
@@ -229,16 +244,11 @@ proc initBoard(board: array[0..63, int]): Board =
Block, Block, Block, Block, Block, Block, Block, Block, Block, Block] Block, Block, Block, Block, Block, Block, Block, Block, Block, Block]
return board return board
proc initMoved(): Moved =
## Create and return a board of pieces moved.
var moved: Moved
return moved
proc initGame*(): Game = proc initGame*(): Game =
## Create and return a Game object. ## Create and return a Game object.
let game = Game(board: initBoard(), moved: initMoved(), let game = Game(board: initBoard(),
to_move: Color.White, previousBoard: @[], previousCastleRights: @[], to_move: Color.White, previousBoard: @[], previousCastleRights: @[],
fiftyMoveCounter: 0) fiftyMoveCounter: 0, castleRights: (true, true, true, true))
return game return game
proc initGame*(board: array[0..63, int], color: Color): Game = proc initGame*(board: array[0..63, int], color: Color): Game =
@@ -246,30 +256,28 @@ proc initGame*(board: array[0..63, int], color: Color): Game =
## `board` describes the pieces, `color` the color that is about to move. ## `board` describes the pieces, `color` the color that is about to move.
let board = initBoard(board) let board = initBoard(board)
let compare = initBoard() let compare = initBoard()
var moved = initMoved()
var same_piece: bool var same_piece: bool
var wk = false
var wq = false
var bk = false
var bq = false
if (board[fieldToInd("e1")] == compare[fieldToInd("e1")]):
if (board[fieldToInd("a1")] == compare[fieldToInd("a1")]):
wq = true
if (board[fieldToInd("h1")] == compare[fieldToInd("h1")]):
wk = true
if (board[fieldToInd("e8")] == compare[fieldToInd("e8")]):
if (board[fieldToInd("a8")] == compare[fieldToInd("a8")]):
bq = true
if (board[fieldToInd("h8")] == compare[fieldToInd("h8")]):
bk = true
for ind in board.low..board.high: for ind in board.low..board.high:
same_piece = (board[ind] != compare[ind]) same_piece = (board[ind] != compare[ind])
moved[ind] = same_piece let game = Game(board: board,
let game = Game(board: board, moved: moved,
to_move: color, previousBoard: @[], previousCastleRights: @[], to_move: color, previousBoard: @[], previousCastleRights: @[],
fiftyMoveCounter: 0) fiftyMoveCounter: 0, castleRights: (wk, wq, bk, bq))
return game return game
proc getMove*(start: int, dest: int, prom: int, color: Color): Move =
## Get a move object of the `color` player from `start` to `dest` with an
## eventual promition to `prom`.
var move = Move(start: start, dest: dest, prom: prom * ord(color), color: color)
if (WKnight > prom or WQueen < prom):
move.prom = WQueen
return move
proc getMove*(start: int, dest: int, color: Color): Move =
## Get a move object of the `color` player from `start` to `dest` with
## automatic promition to queen.
var move = Move(start: start, dest: dest, prom: WQueen * ord(color), color: color)
return move
proc echoBoard*(game: Game, color: Color) = proc echoBoard*(game: Game, color: Color) =
## Prints out the given `board` with its pieces as characters and line ## Prints out the given `board` with its pieces as characters and line
## indices from perspecive of `color`. ## indices from perspecive of `color`.
@@ -293,59 +301,88 @@ proc echoBoard*(game: Game, color: Color) =
echo line_str echo line_str
echo "a b c d e f g h" echo "a b c d e f g h"
proc fieldToInd*(file: string, line: int): int = proc genPawnAttackDests(game: Game, field: int, color: Color): seq[int] =
## Calculate and return board index from `file` and `line` of a chess board. ## Generate possible attack destinations for a pawn with specific `color`
## Returns -1 if the `field` was not input correct. ## located at index `field` of `game`.
try: ## Returns a sequence of possible indices to move to.
return 1+(line+1)*10+FileChar[file] if (not field in game.board.low..game.board.high):
except IndexDefect, ValueError: return @[]
return -1 var res = newSeq[int]()
var dest: int
var target: int
for attacks in Pawn_Moves_White_Attack:
dest = field + (attacks * ord(color))
if (not dest in game.board.low..game.board.high):
continue
target = game.board[dest]
if (target == 999 or ord(color) * target >= 0):
continue
res.add(dest)
return res
proc fieldToInd*(field: string): int = proc genPawnDoubleDests(game: Game, field: int, color: Color): seq[int] =
## Calculate and return board index from `field` of a chess board. ## Generate possible double destinations for a pawn with specific `color`
## Returns -1 if the `field` was not input correct. ## located at index `field` of `game`.
try: ## Returns a sequence of possible indices to move to.
return fieldToInd($field[0], parseInt($field[1])) if (not field in game.board.low..game.board.high):
except IndexDefect, ValueError: return @[]
return -1 var res = newSeq[int]()
var dest: int
var target: int
for doubles in Pawn_Moves_White_Double:
dest = field + doubles * ord(color)
if (not dest in game.board.low..game.board.high):
continue
target = game.board[dest]
if ((target != 0) or (
game.board[dest+(S*ord(color))] != 0)):
continue
if (color == Color.White and not (field in fieldToInd("h2")..fieldToInd("a2"))):
continue
if (color == Color.Black and not (field in fieldToInd("h7")..fieldToInd("a7"))):
continue
res.add(dest)
return res
proc indToField*(ind: int): string = proc genPawnDests(game: Game, field: int, color: Color): seq[int] =
## Calculate and returns field name from board index `ind`. ## Generate possible destinations for a pawn with specific `color` located at
let line = (int)ind/10-1 ## index `field` of `game`.
let file_ind = (ind)%%10-1 ## Returns a sequence of possible indices to move to.
for file, i in FileChar: if (not field in game.board.low..game.board.high):
if FileChar[file] == file_ind: return @[]
return $file & $line var res = newSeq[int]()
var dest: int
var target: int
for move in Pawn_Moves_White:
dest = field + move * ord(color)
if (not dest in game.board.low..game.board.high):
continue
target = game.board[dest]
if (target != 0 and target != ord(color) * WEnPassant):
continue
res.add(dest)
res.add(game.genPawnAttackDests(field, color))
res.add(game.genPawnDoubleDests(field, color))
return res
proc genCastleRights(moved: Moved): CastleRights = proc genKnightDests(game: Game, field: int, color: Color): seq[int] =
## Generate and return rights to castle from given `moved` ## Generate possible destinations for a knight with specific `color` located
let wk = not moved[fieldToInd("e1")] and not moved[fieldToInd("h1")] ## at index `field` of `game`.
let wq = not moved[fieldToInd("e1")] and not moved[fieldToInd("a1")] ## Returns a sequence of possible indices to move to.
let bk = not moved[fieldToInd("e8")] and not moved[fieldToInd("h8")] if (not field in game.board.low..game.board.high):
let bq = not moved[fieldToInd("e8")] and not moved[fieldToInd("a8")] return @[]
return (wk, wq, bk, bq) var res = newSeq[int]()
var dest: int
proc notationToMove*(notation: string, color: Color): Move = var target: int
## Convert and return simplified algebraic chess `notation` to a move object, for move in Knight_Moves:
## color of player is `color`. dest = field + move
var move: Move if (not dest in game.board.low..game.board.high):
var start = fieldToInd(notation[0..1]) continue
var dest = fieldToInd(notation[2..3]) target = game.board[dest]
move = getMove(start, dest, color) if (target == 999 or (ord(color) * target > 0 and ord(color) * target != WEnPassant)):
if (len(notation) > 4): continue
var promStr = $notation[4] res.add(dest)
var prom: int return res
case promStr:
of "Q":
prom = WQueen * ord(color)
of "R":
prom = WRook * ord(color)
of "B":
prom = WBishop * ord(color)
of "N":
prom = WKnight * ord(color)
move = getMove(start, dest, prom, color)
return move
proc genBishopDests(game: Game, field: int, color: Color): seq[int] = proc genBishopDests(game: Game, field: int, color: Color): seq[int] =
## Generate possible destinations for a bishop with specific `color` located ## Generate possible destinations for a bishop with specific `color` located
@@ -461,85 +498,6 @@ proc genKingDests(game: Game, field: int, color: Color): seq[int] =
res.add(game.genKingCastleDest(field, color)) res.add(game.genKingCastleDest(field, color))
return res return res
proc genKnightDests(game: Game, field: int, color: Color): seq[int] =
## Generate possible destinations for a knight with specific `color` located
## at index `field` of `game`.
## Returns a sequence of possible indices to move to.
if (not field in game.board.low..game.board.high):
return @[]
var res = newSeq[int]()
var dest: int
var target: int
for move in Knight_Moves:
dest = field + move
if (not dest in game.board.low..game.board.high):
continue
target = game.board[dest]
if (target == 999 or (ord(color) * target > 0 and ord(color) * target != WEnPassant)):
continue
res.add(dest)
return res
proc genPawnAttackDests(game: Game, field: int, color: Color): seq[int] =
## Generate possible attack destinations for a pawn with specific `color`
## located at index `field` of `game`.
## Returns a sequence of possible indices to move to.
if (not field in game.board.low..game.board.high):
return @[]
var res = newSeq[int]()
var dest: int
var target: int
for attacks in Pawn_Moves_White_Attack:
dest = field + (attacks * ord(color))
if (not dest in game.board.low..game.board.high):
continue
target = game.board[dest]
if (target == 999 or ord(color) * target >= 0):
continue
res.add(dest)
return res
proc genPawnDoubleDests(game: Game, field: int, color: Color): seq[int] =
## Generate possible double destinations for a pawn with specific `color`
## located at index `field` of `game`.
## Returns a sequence of possible indices to move to.
if (not field in game.board.low..game.board.high):
return @[]
var res = newSeq[int]()
var dest: int
var target: int
for doubles in Pawn_Moves_White_Double:
dest = field + doubles * ord(color)
if (not dest in game.board.low..game.board.high):
continue
target = game.board[dest]
if (game.moved[field] or (target != 0) or (
game.board[dest+(S*ord(color))] != 0)):
continue
res.add(dest)
return res
proc genPawnDests(game: Game, field: int, color: Color): seq[int] =
## Generate possible destinations for a pawn with specific `color` located at
## index `field` of `game`.
## Returns a sequence of possible indices to move to.
if (not field in game.board.low..game.board.high):
return @[]
var res = newSeq[int]()
var dest: int
var target: int
for move in Pawn_Moves_White:
dest = field + move * ord(color)
if (not dest in game.board.low..game.board.high):
continue
target = game.board[dest]
if (target != 0 and target != ord(color) * WEnPassant):
continue
res.add(dest)
res.add(game.genPawnAttackDests(field, color))
res.add(game.genPawnDoubleDests(field, color))
return res
proc pieceOn(game: Game, color: Color, sequence: seq[int], proc pieceOn(game: Game, color: Color, sequence: seq[int],
pieceID: int): bool = pieceID: int): bool =
## Returns true if the `PieceID` of a given `color` is in `sequence` else ## Returns true if the `PieceID` of a given `color` is in `sequence` else
@@ -581,8 +539,22 @@ proc uncheckedMove(game: var Game, start: int, dest: int): bool {.discardable.}
let piece = game.board[start] let piece = game.board[start]
game.board[start] = 0 game.board[start] = 0
game.board[dest] = piece game.board[dest] = piece
game.moved[start] = true if (start == fieldToInd("e1") or start == fieldToInd("a1")):
game.moved[dest] = true game.castleRights.wq = false
if (start == fieldToInd("e1") or start == fieldToInd("h1")):
game.castleRights.wk = false
if (start == fieldToInd("e8") or start == fieldToInd("a8")):
game.castleRights.bq = false
if (start == fieldToInd("e8") or start == fieldToInd("h8")):
game.castleRights.bk = false
if (dest == fieldToInd("e1") or dest == fieldToInd("a1")):
game.castleRights.wq = false
if (dest == fieldToInd("e1") or dest == fieldToInd("h1")):
game.castleRights.wk = false
if (dest == fieldToInd("e8") or dest == fieldToInd("a8")):
game.castleRights.bq = false
if (dest == fieldToInd("e8") or dest == fieldToInd("h8")):
game.castleRights.bk = false
return true return true
proc moveLeadsToCheck(game: Game, start: int, dest: int, proc moveLeadsToCheck(game: Game, start: int, dest: int,
@@ -593,11 +565,31 @@ proc moveLeadsToCheck(game: Game, start: int, dest: int,
check.uncheckedMove(start, dest) check.uncheckedMove(start, dest)
return check.isInCheck(color) return check.isInCheck(color)
proc removeEnPassant(board: var Board, color: Color): void = proc genPawnPromotion(move: Move, color: Color): seq[Move] =
## Removes every en passant of given `color` from the `board`. ## Generate all possible promotions of a `move` by `color`.
for field in board.low..board.high: var promotions = newSeq[Move]()
if board[field] == ord(color) * WEnPassant: let start = move.start
board[field] = 0 let dest = move.dest
if (90 < dest and dest < 99) or (20 < dest and dest < 29):
for piece in WKnight..WQueen:
promotions.add(getMove(start, dest, piece, color))
return promotions
proc genLegalPawnMoves(game: Game, field: int, color: Color): seq[Move] =
## Generates all legal pawn moves in a `game` starting from `field` for a
## `color`.
if game.board[field] != WPawn * ord(color):
return @[]
var res = newSeq[Move]()
var moves = game.genPawnDests(field, color)
for dest in moves:
if not game.moveLeadsToCheck(field, dest, color):
var promotions = genPawnPromotion(getMove(field, dest, color), color)
if promotions != @[]:
res.add(promotions)
else:
res.add(getMove(field, dest, color))
return res
proc genLegalKnightMoves(game: Game, field: int, color: Color): seq[Move] = proc genLegalKnightMoves(game: Game, field: int, color: Color): seq[Move] =
## Generates all legal knight moves in a `game` starting from `field` for a ## Generates all legal knight moves in a `game` starting from `field` for a
@@ -663,32 +655,6 @@ proc genLegalKingMoves(game: Game, field: int, color: Color): seq[Move] =
res.add(getMove(field, dest, color)) res.add(getMove(field, dest, color))
return res return res
proc genPawnPromotion(move: Move, color: Color): seq[Move] =
## Generate all possible promotions of a `move` by `color`.
var promotions = newSeq[Move]()
let start = move.start
let dest = move.dest
if (90 < dest and dest < 99) or (20 < dest and dest < 29):
for piece in WKnight..WQueen:
promotions.add(getMove(start, dest, piece, color))
return promotions
proc genLegalPawnMoves(game: Game, field: int, color: Color): seq[Move] =
## Generates all legal pawn moves in a `game` starting from `field` for a
## `color`.
if game.board[field] != WPawn * ord(color):
return @[]
var res = newSeq[Move]()
var moves = game.genPawnDests(field, color)
for dest in moves:
if not game.moveLeadsToCheck(field, dest, color):
var promotions = genPawnPromotion(getMove(field, dest, color), color)
if promotions != @[]:
res.add(promotions)
else:
res.add(getMove(field, dest, color))
return res
proc genLegalMoves*(game: Game, field: int, color: Color): seq[Move] = proc genLegalMoves*(game: Game, field: int, color: Color): seq[Move] =
## Generates all legal moves in a `game` starting from `field` for a `color`. ## Generates all legal moves in a `game` starting from `field` for a `color`.
var legal_moves = newSeq[Move]() var legal_moves = newSeq[Move]()
@@ -730,15 +696,24 @@ proc castling(game: var Game, kstart: int, dest_kingside: bool,
var kdest = kstart var kdest = kstart
var rstart: int var rstart: int
var rdest: int var rdest: int
var rights = false
if (dest_kingside): if (dest_kingside):
kdest = kstart + (E+E) kdest = kstart + (E+E)
rstart = kstart + (E+E+E) rstart = kstart + (E+E+E)
rdest = rstart + (W+W) rdest = rstart + (W+W)
if (color == Color.White):
rights = game.castleRights.wk
else:
rights = game.castleRights.bk
else: else:
rstart = kstart + (W+W+W+W) rstart = kstart + (W+W+W+W)
rdest = rstart + (E+E+E) rdest = rstart + (E+E+E)
kdest = kstart + (W+W) kdest = kstart + (W+W)
if not game.moved[kstart] and not game.moved[rstart]: if (color == Color.White):
rights = game.castleRights.bq
else:
rights = game.castleRights.bq
if (rights):
var check = false var check = false
if (dest_kingside): if (dest_kingside):
check = check or game.isAttacked(kstart, color) check = check or game.isAttacked(kstart, color)
@@ -756,6 +731,12 @@ proc castling(game: var Game, kstart: int, dest_kingside: bool,
return true return true
return false return false
proc removeEnPassant(board: var Board, color: Color): void =
## Removes every en passant of given `color` from the `board`.
for field in board.low..board.high:
if board[field] == ord(color) * WEnPassant:
board[field] = 0
proc checkedMove*(game: var Game, move: Move): bool {.discardable.} = proc checkedMove*(game: var Game, move: Move): bool {.discardable.} =
## Tries to make a `move` in a given `game``. ## Tries to make a `move` in a given `game``.
## This process checks for the legality of the move and performs the switch ## This process checks for the legality of the move and performs the switch
@@ -799,7 +780,7 @@ proc checkedMove*(game: var Game, move: Move): bool {.discardable.} =
var prevBoard = game.previousBoard var prevBoard = game.previousBoard
var prevCastle = game.previousCastleRights var prevCastle = game.previousCastleRights
game.previousBoard.add(game.board) game.previousBoard.add(game.board)
game.previousCastleRights.add(game.moved.genCastleRights()) game.previousCastleRights.add(game.castleRights)
game.fiftyMoveCounter = game.fiftyMoveCounter + 1 game.fiftyMoveCounter = game.fiftyMoveCounter + 1
if fiftyMoveRuleReset: if fiftyMoveRuleReset:
game.fiftyMoveCounter = 0 game.fiftyMoveCounter = 0
@@ -833,6 +814,48 @@ proc isDrawClaimable*(game: Game): bool =
## Returns true if a draw is claimable by either player. ## Returns true if a draw is claimable by either player.
return game.threeMoveRep() or game.fiftyMoveRule() return game.threeMoveRep() or game.fiftyMoveRule()
proc checkInsufficientMaterial(board: Board): bool =
## Checks for combinations of pieces on a `board`, where no checkmate can be
## forced.
## Returns true if no player can force a checkmate to the other.
var wp = 0
var wn = 0
var wb = 0
var wr = 0
var wq = 0
var bp = 0
var bn = 0
var bb = 0
var br = 0
var bq = 0
for field in board.low..board.high:
case board[field]:
of WPawn:
wp = wp + 1
of BPawn:
bp = bp + 1
of WKnight:
wn = wn + 1
of BKnight:
bn = bn + 1
of WBishop:
wb = wb + 1
of BBishop:
bb = bb + 1
of WRook:
wr = wr + 1
of BRook:
br = br + 1
of WQueen:
wq = wq + 1
of BQueen:
bq = bq + 1
else:
continue
let wpieces: PieceAmount = (wp, wn, wb, wr, wq)
let bpieces: PieceAmount = (bp, bn, bb, br, bq)
return (wpieces in InsufficientMaterial) and (bpieces in InsufficientMaterial)
proc isStalemate*(game: Game, color: Color): bool = proc isStalemate*(game: Game, color: Color): bool =
## Returns true if the `color` player is stalemate in a `game`. ## Returns true if the `color` player is stalemate in a `game`.
return (game.hasNoMoves(color) and not game.isInCheck(color)) or return (game.hasNoMoves(color) and not game.isInCheck(color)) or

View File

@@ -1,6 +1,3 @@
from strutils import parseInt
import rdstdin
import ./chess import ./chess
proc runGame*(): void = proc runGame*(): void =