123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754 |
- use bitboard::Bitboard;
- use bitboard::Square;
- use bitboard::*;
- use game::Game;
- use hash::{Cache, EntryType};
- use crate::hash::CacheEntry;
- pub type Side = bool;
- pub const WHITE: Side = false;
- pub const BLACK: Side = true;
- pub type PieceType = u8;
- pub const NO_PIECE: PieceType = 255;
- pub const PAWN: PieceType = 0;
- pub const KNIGHT: PieceType = 1;
- pub const BISHOP: PieceType = 2;
- pub const ROOK: PieceType = 3;
- pub const QUEEN: PieceType = 4;
- pub const KING: PieceType = 5;
- #[derive(Copy, Clone, Debug, PartialEq, Eq)]
- pub struct SimpleMove {
- pub from: Square,
- pub to: Square,
- }
- #[derive(Debug, Copy, Clone, PartialEq, Eq)]
- pub enum Move {
- 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, captured: Option<PieceType> },
- Nullmove
- }
- #[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::Nullmove
- }
- }
- impl Move {
- pub fn parse_square(sq: &str) -> Option<Square> {
- let col = sq.chars().nth(0)?;
- let row = sq.chars().nth(1)?;
- Some((row as u8 - '1' as u8) * 8 + 7 - (col as u8 - 'a' as u8))
- }
- pub fn square_to_string(sq: Square) -> String {
- let col = 7 - (sq % 8);
- let row = sq / 8;
- let colchar = (('a' as u8) + col) as char;
- let rowchar = (('1' as u8) + row) as char;
- let chars = [colchar, rowchar];
- //println!("{} {}", col, row);
- chars.iter().collect()
- }
- pub fn is_null(&self) -> bool {
- *self == Move::Nullmove
- }
- pub fn to_string(&self) -> String {
- match self {
- Move::Default{ mov, piece_type: _pt, captured: _c } => {
- Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
- },
- Move::Castling{ side, left } => {
- match (side, left) {
- (&WHITE, false) => {
- Self::square_to_string(3) + &Self::square_to_string(1)
- },
- (&WHITE, true) => {
- Self::square_to_string(3) + &Self::square_to_string(5)
- },
- (&BLACK, false) => {
- Self::square_to_string(56 + 3) + &Self::square_to_string(56 + 1)
- },
- (&BLACK, true) => {
- Self::square_to_string(56 + 3) + &Self::square_to_string(56 + 5)
- }
- }
- },
- Move::EnPassant{ mov, beaten: _ } => {
- Self::square_to_string(mov.from) + &Self::square_to_string(mov.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" }
- else if *promote_to == KNIGHT { "n" }
- else if *promote_to == BISHOP { "b" }
- else { "" }
- },
- Move::Nullmove => {
- String::from("0000")
- }
- }
- }
- pub fn is_capture(&self) -> bool {
- match self {
- Move::Default{ mov: _, piece_type: _, captured: c } => c.is_some(),
- Move::Promotion{ mov: _, promote_to: _, captured: c } => c.is_some(),
- Move::EnPassant{ mov: _, beaten: _ } => true,
- Move::Castling{ side: _, left: _ } => false,
- Move::Nullmove => false
- }
- }
- }
- /**
- * @brief Iterator to serialize bitboard bit for bit
- *
- * Extracts every bit out of the bitboard and returns each one as a separate bitboard.
- */
- pub struct BitboardIterator (pub Bitboard);
- impl Iterator for BitboardIterator {
- type Item = Bitboard;
- fn next(&mut self) -> Option<Bitboard> {
- if self.0 != 0 {
- let lsb = self.0 & (self.0.wrapping_neg());
- self.0 ^= lsb;
- //Some(lsb.trailing_zeros())
- Some(lsb)
- } else {
- None
- }
- }
- }
- impl SimpleMove {
- pub fn apply_to(self, bitboard: Bitboard) -> Bitboard {
- (bitboard & !from_square(self.from)) | from_square(self.to)
- }
- }
- pub fn generate_moves(game: &Game, side: Side) -> Vec<Move> {
- let mut moves: Vec<Move> = Vec::with_capacity(128);
- generate_pawn_pushes(game, side, &mut moves);
- generate_pawn_doublepushes(game, side, &mut moves);
- generate_pawn_captures(game, side, &mut moves);
- generate_promotions(game, side, &mut moves);
- generate_en_passant(game, side, &mut moves);
- generate_knight_moves(game, side, &mut moves, false);
- generate_bishop_moves(game, side, &mut moves, false);
- generate_rook_moves(game, side, &mut moves, false);
- generate_queen_moves(game, side, &mut moves, false);
- generate_king_moves(game, side, &mut moves, false);
- generate_castling_moves(game, side, &mut moves);
- return moves;
- }
- /**
- * generates moves that could possibly attack a king,
- * this function is used to check if the king is in check
- */
- pub fn generate_possattacking_moves(game: &Game, side: Side) -> Vec<Move> {
- let mut moves: Vec<Move> = Vec::with_capacity(32);
- generate_pawn_captures(game, side, &mut moves);
- generate_promotions(game, side, &mut moves);
- generate_knight_moves(game, side, &mut moves, true);
- generate_bishop_moves(game, side, &mut moves, true);
- generate_rook_moves(game, side, &mut moves, true);
- generate_queen_moves(game, side, &mut moves, true);
- generate_king_moves(game, side, &mut moves, true);
- return moves;
- }
- pub fn generate_legal_moves(game: &mut Game, side: Side) -> Vec<Move> {
- let moves = generate_moves(game, side);
- let check_legality = |mov: &Move| {
- let undo = game.apply(*mov);
- let legal = !is_check(game, side);
- game.undo_move(undo);
- return legal;
- };
- moves.into_iter().filter(check_legality).collect::<Vec<Move>>()
- }
- pub fn generate_legal_sorted_moves(game: &mut Game, hash: &mut Cache, killers: &[Move], ce: Option<CacheEntry>, side: Side) -> Vec<Move> {
- let moves = generate_moves(game, side);
- let illegal_value = crate::evaluate::MAX_VALUE;
- let mut mov_val_and_legality = |mov: &Move| {
- let undo = game.apply(*mov);
- let illegal = is_check(game, side);
- if illegal {
- game.undo_move(undo);
- return illegal_value;
- }
- let pv_bonus = if let Some(c) = &ce { if &c.mov == mov { 1000 } else { 0 } } else { 0 };
- let killer_bonus = if killers.contains(mov) { 200 } else { 0 };
- let eval = crate::evaluate::evaluate(game) - killer_bonus - pv_bonus;
- game.undo_move(undo);
- return eval;
- };
- let mut amovs: Vec<_> = moves.iter().map(|m| (*m, mov_val_and_legality(m))).collect();
- amovs.sort_unstable_by_key(|x| x.1);
- amovs.into_iter().filter(|x| x.1 != illegal_value).map(|(m, _v)| m).collect::<Vec<Move>>()
- }
- pub fn generate_attacking_moves(game: &Game, side: Side) -> Vec<Move> {
- let mut moves: Vec<Move> = Vec::with_capacity(32);
- generate_pawn_captures(game, side, &mut moves);
- generate_knight_moves(game, side, &mut moves, true);
- generate_bishop_moves(game, side, &mut moves, true);
- generate_rook_moves(game, side, &mut moves, true);
- generate_queen_moves(game, side, &mut moves, true);
- generate_king_moves(game, side, &mut moves, true);
- return moves;
- }
- pub fn sort_moves(game: &mut Game, hash: &mut Cache, killers: &[Move], move_list: &mut Vec<Move>) {
- move_list.sort_by_cached_key(|mov| {
- let undo = game.apply(*mov);
- if let Some(e) = hash.lookup(game) {
- game.undo_move(undo);
- if let EntryType::Value = e.entry_type {
- return e.value;
- }
- else if let EntryType::LowerBound = e.entry_type {
- return e.value - 1000;
- }
- else if let EntryType::UpperBound = e.entry_type {
- return e.value + 1000;
- }
- else {
- return crate::evaluate::evaluate(game) - if killers.contains(mov) { 200 } else { 0 };
- }
- }
- else {
- let eval = crate::evaluate::evaluate(game) - if killers.contains(mov) { 200 } else { 0 };
- game.undo_move(undo);
- return eval;
- }
- });
- }
- pub fn sort_moves_no_hash(game: &mut Game, move_list: &mut Vec<Move>) {
- move_list.sort_by_cached_key(|mov| {
- let undo = game.apply(*mov);
- let eval = crate::evaluate::evaluate(game);
- game.undo_move(undo);
- return eval;
- });
- }
- pub fn sort_quiescence(game: &mut Game, move_list: &mut Vec<Move>) {
- let value_piece = |pt| {
- match pt {
- PAWN => 1,
- KNIGHT => 2,
- BISHOP => 3,
- ROOK => 4,
- QUEEN => 5,
- KING => 6,
- _ => 0,
- }
- };
- move_list.sort_by_cached_key(|mov| {
- match *mov {
- Move::Default{ mov: _, piece_type, captured: Some(c) } => {
- value_piece(piece_type) - value_piece(c)
- },
- Move::Promotion{ mov: _, promote_to: _, captured: Some(c) } => {
- value_piece(PAWN) - value_piece(c)
- },
- Move::EnPassant{ mov: _, beaten } => {
- value_piece(PAWN) - value_piece(game.get_square(beaten).0)
- },
- _ => 0
- }
- });
- }
- fn generate_pawn_pushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
- let pawns = game.pawns(side);
- let others = game.get_all_side(!side);
- let pieces = game.get_all_side(side);
- let moved_pawns =
- match side {
- WHITE => north_one(pawns),
- BLACK => south_one(pawns)
- } & !(ROW_1 | ROW_8) & !(others | pieces);
- let iter = BitboardIterator(moved_pawns & !others);
- for p in iter {
- let origin = match side {
- WHITE => south_one(p),
- BLACK => north_one(p)
- };
- move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN, captured: None });
- }
- }
- 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 pieces = game.get_all_side(side);
- let all_pieces = others | pieces;
- let moved_pawns =
- match side {
- WHITE => north_one(north_one(pawns) & !all_pieces),
- BLACK => south_one(south_one(pawns) & !all_pieces)
- } & !all_pieces;
- let iter = BitboardIterator(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, captured: None });
- }
- }
- fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
- let pawns = game.pawns(side);
- let others = game.get_all_side(!side);
- let promotion_mask = ROW_1 | ROW_8;
- let pawn_iterator = BitboardIterator(pawns);
- for pawn in pawn_iterator {
- let left_cap = match side {
- WHITE => northeast_one(pawn),
- BLACK => southeast_one(pawn)
- };
- let right_cap = match side {
- WHITE => northwest_one(pawn),
- BLACK => southwest_one(pawn)
- };
- for cap in [left_cap, right_cap].iter() {
- if cap & others != 0 {
- 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, 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, captured: captured });
- }
- }
- }
- }
- }
- fn generate_promotions(game: &Game, side: Side, move_list: &mut Vec<Move>) {
- let pawns = game.pawns(side);
- let others = game.get_all_side(!side);
- let pieces = game.get_all_side(side);
- let moved_pawns =
- match side {
- WHITE => north_one(pawns),
- BLACK => south_one(pawns)
- } & (ROW_1 | ROW_8) & !(others | pieces);
- let iter = BitboardIterator(moved_pawns);
- for p in iter {
- let origin = match side {
- WHITE => south_one(p),
- BLACK => north_one(p)
- };
- 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, 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 });
- }
- }
- fn generate_en_passant(game: &Game, side: Side, move_list: &mut Vec<Move>) {
- if let Some(ep) = game.en_passant {
- let pawncolumn = FILE_A >> ep;
- let pawnrow: Bitboard = match side {
- WHITE => ROW_5,
- BLACK => ROW_4
- };
- let beaten_pawn = pawncolumn & pawnrow;
- if beaten_pawn & game.get_piece(PAWN, !side) == 0 {
- return;
- }
- let pawn_left = (beaten_pawn << 1) & pawnrow;
- let pawn_right = (beaten_pawn >> 1) & pawnrow;
- let attacking_pawns = game.get_piece(PAWN, side);
- let target_square = pawncolumn & match side {
- WHITE => ROW_6,
- BLACK => ROW_3
- };
- if pawn_left & attacking_pawns != 0 {
- let mov = Move::EnPassant{ mov: SimpleMove{ from: square(pawn_left), to: square(target_square) }, beaten: square(beaten_pawn) };
- move_list.push(mov);
- }
- if pawn_right & attacking_pawns != 0 {
- let mov = Move::EnPassant{ mov: SimpleMove{ from: square(pawn_right), to: square(target_square) }, beaten: square(beaten_pawn) };
- move_list.push(mov);
- }
- }
- }
- fn generate_knight_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);
- let knights = game.knights(side);
- let knight_iter = BitboardIterator(knights);
- for k in knight_iter {
- 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 simple_move = SimpleMove { from: square(k), to: square(target) };
- 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 });
- }
- }
- }
- }
- pub 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>, captures_only: bool) {
- let friends = game.get_all_side(side);
- let others = game.get_all_side(!side);
-
- 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(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(game, friends, others, game.queens(side), QUEEN, true, true, move_list, captures_only);
- }
- 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);
- let mask = if captures_only { others } else { !(0 as Bitboard) };
- for piece in pieces_iter {
- let destinations = generate_sliding_destinations(friends, others, piece, straight, diagonal);
- let dest_iter = BitboardIterator(destinations & mask);
- for dest in dest_iter {
- let smove = SimpleMove{ from: square(piece), to: square(dest) };
- 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 });
- }
- }
- }
- }
- fn generate_sliding_destinations(friends: Bitboard, others: Bitboard,
- piece: Bitboard, straight: bool,
- diagonal: bool) -> Bitboard {
- let occupied = friends | others;
- 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.iter() {
- result |= generate_direction(piece, *direction, occupied);
- }
- }
- if diagonal {
- for direction in diagonals.iter() {
- result |= generate_direction(piece, *direction, occupied);
- }
- }
- 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>, captures_only: bool) {
- 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
- if king.count_ones() != 1 { return; }
- let mask =
- if captures_only {
- !friends & others
- }
- else {
- !friends
- };
- 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))
- & mask;
- let area_iter = BitboardIterator(area);
- for destination in area_iter {
- let simple_move = SimpleMove{ from: square(king), to: square(destination) };
- let captured = game.find_piece(destination);
- move_list.push(Move::Default { mov: simple_move, piece_type: KING, captured });
- }
- }
- fn generate_castling_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
- let c1 = Move::Castling{ side: side, left: false };
- let c2 = Move::Castling{ side: side, left: true };
- let legal_castlings: &[bool] = match side {
- WHITE => &game.castling_rights[0..2],
- BLACK => &game.castling_rights[2..4],
- };
- let all_pieces = game.get_all_side(WHITE) | game.get_all_side(BLACK);
- // kingside castling
- if legal_castlings[0] {
- //info!("possible castling? {} {} {}", game.get_piece(KING, side), game.get_piece(ROOK, side), ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)));
- if ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)) != 0 &&
- ((game.get_piece(KING, side) >> 1) | (game.get_piece(KING, side) >> 2)) & all_pieces == 0 {
- let mut tg1 = game.clone();
- *tg1.get_piece_mut(KING, side) = game.get_piece(KING, side) >> 1;
- if !is_check(game, side) && !is_check(&tg1, side) {
- move_list.push(c1);
- }
- }
- }
- // queenside
- if legal_castlings[1] {
- //info!("possible castling? {} {} {}", game.get_piece(KING, side), game.get_piece(ROOK, side), ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)));
- if ((game.get_piece(KING, side) << 4) & game.get_piece(ROOK, side)) != 0 &&
- ((game.get_piece(KING, side) << 1) | (game.get_piece(KING, side) << 2) | (game.get_piece(KING, side) << 3)) & all_pieces == 0 {
- let mut tg1 = game.clone();
- let mut tg2 = game.clone();
- *tg1.get_piece_mut(KING, side) = game.get_piece(KING, side) << 1;
- *tg2.get_piece_mut(KING, side) = game.get_piece(KING, side) << 2;
- if !is_check(game, side) && !is_check(&tg1, side) && !is_check(&tg2, side) {
- move_list.push(c2);
- }
- }
- }
- }
- pub fn is_check(game: &Game, side: Side) -> bool {
- let king = game.get_piece(KING, side);
- let king_square = square(king);
- let friends = game.get_all_side(side);
- let others = game.get_all_side(!side);
- let knights = get_knight_targets(king_square);
- if knights & game.get_piece(KNIGHT, !side) != 0 {
- return true;
- }
- let diagonal = generate_sliding_destinations(friends, others, king, false, true);
- let straight = generate_sliding_destinations(friends, others, king, true, false);
- if diagonal & game.get_piece(BISHOP, !side) != 0 {
- return true;
- }
- if diagonal & game.get_piece(QUEEN, !side) != 0 {
- return true;
- }
- if straight & game.get_piece(ROOK, !side) != 0 {
- return true;
- }
- if straight & game.get_piece(QUEEN, !side) != 0 {
- return true;
- }
- if side == BLACK {
- if ((southeast_one(king) | southwest_one(king)) & game.get_piece(PAWN, !side)) != 0 {
- return true;
- }
- }
- else {
- if ((northeast_one(king) | northwest_one(king)) & game.get_piece(PAWN, !side)) != 0 {
- return true;
- }
- }
- let king_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);
- if king_area & game.get_piece(KING, !side) != 0 {
- return true;
- }
- return false;
- }
- /**
- * checks if side's king is in check
- */
- pub fn is_check_old(game: &Game, side: Side) -> bool {
- let king = game.get_piece(KING, side);
- let king_square = square(king);
- let possible_attacks = generate_possattacking_moves(game, !side);
- for mov in possible_attacks {
- if let Move::Default{ mov, piece_type: _, captured: _ } = mov {
- if mov.to == king_square {
- if !is_check(game, side) {
- panic!("incorrect non-check {}", game.beautiful_print());
- }
- return true;
- }
- }
- else if let Move::Promotion{ mov, promote_to: _, captured: _ } = mov {
- if mov.to == king_square {
- if !is_check(game, side) {
- panic!("incorrect non-check {}", game.beautiful_print());
- }
- return true;
- }
- }
- }
- if is_check(game, side) {
- panic!("incorrect check {}", game.beautiful_print());
- }
- false
- }
- /*
- #[cfg(test)]
- mod tests {
- use search::Game;
- use movegen::*;
- #[test]
- fn pawn_pushes() {
- let mut game: Game = Game::default();
- let pawn_moves = generate_pawn_moves(&game, WHITE);
- assert_eq!(pawn_moves, ());
- }
- }
- */
|