@ -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