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.
master
TiynGER 4 years ago
parent c91bf64047
commit 0a0accb3d0

@ -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
@ -246,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 =
@ -263,14 +256,26 @@ 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 echoBoard*(game: Game, color: Color) = proc echoBoard*(game: Game, color: Color) =
@ -296,14 +301,6 @@ 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 genCastleRights(moved: Moved): CastleRights =
## Generate and return rights to castle from given `moved`
let wk = not moved[fieldToInd("e1")] and not moved[fieldToInd("h1")]
let wq = not moved[fieldToInd("e1")] and not moved[fieldToInd("a1")]
let bk = not moved[fieldToInd("e8")] and not moved[fieldToInd("h8")]
let bq = not moved[fieldToInd("e8")] and not moved[fieldToInd("a8")]
return (wk, wq, bk, bq)
proc genPawnAttackDests(game: Game, field: int, color: Color): seq[int] = proc genPawnAttackDests(game: Game, field: int, color: Color): seq[int] =
## Generate possible attack destinations for a pawn with specific `color` ## Generate possible attack destinations for a pawn with specific `color`
## located at index `field` of `game`. ## located at index `field` of `game`.
@ -337,9 +334,13 @@ proc genPawnDoubleDests(game: Game, field: int, color: Color): seq[int] =
if (not dest in game.board.low..game.board.high): if (not dest in game.board.low..game.board.high):
continue continue
target = game.board[dest] target = game.board[dest]
if (game.moved[field] or (target != 0) or ( if ((target != 0) or (
game.board[dest+(S*ord(color))] != 0)): game.board[dest+(S*ord(color))] != 0)):
continue 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) res.add(dest)
return res return res
@ -538,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,
@ -681,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,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

Loading…
Cancel
Save