|
@@ -10,6 +10,7 @@ pub const BLACK: Side = true;
|
|
|
|
|
|
pub type PieceType = u8;
|
|
pub type PieceType = u8;
|
|
|
|
|
|
|
|
+pub const NO_PIECE: PieceType = 255;
|
|
pub const PAWN: PieceType = 0;
|
|
pub const PAWN: PieceType = 0;
|
|
pub const KNIGHT: PieceType = 1;
|
|
pub const KNIGHT: PieceType = 1;
|
|
pub const BISHOP: PieceType = 2;
|
|
pub const BISHOP: PieceType = 2;
|
|
@@ -32,7 +33,7 @@ pub enum Move {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * \brief Iterator to serialize bitboard bit for bit
|
|
|
|
|
|
+ * @brief Iterator to serialize bitboard bit for bit
|
|
*
|
|
*
|
|
* Extracts every bit out of the bitboard and returns each one as a separate bitboard.
|
|
* Extracts every bit out of the bitboard and returns each one as a separate bitboard.
|
|
*/
|
|
*/
|
|
@@ -43,7 +44,7 @@ impl Iterator for BitboardIterator {
|
|
|
|
|
|
fn next(&mut self) -> Option<Bitboard> {
|
|
fn next(&mut self) -> Option<Bitboard> {
|
|
if self.board != 0 {
|
|
if self.board != 0 {
|
|
- let lsb = self.board & (0_u64.wrapping_sub(self.board));
|
|
|
|
|
|
+ let lsb = self.board & (self.board.wrapping_neg());
|
|
self.board ^= lsb;
|
|
self.board ^= lsb;
|
|
//Some(lsb.trailing_zeros())
|
|
//Some(lsb.trailing_zeros())
|
|
Some(lsb)
|
|
Some(lsb)
|
|
@@ -57,8 +58,13 @@ impl Iterator for BitboardIterator {
|
|
pub fn generate_moves(game: &Game, side: Side) -> Vec<Move> {
|
|
pub fn generate_moves(game: &Game, side: Side) -> Vec<Move> {
|
|
let mut moves: Vec<Move> = Vec::new();
|
|
let mut moves: Vec<Move> = Vec::new();
|
|
generate_pawn_pushes(game, side, &mut moves);
|
|
generate_pawn_pushes(game, side, &mut moves);
|
|
|
|
+ generate_pawn_doublepushes(game, side, &mut moves);
|
|
generate_pawn_captures(game, side, &mut moves);
|
|
generate_pawn_captures(game, side, &mut moves);
|
|
|
|
+ generate_knight_moves(game, side, &mut moves);
|
|
|
|
+ generate_bishop_moves(game, side, &mut moves);
|
|
|
|
+ generate_rook_moves(game, side, &mut moves);
|
|
generate_queen_moves(game, side, &mut moves);
|
|
generate_queen_moves(game, side, &mut moves);
|
|
|
|
+ generate_king_moves(game, side, &mut moves);
|
|
return moves;
|
|
return moves;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -93,6 +99,26 @@ fn generate_pawn_pushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+fn generate_pawn_doublepushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
|
|
+ let pawns = game.pawns(side) & match side { WHITE => ROW_2, BLACK => ROW_7 };
|
|
|
|
+ let others = game.get_all_side(!side);
|
|
|
|
+
|
|
|
|
+ let moved_pawns =
|
|
|
|
+ match side {
|
|
|
|
+ WHITE => north_one(north_one(pawns)),
|
|
|
|
+ BLACK => south_one(south_one(pawns))
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ let iter = BitboardIterator { board: moved_pawns & !others };
|
|
|
|
+ for p in iter {
|
|
|
|
+ let origin = match side {
|
|
|
|
+ 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 });
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
let pawns = game.pawns(side);
|
|
let pawns = game.pawns(side);
|
|
let others = game.get_all_side(!side);
|
|
let others = game.get_all_side(!side);
|
|
@@ -126,45 +152,137 @@ fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+fn generate_knight_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
|
|
+ let friends = game.get_all_side(side);
|
|
|
|
+ let others = game.get_all_side(!side);
|
|
|
|
+
|
|
|
|
+ let knights = game.knights(side);
|
|
|
|
+ let knight_iter = BitboardIterator{ board: knights };
|
|
|
|
+
|
|
|
|
+ for k in knight_iter {
|
|
|
|
+ let targets = BitboardIterator { board: get_knight_targets(square(k)) & !friends };
|
|
|
|
+ for target in targets {
|
|
|
|
+ let simple_move = SimpleMove { from: square(k), to: square(target) };
|
|
|
|
+ move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+fn get_knight_targets(square: Square) -> Bitboard {
|
|
|
|
+ /// @brief array containing the possible targets for a knight on each square.
|
|
|
|
+ /// entry at index i is a bitboard with all bits set where a knight on square i can jump
|
|
|
|
+ const TARGETS: [Bitboard; 64] = [132096, 329728, 659712, 1319424, 2638848, 5277696, 10489856,
|
|
|
|
+ 4202496, 33816580, 84410376, 168886289, 337772578, 675545156, 1351090312, 2685403152,
|
|
|
|
+ 1075839008, 8657044482, 21609056261, 43234889994, 86469779988, 172939559976, 345879119952,
|
|
|
|
+ 687463207072, 275414786112, 2216203387392, 5531918402816, 11068131838464, 22136263676928,
|
|
|
|
+ 44272527353856, 88545054707712, 175990581010432, 70506185244672, 567348067172352,
|
|
|
|
+ 1416171111120896, 2833441750646784, 5666883501293568, 11333767002587136, 22667534005174272,
|
|
|
|
+ 45053588738670592, 18049583422636032, 145241105196122112, 362539804446949376,
|
|
|
|
+ 725361088165576704, 1450722176331153408, 2901444352662306816, 5802888705324613632,
|
|
|
|
+ 11533718717099671552, 4620693356194824192, 288234782788157440, 576469569871282176,
|
|
|
|
+ 1224997833292120064, 2449995666584240128, 4899991333168480256, 9799982666336960512,
|
|
|
|
+ 1152939783987658752, 2305878468463689728, 1128098930098176, 2257297371824128, 4796069720358912,
|
|
|
|
+ 9592139440717824, 19184278881435648, 38368557762871296, 4679521487814656, 9077567998918656];
|
|
|
|
+
|
|
|
|
+ TARGETS[square as usize]
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+fn generate_bishop_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
|
|
+ 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);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+fn generate_rook_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
|
|
+ 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);
|
|
|
|
+}
|
|
|
|
|
|
fn generate_queen_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
fn generate_queen_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
let friends = game.get_all_side(side);
|
|
let friends = game.get_all_side(side);
|
|
let others = game.get_all_side(!side);
|
|
let others = game.get_all_side(!side);
|
|
|
|
|
|
- let queens = BitboardIterator { board: game.queens(side) };
|
|
|
|
|
|
+ generate_sliding_moves(friends, others, game.queens(side), QUEEN, true, true, move_list);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+fn generate_sliding_moves(friends: Bitboard, others: Bitboard, pieces: Bitboard, piece_type: PieceType,
|
|
|
|
+ straight: bool, diagonal: bool, move_list: &mut Vec<Move>) {
|
|
|
|
+ let pieces_iter = BitboardIterator { board: pieces };
|
|
|
|
|
|
- for queen in queens {
|
|
|
|
- let destinations = generate_queen_destinations(friends, others, queen);
|
|
|
|
|
|
+ for piece in pieces_iter {
|
|
|
|
+ let destinations = generate_sliding_destinations(friends, others, piece, straight, diagonal);
|
|
let dest_iter = BitboardIterator { board: destinations };
|
|
let dest_iter = BitboardIterator { board: destinations };
|
|
for dest in dest_iter {
|
|
for dest in dest_iter {
|
|
- let smove = SimpleMove{ from: square(queen), to: square(dest) };
|
|
|
|
- move_list.push(Move::Default { mov: smove, piece_type: QUEEN });
|
|
|
|
|
|
+ let smove = SimpleMove{ from: square(piece), to: square(dest) };
|
|
|
|
+ move_list.push(Move::Default { mov: smove, piece_type: piece_type});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-fn generate_queen_destinations(friends: Bitboard, others: Bitboard,
|
|
|
|
- queen: Bitboard) -> Bitboard {
|
|
|
|
|
|
+fn generate_sliding_destinations(friends: Bitboard, others: Bitboard,
|
|
|
|
+ piece: Bitboard, straight: bool,
|
|
|
|
+ diagonal: bool) -> Bitboard {
|
|
let occupied = friends | others;
|
|
let occupied = friends | others;
|
|
|
|
|
|
- let directions = [north_one, south_one, east_one, west_one,
|
|
|
|
- northeast_one, southeast_one, northwest_one, southwest_one];
|
|
|
|
-
|
|
|
|
- let mut result = 0;
|
|
|
|
- for direction in directions.into_iter() {
|
|
|
|
- let mut q = queen;
|
|
|
|
- loop {
|
|
|
|
- q = direction(q);
|
|
|
|
- result |= q;
|
|
|
|
- if q & (occupied) != 0 || q == 0 {
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+ let straights = [north_one, south_one, east_one, west_one];
|
|
|
|
+ let diagonals = [northeast_one, southeast_one, northwest_one, southwest_one];
|
|
|
|
+
|
|
|
|
+ let mut result: Bitboard = 0;
|
|
|
|
+ if straight {
|
|
|
|
+ for direction in straights.into_iter() {
|
|
|
|
+ result |= generate_direction(piece, *direction, occupied);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if diagonal {
|
|
|
|
+ for direction in diagonals.into_iter() {
|
|
|
|
+ result |= generate_direction(piece, *direction, occupied);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return result & !friends;
|
|
return result & !friends;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+fn generate_direction(piece: Bitboard, direction: fn(Bitboard) -> Bitboard, occupied: Bitboard) -> Bitboard {
|
|
|
|
+ let mut result: Bitboard = 0;
|
|
|
|
+ let mut b = piece;
|
|
|
|
+ loop {
|
|
|
|
+ b = direction(b);
|
|
|
|
+ result |= b;
|
|
|
|
+ if b & (occupied) != 0 || b == 0 {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+fn generate_king_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
|
|
|
|
+ let friends = game.get_all_side(side);
|
|
|
|
+ let others = game.get_all_side(!side);
|
|
|
|
+
|
|
|
|
+ let king = game.kings(side);
|
|
|
|
+
|
|
|
|
+ assert_eq!(king.count_ones(), 1); // assume only one king per player
|
|
|
|
+
|
|
|
|
+ let area = (north_one(king)
|
|
|
|
+ | south_one(king)
|
|
|
|
+ | east_one(king)
|
|
|
|
+ | west_one(king)
|
|
|
|
+ | northeast_one(king)
|
|
|
|
+ | northwest_one(king)
|
|
|
|
+ | southwest_one(king)
|
|
|
|
+ | southeast_one(king))
|
|
|
|
+ & !friends;
|
|
|
|
+
|
|
|
|
+ let area_iter = BitboardIterator { board: 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 });
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
#[cfg(test)]
|
|
#[cfg(test)]
|
|
mod tests {
|
|
mod tests {
|