@ -12,7 +12,7 @@ type
Game * = object
Game * = object
pieces * : Pieces
pieces * : Pieces
moved : Moved
moved : Moved
to _m ove* : Color
to M ove* : Color
## Move as object
## Move as object
Move * = object
Move * = object
start : int
start : int
@ -92,7 +92,28 @@ var FileChar = {
" h " : 0
" h " : 0
} . newTable
} . newTable
proc init_board ( ) : Pieces =
proc getField * ( pieces : Pieces , field : int ) : int =
return pieces [ field ]
proc setField ( pieces : var Pieces , field : int , val : int ) : bool {. discardable . } =
if ( val in PieceChar ) :
try :
pieces [ field ] = val
return true
except Exception :
return false
proc getField * ( moved : Moved , field : int ) : bool =
return moved [ field ]
proc setField ( moved : var Moved , field : int , val : bool ) : bool {. discardable . } =
try :
moved [ field ] = val
return true
except Exception :
return false
proc initBoard ( ) : Pieces =
## Create and return a board with pieces in starting position.
## Create and return a board with pieces in starting position.
let board = [
let board = [
Block , Block , Block , Block , Block , Block , Block , Block , Block , Block ,
Block , Block , Block , Block , Block , Block , Block , Block , Block , Block ,
@ -109,56 +130,73 @@ proc init_board(): Pieces =
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 get_move * ( start : int , dest : int , prom : int , color : Color ) : Move =
proc initBoard ( pieces : array [ 0 .. 63 , int ] ) : Pieces =
## Get a move object from `start` to `dest` with an eventual promition to `prom`
## Create and return a board with pieces in position of choice
var move = Move ( start : start , dest : dest , prom : prom * ord ( color ) , color : color )
let board = [
if ( KnightID > prom or QueenID < prom ) :
Block , Block , Block , Block , Block , Block , Block , Block , Block , Block ,
move . prom = QueenID
Block , Block , Block , Block , Block , Block , Block , Block , Block , Block ,
return move
Block , pieces [ 0 ] , pieces [ 1 ] , pieces [ 2 ] , pieces [ 3 ] , pieces [ 4 ] , pieces [ 5 ] ,
pieces [ 6 ] , pieces [ 7 ] , Block ,
proc get_move * ( start : int , dest : int , color : Color ) : Move =
Block , pieces [ 8 ] , pieces [ 9 ] , pieces [ 10 ] , pieces [ 11 ] , pieces [ 12 ] , pieces [ 13 ] ,
## Get a move object from `start` to `dest` with automatic promition to `queen`
pieces [ 14 ] , pieces [ 15 ] , Block ,
var move = Move ( start : start , dest : dest , prom : QueenID * ord ( color ) , color : color )
Block , pieces [ 16 ] , pieces [ 17 ] , pieces [ 18 ] , pieces [ 19 ] , pieces [ 20 ] , pieces [
return move
21 ] , pieces [ 22 ] , pieces [ 23 ] , Block ,
Block , pieces [ 24 ] , pieces [ 25 ] , pieces [ 26 ] , pieces [ 27 ] , pieces [ 28 ] , pieces [
29 ] , pieces [ 30 ] , pieces [ 31 ] , Block ,
Block , pieces [ 32 ] , pieces [ 33 ] , pieces [ 34 ] , pieces [ 35 ] , pieces [ 36 ] , pieces [
37 ] , pieces [ 38 ] , pieces [ 39 ] , Block ,
Block , pieces [ 40 ] , pieces [ 41 ] , pieces [ 42 ] , pieces [ 43 ] , pieces [ 44 ] , pieces [
45 ] , pieces [ 46 ] , pieces [ 47 ] , Block ,
Block , pieces [ 48 ] , pieces [ 49 ] , pieces [ 50 ] , pieces [ 51 ] , pieces [ 52 ] , pieces [
53 ] , pieces [ 54 ] , pieces [ 55 ] , Block ,
Block , pieces [ 56 ] , pieces [ 57 ] , pieces [ 58 ] , pieces [ 59 ] , pieces [ 60 ] , pieces [
61 ] , pieces [ 62 ] , pieces [ 63 ] , Block ,
Block , Block , Block , Block , Block , Block , Block , Block , Block , Block ,
Block , Block , Block , Block , Block , Block , Block , Block , Block , Block ]
return board
proc init_moved ( ) : Moved =
proc init M oved( ) : Moved =
## Create and return a board of pieces moved.
## Create and return a board of pieces moved.
var moved : Moved
var moved : Moved
return moved
return moved
proc init_game * ( ) : Game =
proc init G ame* ( ) : Game =
## Create and return a Game object.
## Create and return a Game object.
let game = Game ( pieces : init_board ( ) , moved : init_moved ( ) ,
let game = Game ( pieces : init Board( ) , moved : initM oved( ) ,
to_move : Color . White )
to_move : Color . White )
return game
return game
proc get_field ( pieces : Pieces , field : int ) : int =
proc initGame * ( pieces : array [ 0 .. 63 , int ] , color : Color ) : Game =
return pieces [ field ]
## Create ad return a Game object based on a position of choice.
let pieces = initBoard ( pieces )
proc set_field ( pieces : var Pieces , field : int , val : int ) : bool {. discardable . } =
let compare = initBoard ( )
if ( val in PieceChar ) :
var moved = initMoved ( )
try :
var same_piece : bool
pieces [ field ] = val
for ind in pieces . low .. pieces . high :
return true
same_piece = ( pieces [ ind ] ! = compare [ ind ] )
except Exception :
moved . setField ( ind , same_piece )
return false
let game = Game ( pieces : pieces , moved : moved ,
to_move : color )
return game
proc get_field ( moved : Moved , field : int ) : bool =
proc getMove * ( start : int , dest : int , prom : int , color : Color ) : Move =
return moved [ field ]
## Get a move object from `start` to `dest` with an eventual promition to `prom`
var move = Move ( start : start , dest : dest , prom : prom * ord ( color ) , color : color )
if ( KnightID > prom or QueenID < prom ) :
move . prom = QueenID
return move
proc set_field ( moved : var Moved , field : int , val : bool ) : bool {. discardable . } =
proc getMove * ( start : int , dest : int , color : Color ) : Move =
try :
## Get a move object from `start` to `dest` with automatic promition to `queen`
moved [ field ] = val
var move = Move ( start : start , dest : dest , prom : QueenID * ord ( color ) , color : color )
return true
return move
except Exception :
return false
proc echo _b oard* ( game : Game , color : Color ) =
proc echoBoard * ( game : Game , color : Color ) =
## Prints out the given `board` with its pieces as characters and line indices from perspecive of `color`.
## Prints out the given `board` with its pieces as characters and line indices from perspecive of `color`.
var line_str = " "
var line_str = " "
if ( color = = Color . Black ) :
if ( color = = Color . Black ) :
for i in countup ( 0 , len ( game . pieces ) - 1 ) :
for i in countup ( 0 , len ( game . pieces ) - 1 ) :
if ( game . pieces . get _f ield( i ) = = 999 ) :
if ( game . pieces . get F ield( i ) = = 999 ) :
continue
continue
line_str & = PieceChar [ game . pieces [ i ] ] & " "
line_str & = PieceChar [ game . pieces [ i ] ] & " "
if ( ( i + 2 ) % % 10 = = 0 ) :
if ( ( i + 2 ) % % 10 = = 0 ) :
@ -167,7 +205,7 @@ proc echo_board*(game: Game, color: Color) =
echo " h g f e d c b a "
echo " h g f e d c b a "
else :
else :
for i in countdown ( len ( game . pieces ) - 1 , 0 ) :
for i in countdown ( len ( game . pieces ) - 1 , 0 ) :
if ( game . pieces . get _f ield( i ) = = 999 ) :
if ( game . pieces . get F ield( i ) = = 999 ) :
continue
continue
line_str & = PieceChar [ game . pieces [ i ] ] & " "
line_str & = PieceChar [ game . pieces [ i ] ] & " "
if ( ( i - 1 ) % % 10 = = 0 ) :
if ( ( i - 1 ) % % 10 = = 0 ) :
@ -175,21 +213,21 @@ proc echo_board*(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 field _to_i nd* ( file : string , line : int ) : int =
proc field ToI nd* ( file : string , line : int ) : int =
## Calculate board index from `file` and `line` of a chess board.
## Calculate board index from `file` and `line` of a chess board.
try :
try :
return 1 + ( line + 1 ) * 10 + FileChar [ file ]
return 1 + ( line + 1 ) * 10 + FileChar [ file ]
except IndexDefect , ValueError :
except IndexDefect , ValueError :
return - 1
return - 1
proc field _to_i nd* ( field : string ) : int =
proc field ToI nd* ( field : string ) : int =
## Calculate board index from `field` of a chess board.
## Calculate board index from `field` of a chess board.
try :
try :
return field _to_i nd( $ field [ 0 ] , parseInt ( $ field [ 1 ] ) )
return field ToI nd( $ field [ 0 ] , parseInt ( $ field [ 1 ] ) )
except IndexDefect , ValueError :
except IndexDefect , ValueError :
return - 1
return - 1
proc ind _to_f ield* ( ind : int ) : string =
proc ind ToF ield* ( ind : int ) : string =
## Calculate field name from board index `ind`.
## Calculate field name from board index `ind`.
let line = ( int ) ind / 10 - 1
let line = ( int ) ind / 10 - 1
let file_ind = ( ind ) % % 10 - 1
let file_ind = ( ind ) % % 10 - 1
@ -197,7 +235,32 @@ proc ind_to_field*(ind: int): string =
if FileChar [ file ] = = file_ind :
if FileChar [ file ] = = file_ind :
return $ file & $ line
return $ file & $ line
proc gen_bishop_dests ( game : Game , field : int , color : Color ) : seq [ int ] =
proc notationToMove * ( notation : string , color : Color ) : Move =
## Convert simplified algebraic chess `notation` to a move object, color of player is `color`.
try :
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 = QueenID * ord ( color )
of " R " :
prom = RookID * ord ( color )
of " B " :
prom = BishopID * ord ( color )
of " N " :
prom = KnightID * ord ( color )
move = getMove ( start , dest , prom , color )
return move
except IndexError :
var move : Move
return move
proc genBishopDests ( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible destinations for a bishop with specific `color` located at index `field` of `game`.
## Generate possible destinations for a bishop with specific `color` located at index `field` of `game`.
## Returns a sequence of possible indices to move to.
## Returns a sequence of possible indices to move to.
try :
try :
@ -206,18 +269,19 @@ proc gen_bishop_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
var target : int
for move in Bishop_Moves :
for move in Bishop_Moves :
dest = field + move
dest = field + move
target = game . pieces . get_field ( dest )
target = game . pieces . getField ( dest )
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = = EnPassantID ) :
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = =
EnPassantID or target = = - EnPassantID ) :
res . add ( dest )
res . add ( dest )
if ( ord ( color ) * target < 0 and ord ( color ) * target > - EnPassantID ) :
if ( ord ( color ) * target < 0 and ord ( color ) * target > - EnPassantID ) :
break
break
dest = dest + move
dest = dest + move
target = game . pieces . get _f ield( dest )
target = game . pieces . get F ield( dest )
return res
return res
except IndexDefect :
except IndexDefect :
return @ [ ]
return @ [ ]
proc gen _rook_d ests( game : Game , field : int , color : Color ) : seq [ int ] =
proc gen RookD ests( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible destinations for a rook with specific `color` located at index `field` of `game`.
## Generate possible destinations for a rook with specific `color` located at index `field` of `game`.
## Returns a sequence of possible indices to move to.
## Returns a sequence of possible indices to move to.
try :
try :
@ -226,18 +290,19 @@ proc gen_rook_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
var target : int
for move in Rook_Moves :
for move in Rook_Moves :
dest = field + move
dest = field + move
target = game . pieces . get_field ( dest )
target = game . pieces . getField ( dest )
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = = EnPassantID ) :
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = =
EnPassantID or target = = - EnPassantID ) :
res . add ( dest )
res . add ( dest )
if ( ord ( color ) * target < 0 and ord ( color ) * target > - EnPassantID ) :
if ( ord ( color ) * target < 0 and ord ( color ) * target > - EnPassantID ) :
break
break
dest = dest + move
dest = dest + move
target = game . pieces . get _f ield( dest )
target = game . pieces . get F ield( dest )
return res
return res
except IndexDefect :
except IndexDefect :
return @ [ ]
return @ [ ]
proc gen _queen_d ests( game : Game , field : int , color : Color ) : seq [ int ] =
proc gen QueenD ests( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible destinations for a queen with specific `color` located at index `field` of `game`.
## Generate possible destinations for a queen with specific `color` located at index `field` of `game`.
## Returns a sequence of possible indices to move to.
## Returns a sequence of possible indices to move to.
try :
try :
@ -246,18 +311,19 @@ proc gen_queen_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
var target : int
for move in Queen_Moves :
for move in Queen_Moves :
dest = field + move
dest = field + move
target = game . pieces . get_field ( dest )
target = game . pieces . getField ( dest )
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = = EnPassantID ) :
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = =
EnPassantID or target = = - EnPassantID ) :
res . add ( dest )
res . add ( dest )
if ( ord ( color ) * target < 0 and ord ( color ) * target > - EnPassantID ) :
if ( ord ( color ) * target < 0 and ord ( color ) * target > - EnPassantID ) :
break
break
dest = dest + move
dest = dest + move
target = game . pieces . get _f ield( dest )
target = game . pieces . get F ield( dest )
return res
return res
except IndexDefect :
except IndexDefect :
return @ [ ]
return @ [ ]
proc gen _king_castle_d est( game : Game , field : int , color : Color ) : seq [ int ] =
proc gen KingCastleD est( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible castle destinations for a king with specific `color` located at index `field` of `game`
## Generate possible castle destinations for a king with specific `color` located at index `field` of `game`
## Returns a sequence of possible indices to move to.
## Returns a sequence of possible indices to move to.
try :
try :
@ -268,9 +334,9 @@ proc gen_king_castle_dest(game: Game, field: int, color: Color): seq[int] =
var half_target : int
var half_target : int
for castle in King_Moves_White_Castle :
for castle in King_Moves_White_Castle :
dest = field + castle
dest = field + castle
target = game . pieces . get _f ield( dest )
target = game . pieces . get F ield( dest )
half_dest = field + ( int ) castle / 2
half_dest = field + ( int ) castle / 2
half_target = game . pieces . get _f ield( half_dest )
half_target = game . pieces . get F ield( half_dest )
if ( target = = 999 or ( target ! = 0 ) ) :
if ( target = = 999 or ( target ! = 0 ) ) :
continue
continue
if ( half_target = = 999 or ( half_target ! = 0 ) ) :
if ( half_target = = 999 or ( half_target ! = 0 ) ) :
@ -281,7 +347,7 @@ proc gen_king_castle_dest(game: Game, field: int, color: Color): seq[int] =
return @ [ ]
return @ [ ]
proc gen _king_d ests( game : Game , field : int , color : Color ) : seq [ int ] =
proc gen KingD ests( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible destinations for a king with specific `color` located at index `field` of `game`.
## Generate possible destinations for a king with specific `color` located at index `field` of `game`.
## Returns a sequence of possible indices to move to.
## Returns a sequence of possible indices to move to.
try :
try :
@ -290,16 +356,16 @@ proc gen_king_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
var target : int
for move in King_Moves :
for move in King_Moves :
dest = field + move
dest = field + move
target = game . pieces . get _f ield( dest )
target = game . pieces . get F ield( dest )
if ( target = = 999 or ( ord ( color ) * target > 0 and ord ( color ) * target ! = EnPassantID ) ) :
if ( target = = 999 or ( ord ( color ) * target > 0 and ord ( color ) * target ! = EnPassantID ) ) :
continue
continue
res . add ( dest )
res . add ( dest )
res . add ( game . gen _king_castle_d est( field , color ) )
res . add ( game . gen KingCastleD est( field , color ) )
return res
return res
except IndexDefect :
except IndexDefect :
return @ [ ]
return @ [ ]
proc gen _knight_d ests( game : Game , field : int , color : Color ) : seq [ int ] =
proc gen KnightD ests( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible destinations for a knight with specific `color` located at index `field` of `game`.
## Generate possible destinations for a knight with specific `color` located at index `field` of `game`.
## Returns a sequence of possible indices to move to.
## Returns a sequence of possible indices to move to.
try :
try :
@ -308,7 +374,7 @@ proc gen_knight_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
var target : int
for move in Knight_Moves :
for move in Knight_Moves :
dest = field + move
dest = field + move
target = game . pieces . get _f ield( dest )
target = game . pieces . get F ield( dest )
if ( target = = 999 or ( ord ( color ) * target > 0 and ord ( color ) * target ! = EnPassantID ) ) :
if ( target = = 999 or ( ord ( color ) * target > 0 and ord ( color ) * target ! = EnPassantID ) ) :
continue
continue
res . add ( dest )
res . add ( dest )
@ -316,7 +382,7 @@ proc gen_knight_dests(game: Game, field: int, color: Color): seq[int] =
except IndexDefect :
except IndexDefect :
return @ [ ]
return @ [ ]
proc gen _pawn_attack_d ests( game : Game , field : int , color : Color ) : seq [ int ] =
proc gen PawnAttackD ests( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible attack destinations for a pawn with specific `color` located at index `field` of `game`.
## 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.
## Returns a sequence of possible indices to move to.
try :
try :
@ -324,8 +390,8 @@ proc gen_pawn_attack_dests(game: Game, field: int, color: Color): seq[int] =
var dest : int
var dest : int
var target : int
var target : int
for attacks in Pawn_Moves_White_Attack :
for attacks in Pawn_Moves_White_Attack :
dest = field + attacks * ord ( color )
dest = field + ( attacks * ord ( color ) )
target = game . pieces . get _f ield( dest )
target = game . pieces . get F ield( dest )
if ( target = = 999 or ord ( color ) * target > = 0 ) :
if ( target = = 999 or ord ( color ) * target > = 0 ) :
continue
continue
res . add ( dest )
res . add ( dest )
@ -333,7 +399,7 @@ proc gen_pawn_attack_dests(game: Game, field: int, color: Color): seq[int] =
except IndexDefect :
except IndexDefect :
return @ [ ]
return @ [ ]
proc gen _pawn_double_d ests( game : Game , field : int , color : Color ) : seq [ int ] =
proc gen PawnDoubleD ests( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible double destinations for a pawn with specific `color` located at index `field` of `game`.
## 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.
## Returns a sequence of possible indices to move to.
try :
try :
@ -342,16 +408,16 @@ proc gen_pawn_double_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
var target : int
for doubles in Pawn_Moves_White_Double :
for doubles in Pawn_Moves_White_Double :
dest = field + doubles * ord ( color )
dest = field + doubles * ord ( color )
target = game . pieces . get _f ield( dest )
target = game . pieces . get F ield( dest )
if ( game . moved . get _f ield( field ) or ( target ! = 0 ) or (
if ( game . moved . get F ield( field ) or ( target ! = 0 ) or (
game . pieces . get _f ield( dest + ( S * ord ( color ) ) ) ! = 0 ) ) :
game . pieces . get F ield( dest + ( S * ord ( color ) ) ) ! = 0 ) ) :
continue
continue
res . add ( dest )
res . add ( dest )
return res
return res
except IndexDefect :
except IndexDefect :
return @ [ ]
return @ [ ]
proc gen _pawn_d ests( game : Game , field : int , color : Color ) : seq [ int ] =
proc gen PawnD ests( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible destinations for a pawn with specific `color` located at index `field` of `game`.
## Generate possible destinations for a pawn with specific `color` located at index `field` of `game`.
## Returns a sequence of possible indices to move to.
## Returns a sequence of possible indices to move to.
try :
try :
@ -360,189 +426,189 @@ proc gen_pawn_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
var target : int
for move in Pawn_Moves_White :
for move in Pawn_Moves_White :
dest = field + move * ord ( color )
dest = field + move * ord ( color )
target = game . pieces . get _f ield( dest )
target = game . pieces . get F ield( dest )
if ( target ! = 0 and target ! = ord ( color ) * EnPassantID ) :
if ( target ! = 0 and target ! = ord ( color ) * EnPassantID ) :
continue
continue
res . add ( dest )
res . add ( dest )
res . add ( game . gen _pawn_attack_d ests( field , color ) )
res . add ( game . gen PawnAttackD ests( field , color ) )
res . add ( game . gen _pawn_double_d ests( field , color ) )
res . add ( game . gen PawnDoubleD ests( field , color ) )
return res
return res
except IndexDefect :
except IndexDefect :
return @ [ ]
return @ [ ]
proc piece _o n( game : Game , color : Color , sequence : seq [ int ] ,
proc piece O n( game : Game , color : Color , sequence : seq [ int ] ,
pieceID : int ) : bool =
pieceID : int ) : bool =
## Check if a piece with `pieceID` of a given `color` is in a field described in a `sequence` in a `game`.
## Check if a piece with `pieceID` of a given `color` is in a field described in a `sequence` in a `game`.
for check in sequence :
for check in sequence :
if game . pieces . get _f ield( check ) = = ord ( color ) * - 1 * pieceID :
if game . pieces . get F ield( check ) = = ord ( color ) * - 1 * pieceID :
return true
return true
return false
return false
proc is _a ttacked( game : Game , position : int , color : Color ) : bool =
proc is A ttacked( game : Game , position : int , color : Color ) : bool =
## Check if a field is attacked by the opposite of `color` in a `game`.
## Check if a field is attacked by the opposite of `color` in a `game`.
var attacked = false
var attacked = false
attacked = attacked or game . piece _on( color , game . gen_pawn_attack_d ests(
attacked = attacked or game . piece On( color , game . genPawnAttackD ests(
position , color ) , PawnID )
position , color ) , PawnID )
attacked = attacked or game . piece _on( color , game . gen_queen_d ests( position ,
attacked = attacked or game . piece On( color , game . genQueenD ests( position ,
color ) , QueenID )
color ) , QueenID )
attacked = attacked or game . piece _on( color , game . gen_king_d ests( position ,
attacked = attacked or game . piece On( color , game . genKingD ests( position ,
color ) , KingID )
color ) , KingID )
attacked = attacked or game . piece _on( color , game . gen_rook_d ests( position ,
attacked = attacked or game . piece On( color , game . genRookD ests( position ,
color ) , RookID )
color ) , RookID )
attacked = attacked or game . piece _on( color , game . gen_bishop_d ests( position ,
attacked = attacked or game . piece On( color , game . genBishopD ests( position ,
color ) , BishopID )
color ) , BishopID )
attacked = attacked or game . piece _on( color , game . gen_knight_d ests( position ,
attacked = attacked or game . piece On( color , game . genKnightD ests( position ,
color ) , KnightID )
color ) , KnightID )
return attacked
return attacked
proc is _in_c heck* ( game : Game , color : Color ) : bool =
proc is InC heck* ( game : Game , color : Color ) : bool =
## Check if the King of a given `color` is in check in a `game`.
## Check if the King of a given `color` is in check in a `game`.
var king_pos : int
var king_pos : int
for i in countup ( 0 , game . pieces . high ) :
for i in countup ( 0 , game . pieces . high ) :
if game . pieces . get _f ield( i ) = = ord ( color ) * KingID :
if game . pieces . get F ield( i ) = = ord ( color ) * KingID :
king_pos = i
king_pos = i
return game . is _a ttacked( king_pos , color )
return game . is A ttacked( king_pos , color )
proc unchecked _m ove( game : var Game , start : int , dest : int ) : bool {. discardable . } =
proc unchecked M ove( game : var Game , start : int , dest : int ) : bool {. discardable . } =
## Moves a piece if possible from `start` position to `dest` position.
## Moves a piece if possible from `start` position to `dest` position.
## Doesnt check boundaries, checks, movement.
## Doesnt check boundaries, checks, movement.
## returns true if the piece moved, else false
## returns true if the piece moved, else false
try :
try :
let piece = game . pieces . get _f ield( start )
let piece = game . pieces . get F ield( start )
if game . pieces . set _f ield( start , 0 ) :
if game . pieces . set F ield( start , 0 ) :
if game . pieces . set _f ield( dest , piece ) :
if game . pieces . set F ield( dest , piece ) :
game . moved . set _f ield( start , true )
game . moved . set F ield( start , true )
game . moved . set _f ield( dest , true )
game . moved . set F ield( dest , true )
return true
return true
else :
else :
game . pieces . set _f ield( start , piece )
game . pieces . set F ield( start , piece )
except IndexDefect , ValueError :
except IndexDefect , ValueError :
return false
return false
proc move _leads_to_c heck( game : Game , start : int , dest : int ,
proc move LeadsToC heck( game : Game , start : int , dest : int ,
color : Color ) : bool =
color : Color ) : bool =
## Checks in a `game` if a move from `start` to `dest` puts the `color` king in check.
## Checks in a `game` if a move from `start` to `dest` puts the `color` king in check.
var check = game
var check = game
check . unchecked _m ove( start , dest )
check . unchecked M ove( start , dest )
return check . is _in_c heck( color )
return check . is InC heck( color )
proc remove _en_p assant( pieces : var Pieces , color : Color ) : void =
proc remove EnP assant( pieces : var Pieces , color : Color ) : void =
## Removes every en passant of given `color` from the `game`.
## Removes every en passant of given `color` from the `game`.
for field in pieces . low .. pieces . high :
for field in pieces . low .. pieces . high :
if pieces . get _f ield( field ) = = ord ( color ) * EnPassantID :
if pieces . get F ield( field ) = = ord ( color ) * EnPassantID :
pieces . set _f ield( field , 0 )
pieces . set F ield( field , 0 )
proc gen _legal_knight_m oves( game : Game , field : int , color : Color ) : seq [ Move ] =
proc gen LegalKnightM oves( game : Game , field : int , color : Color ) : seq [ Move ] =
## Generates all legal knight moves starting from `field` in a `game` for a `color`.
## Generates all legal knight moves starting from `field` in a `game` for a `color`.
if game . pieces . get _f ield( field ) ! = KnightID * ord ( color ) :
if game . pieces . get F ield( field ) ! = KnightID * ord ( color ) :
return @ [ ]
return @ [ ]
var res = newSeq [ Move ] ( )
var res = newSeq [ Move ] ( )
var moves = game . gen _knight_d ests( field , color )
var moves = game . gen KnightD ests( field , color )
for dest in moves :
for dest in moves :
if not game . move _leads_to_c heck( field , dest , color ) :
if not game . move LeadsToC heck( field , dest , color ) :
res . add ( get _m ove( field , dest , color ) )
res . add ( get M ove( field , dest , color ) )
return res
return res
proc gen _legal_bishop_m oves( game : Game , field : int , color : Color ) : seq [ Move ] =
proc gen LegalBishopM oves( game : Game , field : int , color : Color ) : seq [ Move ] =
## Generates all legal bishop moves starting from `field` in a `game` for a `color`.
## Generates all legal bishop moves starting from `field` in a `game` for a `color`.
if game . pieces . get _f ield( field ) ! = BishopID * ord ( color ) :
if game . pieces . get F ield( field ) ! = BishopID * ord ( color ) :
return @ [ ]
return @ [ ]
var res = newSeq [ Move ] ( )
var res = newSeq [ Move ] ( )
var moves = game . gen _bishop_d ests( field , color )
var moves = game . gen BishopD ests( field , color )
for dest in moves :
for dest in moves :
if not game . move _leads_to_c heck( field , dest , color ) :
if not game . move LeadsToC heck( field , dest , color ) :
res . add ( get _m ove( field , dest , color ) )
res . add ( get M ove( field , dest , color ) )
return res
return res
proc gen _legal_rook_m oves( game : Game , field : int , color : Color ) : seq [ Move ] =
proc gen LegalRookM oves( game : Game , field : int , color : Color ) : seq [ Move ] =
## Generates all legal rook moves starting from `field` in a `game` for a `color`.
## Generates all legal rook moves starting from `field` in a `game` for a `color`.
if game . pieces . get _f ield( field ) ! = RookID * ord ( color ) :
if game . pieces . get F ield( field ) ! = RookID * ord ( color ) :
return @ [ ]
return @ [ ]
var res = newSeq [ Move ] ( )
var res = newSeq [ Move ] ( )
var moves = game . gen _rook_d ests( field , color )
var moves = game . gen RookD ests( field , color )
for dest in moves :
for dest in moves :
if not game . move _leads_to_c heck( field , dest , color ) :
if not game . move LeadsToC heck( field , dest , color ) :
res . add ( get _m ove( field , dest , color ) )
res . add ( get M ove( field , dest , color ) )
return res
return res
proc gen _legal_queen_m oves( game : Game , field : int , color : Color ) : seq [ Move ] =
proc gen LegalQueenM oves( game : Game , field : int , color : Color ) : seq [ Move ] =
## Generates all legal queen moves starting from `field` in a `game` for a `color`.
## Generates all legal queen moves starting from `field` in a `game` for a `color`.
if game . pieces . get _f ield( field ) ! = QueenID * ord ( color ) :
if game . pieces . get F ield( field ) ! = QueenID * ord ( color ) :
return @ [ ]
return @ [ ]
var res = newSeq [ Move ] ( )
var res = newSeq [ Move ] ( )
var moves = game . gen _queen_d ests( field , color )
var moves = game . gen QueenD ests( field , color )
for dest in moves :
for dest in moves :
if not game . move _leads_to_c heck( field , dest , color ) :
if not game . move LeadsToC heck( field , dest , color ) :
res . add ( get _m ove( field , dest , color ) )
res . add ( get M ove( field , dest , color ) )
return res
return res
proc gen _legal_king_m oves( game : Game , field : int , color : Color ) : seq [ Move ] =
proc gen LegalKingM oves( game : Game , field : int , color : Color ) : seq [ Move ] =
## Generates all legal king moves starting from `field` in a `game` for a `color`.
## Generates all legal king moves starting from `field` in a `game` for a `color`.
if game . pieces . get _f ield( field ) ! = KingID * ord ( color ) :
if game . pieces . get F ield( field ) ! = KingID * ord ( color ) :
return @ [ ]
return @ [ ]
var res = newSeq [ Move ] ( )
var res = newSeq [ Move ] ( )
var moves = game . gen _king_d ests( field , color )
var moves = game . gen KingD ests( field , color )
for dest in moves :
for dest in moves :
if field - dest = = W + W and game . is _a ttacked( dest + W , color ) :
if field - dest = = W + W and game . is A ttacked( dest + W , color ) :
continue
continue
if field - dest = = E + E and game . is _a ttacked( dest + E , color ) :
if field - dest = = E + E and game . is A ttacked( dest + E , color ) :
continue
continue
if not game . move _leads_to_c heck( field , dest , color ) :
if not game . move LeadsToC heck( field , dest , color ) :
res . add ( get _m ove( field , dest , color ) )
res . add ( get M ove( field , dest , color ) )
return res
return res
proc gen _pawn_p romotion( move : Move , color : Color ) : seq [ Move ] =
proc gen PawnP romotion( move : Move , color : Color ) : seq [ Move ] =
## Generate all possible promotions of a `move` by `color`.
## Generate all possible promotions of a `move` by `color`.
var promotions = newSeq [ Move ] ( )
var promotions = newSeq [ Move ] ( )
let start = move . start
let start = move . start
let dest = move . dest
let dest = move . dest
if ( 90 < dest and dest < 99 ) or ( 20 < dest and dest < 29 ) :
if ( 90 < dest and dest < 99 ) or ( 20 < dest and dest < 29 ) :
for piece in KnightID .. QueenID :
for piece in KnightID .. QueenID :
promotions . add ( get _m ove( start , dest , piece , color ) )
promotions . add ( get M ove( start , dest , piece , color ) )
return promotions
return promotions
proc gen _legal_pawn_m oves( game : Game , field : int , color : Color ) : seq [ Move ] =
proc gen LegalPawnM oves( game : Game , field : int , color : Color ) : seq [ Move ] =
## Generates all legal pawn moves starting from `field` in a `game` for a `color`.
## Generates all legal pawn moves starting from `field` in a `game` for a `color`.
if game . pieces . get _f ield( field ) ! = PawnID * ord ( color ) :
if game . pieces . get F ield( field ) ! = PawnID * ord ( color ) :
return @ [ ]
return @ [ ]
var res = newSeq [ Move ] ( )
var res = newSeq [ Move ] ( )
var moves = game . gen _pawn_d ests( field , color )
var moves = game . gen PawnD ests( field , color )
for dest in moves :
for dest in moves :
if not game . move _leads_to_c heck( field , dest , color ) :
if not game . move LeadsToC heck( field , dest , color ) :
var promotions = gen _pawn_promotion( get_m ove( field , dest , color ) , color )
var promotions = gen PawnPromotion( getM ove( field , dest , color ) , color )
if promotions ! = @ [ ] :
if promotions ! = @ [ ] :
res . add ( promotions )
res . add ( promotions )
else :
else :
res . add ( get _m ove( field , dest , color ) )
res . add ( get M ove( field , dest , color ) )
return res
return res
proc gen _legal_m oves* ( game : Game , field : int , color : Color ) : seq [ Move ] =
proc gen LegalM oves* ( game : Game , field : int , color : Color ) : seq [ Move ] =
## Generates all legal moves starting from `field` in a `game` for a `color`.
## Generates all legal moves starting from `field` in a `game` for a `color`.
var legal_moves = newSeq [ Move ] ( )
var legal_moves = newSeq [ Move ] ( )
var target = ord ( color ) * game . pieces . get _f ield( field )
var target = ord ( color ) * game . pieces . get F ield( field )
if 0 < target and target < EnPassantID :
if 0 < target and target < EnPassantID :
legal_moves = case target :
legal_moves = case target :
of PawnID :
of PawnID :
game . gen _legal_pawn_m oves( field , color )
game . gen LegalPawnM oves( field , color )
of KnightID :
of KnightID :
game . gen _legal_knight_m oves( field , color )
game . gen LegalKnightM oves( field , color )
of BishopID :
of BishopID :
game . gen _legal_bishop_m oves( field , color )
game . gen LegalBishopM oves( field , color )
of RookID :
of RookID :
game . gen _legal_rook_m oves( field , color )
game . gen LegalRookM oves( field , color )
of QueenID :
of QueenID :
game . gen _legal_queen_m oves( field , color )
game . gen LegalQueenM oves( field , color )
of KingID :
of KingID :
game . gen _legal_king_m oves( field , color )
game . gen LegalKingM oves( field , color )
else :
else :
@ [ ]
@ [ ]
return legal_moves
return legal_moves
proc gen _legal_m oves* ( game : Game , color : Color ) : seq [ Move ] =
proc gen LegalM oves* ( game : Game , color : Color ) : seq [ Move ] =
## Generates all legal moves in a `game` for a `color`.
## Generates all legal moves in a `game` for a `color`.
var legal_moves = newSeq [ Move ] ( )
var legal_moves = newSeq [ Move ] ( )
for field in game . pieces . low .. game . pieces . high :
for field in game . pieces . low .. game . pieces . high :
legal_moves . add ( game . gen _legal_m oves( field , color ) )
legal_moves . add ( game . gen LegalM oves( field , color ) )
return legal_moves
return legal_moves
proc castling ( game : var Game , kstart : int , dest_kingside : bool ,
proc castling ( game : var Game , kstart : int , dest_kingside : bool ,
@ -551,7 +617,7 @@ proc castling(game: var Game, kstart: int, dest_kingside: bool,
## `dest_kingside` for kingside castling, else castling is queenside.
## `dest_kingside` for kingside castling, else castling is queenside.
## This process checks for the legality of the move and performs the switch of `game.to_move`
## This process checks for the legality of the move and performs the switch of `game.to_move`
try :
try :
if game . to _m ove ! = color :
if game . to M ove ! = color :
return false
return false
var kdest = kstart
var kdest = kstart
var rstart : int
var rstart : int
@ -564,26 +630,26 @@ proc castling(game: var Game, kstart: int, dest_kingside: bool,
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 . get _f ield( kstart ) and not game . moved . get _f ield( rstart ) :
if not game . moved . get F ield( kstart ) and not game . moved . get F ield( rstart ) :
var check = false
var check = false
if ( dest_kingside ) :
if ( dest_kingside ) :
check = check or game . is _a ttacked( kstart , color )
check = check or game . is A ttacked( kstart , color )
check = check or game . is _a ttacked( kstart + ( E ) , color )
check = check or game . is A ttacked( kstart + ( E ) , color )
check = check or game . is _a ttacked( kstart + ( E + E ) , color )
check = check or game . is A ttacked( kstart + ( E + E ) , color )
else :
else :
check = check or game . is _a ttacked( kstart , color )
check = check or game . is A ttacked( kstart , color )
check = check or game . is _a ttacked( kstart + ( W ) , color )
check = check or game . is A ttacked( kstart + ( W ) , color )
check = check or game . is _a ttacked( kstart + ( W + W ) , color )
check = check or game . is A ttacked( kstart + ( W + W ) , color )
if check :
if check :
return false
return false
game . unchecked _m ove( kstart , kdest )
game . unchecked M ove( kstart , kdest )
game . unchecked _m ove( rstart , rdest )
game . unchecked M ove( rstart , rdest )
return true
return true
return false
return false
except IndexDefect , ValueError :
except IndexDefect , ValueError :
return false
return false
proc checked _m ove* ( game : var Game , move : Move ) : bool {. discardable . } =
proc checked M ove* ( game : var Game , move : Move ) : bool {. discardable . } =
## Tries to make a move in a given `game` with the piece of a given `color` from `start` to `dest`.
## Tries to make a move in a given `game` with the piece of a given `color` from `start` to `dest`.
## This process checks for the legality of the move and performs the switch of `game.to_move`
## This process checks for the legality of the move and performs the switch of `game.to_move`
try :
try :
@ -591,46 +657,46 @@ proc checked_move*(game: var Game, move: Move): bool {.discardable.} =
let dest = move . dest
let dest = move . dest
let color = move . color
let color = move . color
let prom = move . prom
let prom = move . prom
if game . to _m ove ! = color :
if game . to M ove ! = color :
return false
return false
var sequence = newSeq [ Move ] ( )
var sequence = newSeq [ Move ] ( )
let piece = game . pieces . get _f ield( start )
let piece = game . pieces . get F ield( start )
var create_en_passant = false
var create_en_passant = false
var captured_en_passant = false
var captured_en_passant = false
var move : Move
var move : Move
move = get _m ove( start , dest , color )
move = get M ove( start , dest , color )
if ( piece = = PawnID * ord ( color ) ) :
if ( piece = = PawnID * ord ( color ) ) :
create_en_passant = dest in game . gen _pawn_double_d ests( start , color )
create_en_passant = dest in game . gen PawnDoubleD ests( start , color )
captured_en_passant = ( game . pieces . get _f ield( dest ) = = - 1 * ord ( color ) * EnPassantID )
captured_en_passant = ( game . pieces . get F ield( dest ) = = - 1 * ord ( color ) * EnPassantID )
sequence . add ( game . gen _legal_m oves( start , color ) )
sequence . add ( game . gen LegalM oves( start , color ) )
if ( move in sequence ) :
if ( move in sequence ) :
game . pieces . remove _en_p assant( color )
game . pieces . remove EnP assant( color )
if ( piece = = KingID * ord ( color ) and ( start - dest = = ( W + W ) ) ) :
if ( piece = = KingID * ord ( color ) and ( start - dest = = ( W + W ) ) ) :
game . castling ( start , true , color )
return game . castling ( start , true , color )
elif ( piece = = KingID * ord ( color ) and ( start - dest = = ( E + E ) ) ) :
elif ( piece = = KingID * ord ( color ) and ( start - dest = = ( E + E ) ) ) :
game . castling ( start , false , color )
return game . castling ( start , false , color )
else :
else :
game . unchecked _m ove( start , dest )
game . unchecked M ove( start , dest )
game . to _move = Color ( ord ( game . to_m ove) * ( - 1 ) )
game . to Move = Color ( ord ( game . toM ove) * ( - 1 ) )
if create_en_passant :
if create_en_passant :
game . pieces . set _f ield( dest - ( N * ord ( color ) ) , EnPassantID * ord ( color ) )
game . pieces . set F ield( dest - ( N * ord ( color ) ) , EnPassantID * ord ( color ) )
if captured_en_passant :
if captured_en_passant :
game . pieces . set _f ield( dest - ( N * ord ( color ) ) , 0 )
game . pieces . set F ield( dest - ( N * ord ( color ) ) , 0 )
if ( ( 90 < dest and dest < 99 ) or ( 20 < dest and dest < 29 ) ) and
if ( ( 90 < dest and dest < 99 ) or ( 20 < dest and dest < 29 ) ) and
game . pieces . get _f ield( dest ) = = PawnID * ord ( color ) :
game . pieces . get F ield( dest ) = = PawnID * ord ( color ) :
game . pieces . set _f ield( dest , prom )
game . pieces . set F ield( dest , prom )
return true
return true
except IndexDefect , ValueError :
except IndexDefect , ValueError :
return false
return false
proc has _no_m oves( game : Game , color : Color ) : bool =
proc has NoM oves( game : Game , color : Color ) : bool =
## Checks if a player of a given `color` has no legal moves in a `game`.
## Checks if a player of a given `color` has no legal moves in a `game`.
return ( game . gen _legal_m oves( color ) = = @ [ ] )
return ( game . gen LegalM oves( color ) = = @ [ ] )
proc is _c heckmate* ( game : Game , color : Color ) : bool =
proc is C heckmate* ( game : Game , color : Color ) : bool =
## Checks if a player of a given `color` in a `game` is checkmate.
## Checks if a player of a given `color` in a `game` is checkmate.
return game . has _no_moves( color ) and game . is_in_c heck( color )
return game . has NoMoves( color ) and game . isInC heck( color )
proc is _s talemate* ( game : Game , color : Color ) : bool =
proc is S talemate* ( game : Game , color : Color ) : bool =
## Checks if a player of a given `color` in a `game` is stalemate.
## Checks if a player of a given `color` in a `game` is stalemate.
return game . has _no_moves( color ) and not game . is_in_c heck( color )
return game . has NoMoves( color ) and not game . isInC heck( color )