@ -12,7 +12,7 @@ type
Game * = object
pieces * : Pieces
moved : Moved
to_m ove * : Color
toM ove * : Color
## Move as object
Move * = object
start : int
@ -92,7 +92,28 @@ var FileChar = {
" h " : 0
} . 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.
let board = [
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 ]
return board
proc get_move * ( start : int , dest : int , prom : int , color : Color ) : Move =
## 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 get_move * ( start : int , dest : int , color : Color ) : Move =
## Get a move object from `start` to `dest` with automatic promition to `queen`
var move = Move ( start : start , dest : dest , prom : QueenID * ord ( color ) , color : color )
return move
proc initBoard ( pieces : array [ 0 .. 63 , int ] ) : Pieces =
## Create and return a board with pieces in position of choice
let board = [
Block , Block , Block , Block , Block , Block , Block , Block , Block , Block ,
Block , Block , Block , Block , Block , Block , Block , Block , Block , Block ,
Block , pieces [ 0 ] , pieces [ 1 ] , pieces [ 2 ] , pieces [ 3 ] , pieces [ 4 ] , pieces [ 5 ] ,
pieces [ 6 ] , pieces [ 7 ] , Block ,
Block , pieces [ 8 ] , pieces [ 9 ] , pieces [ 10 ] , pieces [ 11 ] , pieces [ 12 ] , pieces [ 13 ] ,
pieces [ 14 ] , pieces [ 15 ] , Block ,
Block , pieces [ 16 ] , pieces [ 17 ] , pieces [ 18 ] , pieces [ 19 ] , pieces [ 20 ] , pieces [
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 initM oved ( ) : Moved =
## Create and return a board of pieces moved.
var moved : Moved
return moved
proc init_game * ( ) : Game =
proc initG ame * ( ) : Game =
## Create and return a Game object.
let game = Game ( pieces : init_board ( ) , moved : init_moved ( ) ,
let game = Game ( pieces : initB oard ( ) , moved : initM oved ( ) ,
to_move : Color . White )
return game
proc get_field ( pieces : Pieces , field : int ) : int =
return pieces [ field ]
proc set_field ( pieces : var Pieces , field : int , val : int ) : bool {. discardable . } =
if ( val in PieceChar ) :
try :
pieces [ field ] = val
return true
except Exception :
return false
proc initGame * ( pieces : array [ 0 .. 63 , int ] , color : Color ) : Game =
## Create ad return a Game object based on a position of choice.
let pieces = initBoard ( pieces )
let compare = initBoard ( )
var moved = initMoved ( )
var same_piece : bool
for ind in pieces . low .. pieces . high :
same_piece = ( pieces [ ind ] ! = compare [ ind ] )
moved . setField ( ind , same_piece )
let game = Game ( pieces : pieces , moved : moved ,
to_move : color )
return game
proc get_field ( moved : Moved , field : int ) : bool =
return moved [ field ]
proc getMove * ( start : int , dest : int , prom : int , color : Color ) : Move =
## 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 . } =
try :
moved [ field ] = val
return true
except Exception :
return false
proc getMove * ( start : int , dest : int , color : Color ) : Move =
## Get a move object from `start` to `dest` with automatic promition to `queen`
var move = Move ( start : start , dest : dest , prom : QueenID * ord ( color ) , color : color )
return move
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`.
var line_str = " "
if ( color = = Color . Black ) :
for i in countup ( 0 , len ( game . pieces ) - 1 ) :
if ( game . pieces . get_f ield ( i ) = = 999 ) :
if ( game . pieces . getF ield ( i ) = = 999 ) :
continue
line_str & = PieceChar [ game . pieces [ i ] ] & " "
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 "
else :
for i in countdown ( len ( game . pieces ) - 1 , 0 ) :
if ( game . pieces . get_f ield ( i ) = = 999 ) :
if ( game . pieces . getF ield ( i ) = = 999 ) :
continue
line_str & = PieceChar [ game . pieces [ i ] ] & " "
if ( ( i - 1 ) % % 10 = = 0 ) :
@ -175,21 +213,21 @@ proc echo_board*(game: Game, color: Color) =
echo line_str
echo " a b c d e f g h "
proc field_to_i nd * ( file : string , line : int ) : int =
proc fieldToI nd * ( file : string , line : int ) : int =
## Calculate board index from `file` and `line` of a chess board.
try :
return 1 + ( line + 1 ) * 10 + FileChar [ file ]
except IndexDefect , ValueError :
return - 1
proc field_to_i nd * ( field : string ) : int =
proc fieldToI nd * ( field : string ) : int =
## Calculate board index from `field` of a chess board.
try :
return field_to_i nd ( $ field [ 0 ] , parseInt ( $ field [ 1 ] ) )
return fieldToI nd ( $ field [ 0 ] , parseInt ( $ field [ 1 ] ) )
except IndexDefect , ValueError :
return - 1
proc ind_to_f ield * ( ind : int ) : string =
proc indToF ield * ( ind : int ) : string =
## Calculate field name from board index `ind`.
let line = ( int ) 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 :
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`.
## Returns a sequence of possible indices to move to.
try :
@ -206,18 +269,19 @@ proc gen_bishop_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
for move in Bishop_Moves :
dest = field + move
target = game . pieces . get_field ( dest )
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = = EnPassantID ) :
target = game . pieces . getField ( dest )
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = =
EnPassantID or target = = - EnPassantID ) :
res . add ( dest )
if ( ord ( color ) * target < 0 and ord ( color ) * target > - EnPassantID ) :
break
dest = dest + move
target = game . pieces . get_f ield ( dest )
target = game . pieces . getF ield ( dest )
return res
except IndexDefect :
return @ [ ]
proc gen_rook_d ests ( game : Game , field : int , color : Color ) : seq [ int ] =
proc genRookD ests ( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible destinations for a rook with specific `color` located at index `field` of `game`.
## Returns a sequence of possible indices to move to.
try :
@ -226,18 +290,19 @@ proc gen_rook_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
for move in Rook_Moves :
dest = field + move
target = game . pieces . get_field ( dest )
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = = EnPassantID ) :
target = game . pieces . getField ( dest )
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = =
EnPassantID or target = = - EnPassantID ) :
res . add ( dest )
if ( ord ( color ) * target < 0 and ord ( color ) * target > - EnPassantID ) :
break
dest = dest + move
target = game . pieces . get_f ield ( dest )
target = game . pieces . getF ield ( dest )
return res
except IndexDefect :
return @ [ ]
proc gen_queen_d ests ( game : Game , field : int , color : Color ) : seq [ int ] =
proc genQueenD ests ( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible destinations for a queen with specific `color` located at index `field` of `game`.
## Returns a sequence of possible indices to move to.
try :
@ -246,18 +311,19 @@ proc gen_queen_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
for move in Queen_Moves :
dest = field + move
target = game . pieces . get_field ( dest )
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = = EnPassantID ) :
target = game . pieces . getField ( dest )
while ( target ! = 999 and ( ord ( color ) * target < = 0 ) or target = =
EnPassantID or target = = - EnPassantID ) :
res . add ( dest )
if ( ord ( color ) * target < 0 and ord ( color ) * target > - EnPassantID ) :
break
dest = dest + move
target = game . pieces . get_f ield ( dest )
target = game . pieces . getF ield ( dest )
return res
except IndexDefect :
return @ [ ]
proc gen_king_castle_d est ( game : Game , field : int , color : Color ) : seq [ int ] =
proc genKingCastleD 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`
## Returns a sequence of possible indices to move to.
try :
@ -268,9 +334,9 @@ proc gen_king_castle_dest(game: Game, field: int, color: Color): seq[int] =
var half_target : int
for castle in King_Moves_White_Castle :
dest = field + castle
target = game . pieces . get_f ield ( dest )
target = game . pieces . getF ield ( dest )
half_dest = field + ( int ) castle / 2
half_target = game . pieces . get_f ield ( half_dest )
half_target = game . pieces . getF ield ( half_dest )
if ( target = = 999 or ( target ! = 0 ) ) :
continue
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 @ [ ]
proc gen_king_d ests ( game : Game , field : int , color : Color ) : seq [ int ] =
proc genKingD ests ( game : Game , field : int , color : Color ) : seq [ int ] =
## Generate possible destinations for a king with specific `color` located at index `field` of `game`.
## Returns a sequence of possible indices to move to.
try :
@ -290,16 +356,16 @@ proc gen_king_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
for move in King_Moves :
dest = field + move
target = game . pieces . get_f ield ( dest )
target = game . pieces . getF ield ( dest )
if ( target = = 999 or ( ord ( color ) * target > 0 and ord ( color ) * target ! = EnPassantID ) ) :
continue
res . add ( dest )
res . add ( game . gen_king_castle_d est ( field , color ) )
res . add ( game . genKingCastleD est ( field , color ) )
return res
except IndexDefect :
return @ [ ]
proc gen_knight_d ests ( game : Game , field : int , color : Color ) : seq [ int ] =
proc genKnightD ests ( 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.
try :
@ -308,7 +374,7 @@ proc gen_knight_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
for move in Knight_Moves :
dest = field + move
target = game . pieces . get_f ield ( dest )
target = game . pieces . getF ield ( dest )
if ( target = = 999 or ( ord ( color ) * target > 0 and ord ( color ) * target ! = EnPassantID ) ) :
continue
res . add ( dest )
@ -316,7 +382,7 @@ proc gen_knight_dests(game: Game, field: int, color: Color): seq[int] =
except IndexDefect :
return @ [ ]
proc gen_pawn_attack_d ests ( game : Game , field : int , color : Color ) : seq [ int ] =
proc genPawnAttackD 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`.
## Returns a sequence of possible indices to move to.
try :
@ -324,8 +390,8 @@ proc gen_pawn_attack_dests(game: Game, field: int, color: Color): seq[int] =
var dest : int
var target : int
for attacks in Pawn_Moves_White_Attack :
dest = field + attacks * ord ( color )
target = game . pieces . get_f ield ( dest )
dest = field + ( attacks * ord ( color ) )
target = game . pieces . getF ield ( dest )
if ( target = = 999 or ord ( color ) * target > = 0 ) :
continue
res . add ( dest )
@ -333,7 +399,7 @@ proc gen_pawn_attack_dests(game: Game, field: int, color: Color): seq[int] =
except IndexDefect :
return @ [ ]
proc gen_pawn_double_d ests ( game : Game , field : int , color : Color ) : seq [ int ] =
proc genPawnDoubleD 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`.
## Returns a sequence of possible indices to move to.
try :
@ -342,16 +408,16 @@ proc gen_pawn_double_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
for doubles in Pawn_Moves_White_Double :
dest = field + doubles * ord ( color )
target = game . pieces . get_f ield ( dest )
if ( game . moved . get_f ield ( field ) or ( target ! = 0 ) or (
game . pieces . get_f ield ( dest + ( S * ord ( color ) ) ) ! = 0 ) ) :
target = game . pieces . getF ield ( dest )
if ( game . moved . getF ield ( field ) or ( target ! = 0 ) or (
game . pieces . getF ield ( dest + ( S * ord ( color ) ) ) ! = 0 ) ) :
continue
res . add ( dest )
return res
except IndexDefect :
return @ [ ]
proc gen_pawn_d ests ( game : Game , field : int , color : Color ) : seq [ int ] =
proc genPawnD ests ( 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.
try :
@ -360,189 +426,189 @@ proc gen_pawn_dests(game: Game, field: int, color: Color): seq[int] =
var target : int
for move in Pawn_Moves_White :
dest = field + move * ord ( color )
target = game . pieces . get_f ield ( dest )
target = game . pieces . getF ield ( dest )
if ( target ! = 0 and target ! = ord ( color ) * EnPassantID ) :
continue
res . add ( dest )
res . add ( game . gen_pawn_attack_d ests ( field , color ) )
res . add ( game . gen_pawn_double_d ests ( field , color ) )
res . add ( game . genPawnAttackD ests ( field , color ) )
res . add ( game . genPawnDoubleD ests ( field , color ) )
return res
except IndexDefect :
return @ [ ]
proc piece_o n ( game : Game , color : Color , sequence : seq [ int ] ,
proc pieceO n ( game : Game , color : Color , sequence : seq [ int ] ,
pieceID : int ) : bool =
## 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 :
if game . pieces . get_f ield ( check ) = = ord ( color ) * - 1 * pieceID :
if game . pieces . getF ield ( check ) = = ord ( color ) * - 1 * pieceID :
return true
return false
proc is_a ttacked ( game : Game , position : int , color : Color ) : bool =
proc isA ttacked ( game : Game , position : int , color : Color ) : bool =
## Check if a field is attacked by the opposite of `color` in a `game`.
var attacked = false
attacked = attacked or game . piece_o n ( color , game . gen_pawn_attack_d ests (
attacked = attacked or game . pieceO n ( color , game . genPawnAttackD ests (
position , color ) , PawnID )
attacked = attacked or game . piece_o n ( color , game . gen_queen_d ests ( position ,
attacked = attacked or game . pieceO n ( color , game . genQueenD ests ( position ,
color ) , QueenID )
attacked = attacked or game . piece_o n ( color , game . gen_king_d ests ( position ,
attacked = attacked or game . pieceO n ( color , game . genKingD ests ( position ,
color ) , KingID )
attacked = attacked or game . piece_o n ( color , game . gen_rook_d ests ( position ,
attacked = attacked or game . pieceO n ( color , game . genRookD ests ( position ,
color ) , RookID )
attacked = attacked or game . piece_o n ( color , game . gen_bishop_d ests ( position ,
attacked = attacked or game . pieceO n ( color , game . genBishopD ests ( position ,
color ) , BishopID )
attacked = attacked or game . piece_o n ( color , game . gen_knight_d ests ( position ,
attacked = attacked or game . pieceO n ( color , game . genKnightD ests ( position ,
color ) , KnightID )
return attacked
proc is_in_c heck * ( game : Game , color : Color ) : bool =
proc isInC heck * ( game : Game , color : Color ) : bool =
## Check if the King of a given `color` is in check in a `game`.
var king_pos : int
for i in countup ( 0 , game . pieces . high ) :
if game . pieces . get_f ield ( i ) = = ord ( color ) * KingID :
if game . pieces . getF ield ( i ) = = ord ( color ) * KingID :
king_pos = i
return game . is_a ttacked ( king_pos , color )
return game . isA ttacked ( king_pos , color )
proc unchecked_m ove ( game : var Game , start : int , dest : int ) : bool {. discardable . } =
proc uncheckedM ove ( game : var Game , start : int , dest : int ) : bool {. discardable . } =
## Moves a piece if possible from `start` position to `dest` position.
## Doesnt check boundaries, checks, movement.
## returns true if the piece moved, else false
try :
let piece = game . pieces . get_f ield ( start )
if game . pieces . set_f ield ( start , 0 ) :
if game . pieces . set_f ield ( dest , piece ) :
game . moved . set_f ield ( start , true )
game . moved . set_f ield ( dest , true )
let piece = game . pieces . getF ield ( start )
if game . pieces . setF ield ( start , 0 ) :
if game . pieces . setF ield ( dest , piece ) :
game . moved . setF ield ( start , true )
game . moved . setF ield ( dest , true )
return true
else :
game . pieces . set_f ield ( start , piece )
game . pieces . setF ield ( start , piece )
except IndexDefect , ValueError :
return false
proc move_leads_to_c heck ( game : Game , start : int , dest : int ,
proc moveLeadsToC heck ( game : Game , start : int , dest : int ,
color : Color ) : bool =
## Checks in a `game` if a move from `start` to `dest` puts the `color` king in check.
var check = game
check . unchecked_m ove ( start , dest )
return check . is_in_c heck ( color )
check . uncheckedM ove ( start , dest )
return check . isInC heck ( color )
proc remove_en_p assant ( pieces : var Pieces , color : Color ) : void =
proc removeEnP assant ( pieces : var Pieces , color : Color ) : void =
## Removes every en passant of given `color` from the `game`.
for field in pieces . low .. pieces . high :
if pieces . get_f ield ( field ) = = ord ( color ) * EnPassantID :
pieces . set_f ield ( field , 0 )
if pieces . getF ield ( field ) = = ord ( color ) * EnPassantID :
pieces . setF ield ( field , 0 )
proc gen_legal_knight_m oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
proc genLegalKnightM oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
## 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 . getF ield ( field ) ! = KnightID * ord ( color ) :
return @ [ ]
var res = newSeq [ Move ] ( )
var moves = game . gen_knight_d ests ( field , color )
var moves = game . genKnightD ests ( field , color )
for dest in moves :
if not game . move_leads_to_c heck ( field , dest , color ) :
res . add ( get_m ove ( field , dest , color ) )
if not game . moveLeadsToC heck ( field , dest , color ) :
res . add ( getM ove ( field , dest , color ) )
return res
proc gen_legal_bishop_m oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
proc genLegalBishopM oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
## 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 . getF ield ( field ) ! = BishopID * ord ( color ) :
return @ [ ]
var res = newSeq [ Move ] ( )
var moves = game . gen_bishop_d ests ( field , color )
var moves = game . genBishopD ests ( field , color )
for dest in moves :
if not game . move_leads_to_c heck ( field , dest , color ) :
res . add ( get_m ove ( field , dest , color ) )
if not game . moveLeadsToC heck ( field , dest , color ) :
res . add ( getM ove ( field , dest , color ) )
return res
proc gen_legal_rook_m oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
proc genLegalRookM oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
## 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 . getF ield ( field ) ! = RookID * ord ( color ) :
return @ [ ]
var res = newSeq [ Move ] ( )
var moves = game . gen_rook_d ests ( field , color )
var moves = game . genRookD ests ( field , color )
for dest in moves :
if not game . move_leads_to_c heck ( field , dest , color ) :
res . add ( get_m ove ( field , dest , color ) )
if not game . moveLeadsToC heck ( field , dest , color ) :
res . add ( getM ove ( field , dest , color ) )
return res
proc gen_legal_queen_m oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
proc genLegalQueenM oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
## 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 . getF ield ( field ) ! = QueenID * ord ( color ) :
return @ [ ]
var res = newSeq [ Move ] ( )
var moves = game . gen_queen_d ests ( field , color )
var moves = game . genQueenD ests ( field , color )
for dest in moves :
if not game . move_leads_to_c heck ( field , dest , color ) :
res . add ( get_m ove ( field , dest , color ) )
if not game . moveLeadsToC heck ( field , dest , color ) :
res . add ( getM ove ( field , dest , color ) )
return res
proc gen_legal_king_m oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
proc genLegalKingM oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
## 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 . getF ield ( field ) ! = KingID * ord ( color ) :
return @ [ ]
var res = newSeq [ Move ] ( )
var moves = game . gen_king_d ests ( field , color )
var moves = game . genKingD ests ( field , color )
for dest in moves :
if field - dest = = W + W and game . is_a ttacked ( dest + W , color ) :
if field - dest = = W + W and game . isA ttacked ( dest + W , color ) :
continue
if field - dest = = E + E and game . is_a ttacked ( dest + E , color ) :
if field - dest = = E + E and game . isA ttacked ( dest + E , color ) :
continue
if not game . move_leads_to_c heck ( field , dest , color ) :
res . add ( get_m ove ( field , dest , color ) )
if not game . moveLeadsToC heck ( field , dest , color ) :
res . add ( getM ove ( field , dest , color ) )
return res
proc gen_pawn_p romotion ( move : Move , color : Color ) : seq [ Move ] =
proc genPawnP romotion ( 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 KnightID .. QueenID :
promotions . add ( get_m ove ( start , dest , piece , color ) )
promotions . add ( getM ove ( start , dest , piece , color ) )
return promotions
proc gen_legal_pawn_m oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
proc genLegalPawnM oves ( game : Game , field : int , color : Color ) : seq [ Move ] =
## 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 . getF ield ( field ) ! = PawnID * ord ( color ) :
return @ [ ]
var res = newSeq [ Move ] ( )
var moves = game . gen_pawn_d ests ( field , color )
var moves = game . genPawnD ests ( field , color )
for dest in moves :
if not game . move_leads_to_c heck ( field , dest , color ) :
var promotions = gen_pawn_promotion ( get_m ove ( field , dest , color ) , color )
if not game . moveLeadsToC heck ( field , dest , color ) :
var promotions = genPawnPromotion ( getM ove ( field , dest , color ) , color )
if promotions ! = @ [ ] :
res . add ( promotions )
else :
res . add ( get_m ove ( field , dest , color ) )
res . add ( getM ove ( field , dest , color ) )
return res
proc gen_legal_m oves * ( game : Game , field : int , color : Color ) : seq [ Move ] =
proc genLegalM oves * ( game : Game , field : int , color : Color ) : seq [ Move ] =
## Generates all legal moves starting from `field` in a `game` for a `color`.
var legal_moves = newSeq [ Move ] ( )
var target = ord ( color ) * game . pieces . get_f ield ( field )
var target = ord ( color ) * game . pieces . getF ield ( field )
if 0 < target and target < EnPassantID :
legal_moves = case target :
of PawnID :
game . gen_legal_pawn_m oves ( field , color )
game . genLegalPawnM oves ( field , color )
of KnightID :
game . gen_legal_knight_m oves ( field , color )
game . genLegalKnightM oves ( field , color )
of BishopID :
game . gen_legal_bishop_m oves ( field , color )
game . genLegalBishopM oves ( field , color )
of RookID :
game . gen_legal_rook_m oves ( field , color )
game . genLegalRookM oves ( field , color )
of QueenID :
game . gen_legal_queen_m oves ( field , color )
game . genLegalQueenM oves ( field , color )
of KingID :
game . gen_legal_king_m oves ( field , color )
game . genLegalKingM oves ( field , color )
else :
@ [ ]
return legal_moves
proc gen_legal_m oves * ( game : Game , color : Color ) : seq [ Move ] =
proc genLegalM oves * ( game : Game , color : Color ) : seq [ Move ] =
## Generates all legal moves in a `game` for a `color`.
var legal_moves = newSeq [ Move ] ( )
for field in game . pieces . low .. game . pieces . high :
legal_moves . add ( game . gen_legal_m oves ( field , color ) )
legal_moves . add ( game . genLegalM oves ( field , color ) )
return legal_moves
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.
## This process checks for the legality of the move and performs the switch of `game.to_move`
try :
if game . to_m ove ! = color :
if game . toM ove ! = color :
return false
var kdest = kstart
var rstart : int
@ -564,26 +630,26 @@ proc castling(game: var Game, kstart: int, dest_kingside: bool,
rstart = kstart + ( W + W + W + W )
rdest = rstart + ( E + E + E )
kdest = kstart + ( W + W )
if not game . moved . get_f ield ( kstart ) and not game . moved . get_f ield ( rstart ) :
if not game . moved . getF ield ( kstart ) and not game . moved . getF ield ( rstart ) :
var check = false
if ( dest_kingside ) :
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 + E ) , color )
check = check or game . isA ttacked ( kstart , color )
check = check or game . isA ttacked ( kstart + ( E ) , color )
check = check or game . isA ttacked ( kstart + ( E + E ) , color )
else :
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 + W ) , color )
check = check or game . isA ttacked ( kstart , color )
check = check or game . isA ttacked ( kstart + ( W ) , color )
check = check or game . isA ttacked ( kstart + ( W + W ) , color )
if check :
return false
game . unchecked_m ove ( kstart , kdest )
game . unchecked_m ove ( rstart , rdest )
game . uncheckedM ove ( kstart , kdest )
game . uncheckedM ove ( rstart , rdest )
return true
return false
except IndexDefect , ValueError :
return false
proc checked_m ove * ( game : var Game , move : Move ) : bool {. discardable . } =
proc checkedM 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`.
## This process checks for the legality of the move and performs the switch of `game.to_move`
try :
@ -591,46 +657,46 @@ proc checked_move*(game: var Game, move: Move): bool {.discardable.} =
let dest = move . dest
let color = move . color
let prom = move . prom
if game . to_m ove ! = color :
if game . toM ove ! = color :
return false
var sequence = newSeq [ Move ] ( )
let piece = game . pieces . get_f ield ( start )
let piece = game . pieces . getF ield ( start )
var create_en_passant = false
var captured_en_passant = false
var move : Move
move = get_m ove ( start , dest , color )
move = getM ove ( start , dest , color )
if ( piece = = PawnID * ord ( color ) ) :
create_en_passant = dest in game . gen_pawn_double_d ests ( start , color )
captured_en_passant = ( game . pieces . get_f ield ( dest ) = = - 1 * ord ( color ) * EnPassantID )
sequence . add ( game . gen_legal_m oves ( start , color ) )
create_en_passant = dest in game . genPawnDoubleD ests ( start , color )
captured_en_passant = ( game . pieces . getF ield ( dest ) = = - 1 * ord ( color ) * EnPassantID )
sequence . add ( game . genLegalM oves ( start , color ) )
if ( move in sequence ) :
game . pieces . remove_en_p assant ( color )
game . pieces . removeEnP assant ( color )
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 ) ) ) :
game . castling ( start , false , color )
return game . castling ( start , false , color )
else :
game . unchecked_m ove ( start , dest )
game . to_m ove = Color ( ord ( game . to_m ove ) * ( - 1 ) )
game . uncheckedM ove ( start , dest )
game . toM ove = Color ( ord ( game . toM ove ) * ( - 1 ) )
if create_en_passant :
game . pieces . set_f ield ( dest - ( N * ord ( color ) ) , EnPassantID * ord ( color ) )
game . pieces . setF ield ( dest - ( N * ord ( color ) ) , EnPassantID * ord ( color ) )
if captured_en_passant :
game . pieces . set_f ield ( dest - ( N * ord ( color ) ) , 0 )
game . pieces . setF ield ( dest - ( N * ord ( color ) ) , 0 )
if ( ( 90 < dest and dest < 99 ) or ( 20 < dest and dest < 29 ) ) and
game . pieces . get_f ield ( dest ) = = PawnID * ord ( color ) :
game . pieces . set_f ield ( dest , prom )
game . pieces . getF ield ( dest ) = = PawnID * ord ( color ) :
game . pieces . setF ield ( dest , prom )
return true
except IndexDefect , ValueError :
return false
proc has_no_m oves ( game : Game , color : Color ) : bool =
proc hasNoM oves ( game : Game , color : Color ) : bool =
## Checks if a player of a given `color` has no legal moves in a `game`.
return ( game . gen_legal_m oves ( color ) = = @ [ ] )
return ( game . genLegalM oves ( color ) = = @ [ ] )
proc is_c heckmate * ( game : Game , color : Color ) : bool =
proc isC heckmate * ( game : Game , color : Color ) : bool =
## Checks if a player of a given `color` in a `game` is checkmate.
return game . has_no_m oves ( color ) and game . is_in_c heck ( color )
return game . hasNoM oves ( color ) and game . isInC heck ( color )
proc is_s talemate * ( game : Game , color : Color ) : bool =
proc isS talemate * ( game : Game , color : Color ) : bool =
## Checks if a player of a given `color` in a `game` is stalemate.
return game . has_no_m oves ( color ) and not game . is_in_c heck ( color )
return game . hasNoM oves ( color ) and not game . isInC heck ( color )