|
@@ -26,32 +26,28 @@ pub struct SimpleMove {
|
|
|
pub to: Square,
|
|
|
}
|
|
|
|
|
|
+struct MovePieceTypes(u8);
|
|
|
+
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
pub enum Move {
|
|
|
- Default { mov: SimpleMove, piece_type: PieceType },
|
|
|
+ Default { mov: SimpleMove, piece_type: PieceType, captured: Option<PieceType> },
|
|
|
Castling { side: Side, left: bool },
|
|
|
EnPassant { mov: SimpleMove, beaten: Square },
|
|
|
- Promotion { mov: SimpleMove, promote_to: PieceType },
|
|
|
+ Promotion { mov: SimpleMove, promote_to: PieceType, captured: Option<PieceType> },
|
|
|
}
|
|
|
|
|
|
-enum MoveUndo {
|
|
|
- Default {
|
|
|
- piece_type: PieceType,
|
|
|
- before: Bitboard,
|
|
|
- captured_type: PieceType,
|
|
|
- captured_before: Bitboard,
|
|
|
- },
|
|
|
- Castling { rooks_before: Bitboard, king_before: Bitboard },
|
|
|
- Promotion {
|
|
|
- promoted_to: PieceType,
|
|
|
- promoted_to_before: Bitboard,
|
|
|
- pawns_before: Bitboard
|
|
|
- }
|
|
|
+
|
|
|
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
+pub struct MoveUndo {
|
|
|
+ pub castling_rights_before: [bool; 4],
|
|
|
+ pub halfmoves_since_last_event_before: i8,
|
|
|
+ pub en_passant_before: Option<u8>,
|
|
|
+ pub mov: Move
|
|
|
}
|
|
|
|
|
|
impl Default for Move {
|
|
|
fn default() -> Move {
|
|
|
- Move::Default{ mov: SimpleMove { from: 0, to: 0 }, piece_type: NO_PIECE }
|
|
|
+ Move::Default{ mov: SimpleMove { from: 0, to: 0 }, piece_type: NO_PIECE, captured: None }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -79,7 +75,7 @@ impl Move {
|
|
|
|
|
|
pub fn to_string(&self) -> String {
|
|
|
match self {
|
|
|
- Move::Default{ mov, piece_type } => {
|
|
|
+ Move::Default{ mov, piece_type: _pt, captured: _c } => {
|
|
|
Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
|
|
|
},
|
|
|
Move::Castling{ side, left } => {
|
|
@@ -98,10 +94,10 @@ impl Move {
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
- Move::EnPassant{ mov, beaten } => {
|
|
|
+ Move::EnPassant{ mov, beaten: _ } => {
|
|
|
Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
|
|
|
},
|
|
|
- Move::Promotion{ mov, promote_to } => {
|
|
|
+ Move::Promotion{ mov, promote_to, captured: _c } => {
|
|
|
Self::square_to_string(mov.from) + &Self::square_to_string(mov.to) +
|
|
|
if *promote_to == QUEEN { "Q" }
|
|
|
else if *promote_to == ROOK { "R" }
|
|
@@ -204,9 +200,9 @@ pub fn sort_moves(game: &Game, move_list: &mut Vec<Move>) {
|
|
|
|
|
|
move_list.sort_by_key(|mov| {
|
|
|
match mov {
|
|
|
- Move::Default { mov, piece_type } => if (from_square(mov.to) & all_pieces) != 0 { -10 } else { 0 },
|
|
|
+ Move::Default { mov, piece_type: _, captured } => if let None = captured { 0 } else { -10 }, //if (from_square(mov.to) & all_pieces) != 0 { -10 } else { 0 },
|
|
|
Move::Castling { side: _, left: _ } => 0,
|
|
|
- Move::Promotion { mov, promote_to } => -15,
|
|
|
+ Move::Promotion { mov: _, promote_to: _, captured: _ } => -15,
|
|
|
Move::EnPassant { mov: _, beaten: _ } => -10,
|
|
|
}
|
|
|
});
|
|
@@ -229,7 +225,7 @@ fn generate_pawn_pushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
|
WHITE => south_one(p),
|
|
|
BLACK => north_one(p)
|
|
|
};
|
|
|
- move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN });
|
|
|
+ move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN, captured: None });
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -252,7 +248,7 @@ fn generate_pawn_doublepushes(game: &Game, side: Side, move_list: &mut Vec<Move>
|
|
|
WHITE => south_one(south_one(p)),
|
|
|
BLACK => north_one(north_one(p))
|
|
|
};
|
|
|
- move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN });
|
|
|
+ move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN, captured: None });
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -275,14 +271,15 @@ fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
|
|
|
|
for cap in [left_cap, right_cap].iter() {
|
|
|
if cap & others != 0 {
|
|
|
- let simple_move = SimpleMove { from: square(pawn), to: square(*cap) };
|
|
|
+ let captured = game.find_piece(*cap);
|
|
|
+ let simple_move = SimpleMove { from: square(pawn), to: square(*cap)};
|
|
|
if cap & promotion_mask != 0 {
|
|
|
- move_list.push(Move::Promotion { mov: simple_move, promote_to: QUEEN });
|
|
|
- move_list.push(Move::Promotion { mov: simple_move, promote_to: ROOK });
|
|
|
- move_list.push(Move::Promotion { mov: simple_move, promote_to: BISHOP });
|
|
|
- move_list.push(Move::Promotion { mov: simple_move, promote_to: KNIGHT });
|
|
|
+ move_list.push(Move::Promotion { mov: simple_move, promote_to: QUEEN, captured: captured });
|
|
|
+ move_list.push(Move::Promotion { mov: simple_move, promote_to: ROOK, captured: captured });
|
|
|
+ move_list.push(Move::Promotion { mov: simple_move, promote_to: BISHOP, captured: captured });
|
|
|
+ move_list.push(Move::Promotion { mov: simple_move, promote_to: KNIGHT, captured: captured });
|
|
|
} else {
|
|
|
- move_list.push(Move::Default { mov: simple_move, piece_type: PAWN });
|
|
|
+ move_list.push(Move::Default { mov: simple_move, piece_type: PAWN, captured: captured });
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -308,10 +305,10 @@ fn generate_promotions(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
|
};
|
|
|
let movement = SimpleMove { from: square(origin), to: square(p) };
|
|
|
//move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN });
|
|
|
- move_list.push(Move::Promotion { mov: movement, promote_to: QUEEN });
|
|
|
- move_list.push(Move::Promotion { mov: movement, promote_to: ROOK });
|
|
|
- move_list.push(Move::Promotion { mov: movement, promote_to: BISHOP });
|
|
|
- move_list.push(Move::Promotion { mov: movement, promote_to: KNIGHT });
|
|
|
+ move_list.push(Move::Promotion { mov: movement, promote_to: QUEEN, captured: None });
|
|
|
+ move_list.push(Move::Promotion { mov: movement, promote_to: ROOK, captured: None });
|
|
|
+ move_list.push(Move::Promotion { mov: movement, promote_to: BISHOP, captured: None });
|
|
|
+ move_list.push(Move::Promotion { mov: movement, promote_to: KNIGHT, captured: None });
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -358,15 +355,20 @@ fn generate_knight_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, cap
|
|
|
let knight_iter = BitboardIterator(knights);
|
|
|
|
|
|
for k in knight_iter {
|
|
|
- let target_mask = if captures_only {
|
|
|
- !friends & others
|
|
|
- } else {
|
|
|
- !friends
|
|
|
- };
|
|
|
- let targets = BitboardIterator(get_knight_targets(square(k)) & target_mask);
|
|
|
- for target in targets {
|
|
|
+ let cap_targets = BitboardIterator(get_knight_targets(square(k)) & (!friends & others));
|
|
|
+ let nocap_targets = BitboardIterator(get_knight_targets(square(k)) & (!friends & !others));
|
|
|
+
|
|
|
+ for target in cap_targets {
|
|
|
+ let target_square = square(target);
|
|
|
let simple_move = SimpleMove { from: square(k), to: square(target) };
|
|
|
- move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT });
|
|
|
+ let captured = game.find_piece(target);
|
|
|
+ move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT, captured });
|
|
|
+ }
|
|
|
+ if !captures_only {
|
|
|
+ for target in nocap_targets {
|
|
|
+ let simple_move = SimpleMove { from: square(k), to: square(target) };
|
|
|
+ move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT, captured: None });
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -394,24 +396,24 @@ fn generate_bishop_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, cap
|
|
|
let friends = game.get_all_side(side);
|
|
|
let others = game.get_all_side(!side);
|
|
|
|
|
|
- generate_sliding_moves(friends, others, game.bishops(side), BISHOP, false, true, move_list, captures_only);
|
|
|
+ generate_sliding_moves(game, friends, others, game.bishops(side), BISHOP, false, true, move_list, captures_only);
|
|
|
}
|
|
|
|
|
|
fn generate_rook_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
|
|
|
let friends = game.get_all_side(side);
|
|
|
let others = game.get_all_side(!side);
|
|
|
|
|
|
- generate_sliding_moves(friends, others, game.rooks(side), ROOK, true, false, move_list, captures_only);
|
|
|
+ generate_sliding_moves(game, friends, others, game.rooks(side), ROOK, true, false, move_list, captures_only);
|
|
|
}
|
|
|
|
|
|
fn generate_queen_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
|
|
|
let friends = game.get_all_side(side);
|
|
|
let others = game.get_all_side(!side);
|
|
|
|
|
|
- generate_sliding_moves(friends, others, game.queens(side), QUEEN, true, true, move_list, captures_only);
|
|
|
+ generate_sliding_moves(game, friends, others, game.queens(side), QUEEN, true, true, move_list, captures_only);
|
|
|
}
|
|
|
|
|
|
-fn generate_sliding_moves(friends: Bitboard, others: Bitboard, pieces: Bitboard, piece_type: PieceType,
|
|
|
+fn generate_sliding_moves(game: &Game, friends: Bitboard, others: Bitboard, pieces: Bitboard, piece_type: PieceType,
|
|
|
straight: bool, diagonal: bool, move_list: &mut Vec<Move>, captures_only: bool) {
|
|
|
let pieces_iter = BitboardIterator(pieces);
|
|
|
|
|
@@ -422,7 +424,12 @@ fn generate_sliding_moves(friends: Bitboard, others: Bitboard, pieces: Bitboard,
|
|
|
let dest_iter = BitboardIterator(destinations & mask);
|
|
|
for dest in dest_iter {
|
|
|
let smove = SimpleMove{ from: square(piece), to: square(dest) };
|
|
|
- move_list.push(Move::Default { mov: smove, piece_type: piece_type});
|
|
|
+ if dest & others != 0 {
|
|
|
+ move_list.push(Move::Default { mov: smove, piece_type: piece_type, captured: game.find_piece(dest) });
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ move_list.push(Move::Default { mov: smove, piece_type: piece_type, captured: None });
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -495,7 +502,8 @@ fn generate_king_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captu
|
|
|
let area_iter = BitboardIterator(area);
|
|
|
for destination in area_iter {
|
|
|
let simple_move = SimpleMove{ from: square(king), to: square(destination) };
|
|
|
- move_list.push(Move::Default { mov: simple_move, piece_type: KING });
|
|
|
+ let captured = game.find_piece(destination);
|
|
|
+ move_list.push(Move::Default { mov: simple_move, piece_type: KING, captured });
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -551,12 +559,12 @@ pub fn is_check(game: &Game, side: Side) -> bool {
|
|
|
let king_square = square(game.get_piece(KING, side));
|
|
|
let possible_attacks = generate_possattacking_moves(game, !side);
|
|
|
for mov in possible_attacks {
|
|
|
- if let Move::Default{ mov, piece_type: _ } = mov {
|
|
|
+ if let Move::Default{ mov, piece_type: _, captured: _ } = mov {
|
|
|
if mov.to == king_square {
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
- else if let Move::Promotion{ mov, promote_to: _ } = mov {
|
|
|
+ else if let Move::Promotion{ mov, promote_to: _, captured: _ } = mov {
|
|
|
if mov.to == king_square {
|
|
|
return true;
|
|
|
}
|