movegen.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. use bitboard::Bitboard;
  2. use bitboard::Square;
  3. use bitboard::*;
  4. use game::Game;
  5. use hash::Cache;
  6. use log::info;
  7. pub type Side = bool;
  8. pub const WHITE: Side = false;
  9. pub const BLACK: Side = true;
  10. pub type PieceType = u8;
  11. pub const NO_PIECE: PieceType = 255;
  12. pub const PAWN: PieceType = 0;
  13. pub const KNIGHT: PieceType = 1;
  14. pub const BISHOP: PieceType = 2;
  15. pub const ROOK: PieceType = 3;
  16. pub const QUEEN: PieceType = 4;
  17. pub const KING: PieceType = 5;
  18. #[derive(Copy, Clone, Debug, PartialEq, Eq)]
  19. pub struct SimpleMove {
  20. pub from: Square,
  21. pub to: Square,
  22. }
  23. struct MovePieceTypes(u8);
  24. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  25. pub enum Move {
  26. Default { mov: SimpleMove, piece_type: PieceType, captured: Option<PieceType> },
  27. Castling { side: Side, left: bool },
  28. EnPassant { mov: SimpleMove, beaten: Square },
  29. Promotion { mov: SimpleMove, promote_to: PieceType, captured: Option<PieceType> },
  30. Nullmove
  31. }
  32. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  33. pub struct MoveUndo {
  34. pub castling_rights_before: [bool; 4],
  35. pub halfmoves_since_last_event_before: i8,
  36. pub en_passant_before: Option<u8>,
  37. pub mov: Move
  38. }
  39. impl Default for Move {
  40. fn default() -> Move {
  41. Move::Nullmove
  42. }
  43. }
  44. impl Move {
  45. pub fn parse_square(sq: &str) -> Option<Square> {
  46. let col = sq.chars().nth(0)?;
  47. let row = sq.chars().nth(1)?;
  48. Some((row as u8 - '1' as u8) * 8 + 7 - (col as u8 - 'a' as u8))
  49. }
  50. pub fn square_to_string(sq: Square) -> String {
  51. let col = 7 - (sq % 8);
  52. let row = sq / 8;
  53. let colchar = (('a' as u8) + col) as char;
  54. let rowchar = (('1' as u8) + row) as char;
  55. let chars = [colchar, rowchar];
  56. //println!("{} {}", col, row);
  57. chars.iter().collect()
  58. }
  59. pub fn to_string(&self) -> String {
  60. match self {
  61. Move::Default{ mov, piece_type: _pt, captured: _c } => {
  62. Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
  63. },
  64. Move::Castling{ side, left } => {
  65. match (side, left) {
  66. (&WHITE, false) => {
  67. Self::square_to_string(3) + &Self::square_to_string(1)
  68. },
  69. (&WHITE, true) => {
  70. Self::square_to_string(3) + &Self::square_to_string(5)
  71. },
  72. (&BLACK, false) => {
  73. Self::square_to_string(56 + 3) + &Self::square_to_string(56 + 1)
  74. },
  75. (&BLACK, true) => {
  76. Self::square_to_string(56 + 3) + &Self::square_to_string(56 + 5)
  77. }
  78. }
  79. },
  80. Move::EnPassant{ mov, beaten: _ } => {
  81. Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
  82. },
  83. Move::Promotion{ mov, promote_to, captured: _c } => {
  84. Self::square_to_string(mov.from) + &Self::square_to_string(mov.to) +
  85. if *promote_to == QUEEN { "q" }
  86. else if *promote_to == ROOK { "r" }
  87. else if *promote_to == KNIGHT { "n" }
  88. else if *promote_to == BISHOP { "b" }
  89. else { "" }
  90. },
  91. Move::Nullmove => {
  92. String::from("0000")
  93. }
  94. }
  95. }
  96. }
  97. /**
  98. * @brief Iterator to serialize bitboard bit for bit
  99. *
  100. * Extracts every bit out of the bitboard and returns each one as a separate bitboard.
  101. */
  102. pub struct BitboardIterator (pub Bitboard);
  103. impl Iterator for BitboardIterator {
  104. type Item = Bitboard;
  105. fn next(&mut self) -> Option<Bitboard> {
  106. if self.0 != 0 {
  107. let lsb = self.0 & (self.0.wrapping_neg());
  108. self.0 ^= lsb;
  109. //Some(lsb.trailing_zeros())
  110. Some(lsb)
  111. } else {
  112. None
  113. }
  114. }
  115. }
  116. impl SimpleMove {
  117. pub fn apply_to(self, bitboard: Bitboard) -> Bitboard {
  118. (bitboard & !from_square(self.from)) | from_square(self.to)
  119. }
  120. }
  121. pub fn generate_moves(game: &Game, side: Side) -> Vec<Move> {
  122. let mut moves: Vec<Move> = Vec::with_capacity(128);
  123. generate_pawn_pushes(game, side, &mut moves);
  124. generate_pawn_doublepushes(game, side, &mut moves);
  125. generate_pawn_captures(game, side, &mut moves);
  126. generate_promotions(game, side, &mut moves);
  127. generate_en_passant(game, side, &mut moves);
  128. generate_knight_moves(game, side, &mut moves, false);
  129. generate_bishop_moves(game, side, &mut moves, false);
  130. generate_rook_moves(game, side, &mut moves, false);
  131. generate_queen_moves(game, side, &mut moves, false);
  132. generate_king_moves(game, side, &mut moves, false);
  133. generate_castling_moves(game, side, &mut moves);
  134. return moves;
  135. }
  136. /**
  137. * generates moves that could possibly attack a king,
  138. * this function is used to check if the king is in check
  139. */
  140. pub fn generate_possattacking_moves(game: &Game, side: Side) -> Vec<Move> {
  141. let mut moves: Vec<Move> = Vec::with_capacity(32);
  142. generate_pawn_captures(game, side, &mut moves);
  143. generate_promotions(game, side, &mut moves);
  144. generate_knight_moves(game, side, &mut moves, true);
  145. generate_bishop_moves(game, side, &mut moves, true);
  146. generate_rook_moves(game, side, &mut moves, true);
  147. generate_queen_moves(game, side, &mut moves, true);
  148. generate_king_moves(game, side, &mut moves, true);
  149. return moves;
  150. }
  151. pub fn generate_legal_moves(game: &Game, side: Side) -> Vec<Move> {
  152. let moves = generate_moves(game, side);
  153. moves.into_iter().filter(|mov| {
  154. let tryout = crate::search::apply_move(game, *mov);
  155. !is_check(&tryout, side)
  156. }).collect::<Vec<Move>>()
  157. }
  158. pub fn generate_attacking_moves(game: &Game, side: Side) -> Vec<Move> {
  159. let mut moves: Vec<Move> = Vec::with_capacity(32);
  160. generate_pawn_captures(game, side, &mut moves);
  161. generate_knight_moves(game, side, &mut moves, true);
  162. generate_bishop_moves(game, side, &mut moves, true);
  163. generate_rook_moves(game, side, &mut moves, true);
  164. generate_queen_moves(game, side, &mut moves, true);
  165. generate_king_moves(game, side, &mut moves, true);
  166. return moves;
  167. }
  168. pub fn sort_moves(game: &Game, hash: &mut Cache, move_list: &mut Vec<Move>) {
  169. let all_pieces = game.get_all_side(WHITE) | game.get_all_side(BLACK);
  170. move_list.sort_by_cached_key(|mov| {
  171. let new_game = crate::search::apply_move(game, *mov);
  172. if let Some(e) = hash.lookup(&new_game) {
  173. return e.value;
  174. }
  175. else {
  176. return crate::evaluate::evaluate(&new_game);
  177. }
  178. match mov {
  179. Move::Default { mov, piece_type: _, captured } => if let None = captured { 0 } else { -10 }, //if (from_square(mov.to) & all_pieces) != 0 { -10 } else { 0 },
  180. Move::Castling { side: _, left: _ } => 0,
  181. Move::Promotion { mov: _, promote_to: _, captured: _ } => -15,
  182. Move::EnPassant { mov: _, beaten: _ } => -10,
  183. Move::Nullmove => 0,
  184. }
  185. });
  186. }
  187. fn generate_pawn_pushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  188. let pawns = game.pawns(side);
  189. let others = game.get_all_side(!side);
  190. let pieces = game.get_all_side(side);
  191. let moved_pawns =
  192. match side {
  193. WHITE => north_one(pawns),
  194. BLACK => south_one(pawns)
  195. } & !(ROW_1 | ROW_8) & !(others | pieces);
  196. let iter = BitboardIterator(moved_pawns & !others);
  197. for p in iter {
  198. let origin = match side {
  199. WHITE => south_one(p),
  200. BLACK => north_one(p)
  201. };
  202. move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN, captured: None });
  203. }
  204. }
  205. fn generate_pawn_doublepushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  206. let pawns = game.pawns(side) & match side { WHITE => ROW_2, BLACK => ROW_7 };
  207. let others = game.get_all_side(!side);
  208. let pieces = game.get_all_side(side);
  209. let all_pieces = others | pieces;
  210. let moved_pawns =
  211. match side {
  212. WHITE => north_one(north_one(pawns) & !all_pieces),
  213. BLACK => south_one(south_one(pawns) & !all_pieces)
  214. } & !all_pieces;
  215. let iter = BitboardIterator(moved_pawns & !others);
  216. for p in iter {
  217. let origin = match side {
  218. WHITE => south_one(south_one(p)),
  219. BLACK => north_one(north_one(p))
  220. };
  221. move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN, captured: None });
  222. }
  223. }
  224. fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  225. let pawns = game.pawns(side);
  226. let others = game.get_all_side(!side);
  227. let promotion_mask = ROW_1 | ROW_8;
  228. let pawn_iterator = BitboardIterator(pawns);
  229. for pawn in pawn_iterator {
  230. let left_cap = match side {
  231. WHITE => northeast_one(pawn),
  232. BLACK => southeast_one(pawn)
  233. };
  234. let right_cap = match side {
  235. WHITE => northwest_one(pawn),
  236. BLACK => southwest_one(pawn)
  237. };
  238. for cap in [left_cap, right_cap].iter() {
  239. if cap & others != 0 {
  240. let captured = game.find_piece(*cap);
  241. let simple_move = SimpleMove { from: square(pawn), to: square(*cap)};
  242. if cap & promotion_mask != 0 {
  243. move_list.push(Move::Promotion { mov: simple_move, promote_to: QUEEN, captured: captured });
  244. move_list.push(Move::Promotion { mov: simple_move, promote_to: ROOK, captured: captured });
  245. move_list.push(Move::Promotion { mov: simple_move, promote_to: BISHOP, captured: captured });
  246. move_list.push(Move::Promotion { mov: simple_move, promote_to: KNIGHT, captured: captured });
  247. } else {
  248. move_list.push(Move::Default { mov: simple_move, piece_type: PAWN, captured: captured });
  249. }
  250. }
  251. }
  252. }
  253. }
  254. fn generate_promotions(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  255. let pawns = game.pawns(side);
  256. let others = game.get_all_side(!side);
  257. let pieces = game.get_all_side(side);
  258. let moved_pawns =
  259. match side {
  260. WHITE => north_one(pawns),
  261. BLACK => south_one(pawns)
  262. } & (ROW_1 | ROW_8) & !(others | pieces);
  263. let iter = BitboardIterator(moved_pawns);
  264. for p in iter {
  265. let origin = match side {
  266. WHITE => south_one(p),
  267. BLACK => north_one(p)
  268. };
  269. let movement = SimpleMove { from: square(origin), to: square(p) };
  270. //move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN });
  271. move_list.push(Move::Promotion { mov: movement, promote_to: QUEEN, captured: None });
  272. move_list.push(Move::Promotion { mov: movement, promote_to: ROOK, captured: None });
  273. move_list.push(Move::Promotion { mov: movement, promote_to: BISHOP, captured: None });
  274. move_list.push(Move::Promotion { mov: movement, promote_to: KNIGHT, captured: None });
  275. }
  276. }
  277. fn generate_en_passant(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  278. if let Some(ep) = game.en_passant {
  279. let pawncolumn = A_FILE >> ep;
  280. let pawnrow: Bitboard = match side {
  281. WHITE => ROW_5,
  282. BLACK => ROW_4
  283. };
  284. let beaten_pawn = pawncolumn & pawnrow;
  285. if beaten_pawn & game.get_piece(PAWN, !side) == 0 {
  286. return;
  287. }
  288. let pawn_left = (beaten_pawn << 1) & pawnrow;
  289. let pawn_right = (beaten_pawn >> 1) & pawnrow;
  290. let attacking_pawns = game.get_piece(PAWN, side);
  291. let target_square = pawncolumn & match side {
  292. WHITE => ROW_6,
  293. BLACK => ROW_3
  294. };
  295. if pawn_left & attacking_pawns != 0 {
  296. let mov = Move::EnPassant{ mov: SimpleMove{ from: square(pawn_left), to: square(target_square) }, beaten: square(beaten_pawn) };
  297. move_list.push(mov);
  298. }
  299. if pawn_right & attacking_pawns != 0 {
  300. let mov = Move::EnPassant{ mov: SimpleMove{ from: square(pawn_right), to: square(target_square) }, beaten: square(beaten_pawn) };
  301. move_list.push(mov);
  302. }
  303. }
  304. }
  305. fn generate_knight_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  306. let friends = game.get_all_side(side);
  307. let others = game.get_all_side(!side);
  308. let knights = game.knights(side);
  309. let knight_iter = BitboardIterator(knights);
  310. for k in knight_iter {
  311. let cap_targets = BitboardIterator(get_knight_targets(square(k)) & (!friends & others));
  312. let nocap_targets = BitboardIterator(get_knight_targets(square(k)) & (!friends & !others));
  313. for target in cap_targets {
  314. let target_square = square(target);
  315. let simple_move = SimpleMove { from: square(k), to: square(target) };
  316. let captured = game.find_piece(target);
  317. move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT, captured });
  318. }
  319. if !captures_only {
  320. for target in nocap_targets {
  321. let simple_move = SimpleMove { from: square(k), to: square(target) };
  322. move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT, captured: None });
  323. }
  324. }
  325. }
  326. }
  327. pub fn get_knight_targets(square: Square) -> Bitboard {
  328. /// @brief array containing the possible targets for a knight on each square.
  329. /// entry at index i is a bitboard with all bits set where a knight on square i can jump
  330. const TARGETS: [Bitboard; 64] = [132096, 329728, 659712, 1319424, 2638848, 5277696, 10489856,
  331. 4202496, 33816580, 84410376, 168886289, 337772578, 675545156, 1351090312, 2685403152,
  332. 1075839008, 8657044482, 21609056261, 43234889994, 86469779988, 172939559976, 345879119952,
  333. 687463207072, 275414786112, 2216203387392, 5531918402816, 11068131838464, 22136263676928,
  334. 44272527353856, 88545054707712, 175990581010432, 70506185244672, 567348067172352,
  335. 1416171111120896, 2833441750646784, 5666883501293568, 11333767002587136, 22667534005174272,
  336. 45053588738670592, 18049583422636032, 145241105196122112, 362539804446949376,
  337. 725361088165576704, 1450722176331153408, 2901444352662306816, 5802888705324613632,
  338. 11533718717099671552, 4620693356194824192, 288234782788157440, 576469569871282176,
  339. 1224997833292120064, 2449995666584240128, 4899991333168480256, 9799982666336960512,
  340. 1152939783987658752, 2305878468463689728, 1128098930098176, 2257297371824128, 4796069720358912,
  341. 9592139440717824, 19184278881435648, 38368557762871296, 4679521487814656, 9077567998918656];
  342. TARGETS[square as usize]
  343. }
  344. fn generate_bishop_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  345. let friends = game.get_all_side(side);
  346. let others = game.get_all_side(!side);
  347. generate_sliding_moves(game, friends, others, game.bishops(side), BISHOP, false, true, move_list, captures_only);
  348. }
  349. fn generate_rook_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  350. let friends = game.get_all_side(side);
  351. let others = game.get_all_side(!side);
  352. generate_sliding_moves(game, friends, others, game.rooks(side), ROOK, true, false, move_list, captures_only);
  353. }
  354. fn generate_queen_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  355. let friends = game.get_all_side(side);
  356. let others = game.get_all_side(!side);
  357. generate_sliding_moves(game, friends, others, game.queens(side), QUEEN, true, true, move_list, captures_only);
  358. }
  359. fn generate_sliding_moves(game: &Game, friends: Bitboard, others: Bitboard, pieces: Bitboard, piece_type: PieceType,
  360. straight: bool, diagonal: bool, move_list: &mut Vec<Move>, captures_only: bool) {
  361. let pieces_iter = BitboardIterator(pieces);
  362. let mask = if captures_only { others } else { !(0 as Bitboard) };
  363. for piece in pieces_iter {
  364. let destinations = generate_sliding_destinations(friends, others, piece, straight, diagonal);
  365. let dest_iter = BitboardIterator(destinations & mask);
  366. for dest in dest_iter {
  367. let smove = SimpleMove{ from: square(piece), to: square(dest) };
  368. if dest & others != 0 {
  369. move_list.push(Move::Default { mov: smove, piece_type: piece_type, captured: game.find_piece(dest) });
  370. }
  371. else {
  372. move_list.push(Move::Default { mov: smove, piece_type: piece_type, captured: None });
  373. }
  374. }
  375. }
  376. }
  377. fn generate_sliding_destinations(friends: Bitboard, others: Bitboard,
  378. piece: Bitboard, straight: bool,
  379. diagonal: bool) -> Bitboard {
  380. let occupied = friends | others;
  381. let straights = [north_one, south_one, east_one, west_one];
  382. let diagonals = [northeast_one, southeast_one, northwest_one, southwest_one];
  383. let mut result: Bitboard = 0;
  384. if straight {
  385. for direction in straights.iter() {
  386. result |= generate_direction(piece, *direction, occupied);
  387. }
  388. }
  389. if diagonal {
  390. for direction in diagonals.iter() {
  391. result |= generate_direction(piece, *direction, occupied);
  392. }
  393. }
  394. return result & !friends;
  395. }
  396. fn generate_direction(piece: Bitboard, direction: fn(Bitboard) -> Bitboard, occupied: Bitboard) -> Bitboard {
  397. let mut result: Bitboard = 0;
  398. let mut b = piece;
  399. loop {
  400. b = direction(b);
  401. result |= b;
  402. if b & (occupied) != 0 || b == 0 {
  403. break;
  404. }
  405. }
  406. return result;
  407. }
  408. fn generate_king_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  409. let friends = game.get_all_side(side);
  410. let others = game.get_all_side(!side);
  411. let king = game.kings(side);
  412. //assert_eq!(king.count_ones(), 1); // assume only one king per player
  413. if king.count_ones() != 1 { return; }
  414. let mask =
  415. if captures_only {
  416. !friends & others
  417. }
  418. else {
  419. !friends
  420. };
  421. let area = (north_one(king)
  422. | south_one(king)
  423. | east_one(king)
  424. | west_one(king)
  425. | northeast_one(king)
  426. | northwest_one(king)
  427. | southwest_one(king)
  428. | southeast_one(king))
  429. & mask;
  430. let area_iter = BitboardIterator(area);
  431. for destination in area_iter {
  432. let simple_move = SimpleMove{ from: square(king), to: square(destination) };
  433. let captured = game.find_piece(destination);
  434. move_list.push(Move::Default { mov: simple_move, piece_type: KING, captured });
  435. }
  436. }
  437. fn generate_castling_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  438. let c1 = Move::Castling{ side: side, left: false };
  439. let c2 = Move::Castling{ side: side, left: true };
  440. let legal_castlings: &[bool] = match side {
  441. WHITE => &game.castling_rights[0..2],
  442. BLACK => &game.castling_rights[2..4],
  443. };
  444. let all_pieces = game.get_all_side(WHITE) | game.get_all_side(BLACK);
  445. // kingside castling
  446. if legal_castlings[0] {
  447. //info!("possible castling? {} {} {}", game.get_piece(KING, side), game.get_piece(ROOK, side), ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)));
  448. if ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)) != 0 &&
  449. ((game.get_piece(KING, side) >> 1) | (game.get_piece(KING, side) >> 2)) & all_pieces == 0 {
  450. let mut tg1 = game.clone();
  451. *tg1.get_piece_mut(KING, side) = game.get_piece(KING, side) >> 1;
  452. if !is_check(game, side) && !is_check(&tg1, side) {
  453. move_list.push(c1);
  454. }
  455. }
  456. }
  457. // queenside
  458. if legal_castlings[1] {
  459. //info!("possible castling? {} {} {}", game.get_piece(KING, side), game.get_piece(ROOK, side), ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)));
  460. if ((game.get_piece(KING, side) << 4) & game.get_piece(ROOK, side)) != 0 &&
  461. ((game.get_piece(KING, side) << 1) | (game.get_piece(KING, side) << 2) | (game.get_piece(KING, side) << 3)) & all_pieces == 0 {
  462. let mut tg1 = game.clone();
  463. let mut tg2 = game.clone();
  464. *tg1.get_piece_mut(KING, side) = game.get_piece(KING, side) << 1;
  465. *tg2.get_piece_mut(KING, side) = game.get_piece(KING, side) << 2;
  466. if !is_check(game, side) && !is_check(&tg1, side) && !is_check(&tg2, side) {
  467. move_list.push(c2);
  468. }
  469. }
  470. }
  471. }
  472. pub fn is_check(game: &Game, side: Side) -> bool {
  473. let king = game.get_piece(KING, side);
  474. let king_square = square(king);
  475. let friends = game.get_all_side(side);
  476. let others = game.get_all_side(!side);
  477. let knights = get_knight_targets(king_square);
  478. if knights & game.get_piece(KNIGHT, !side) != 0 {
  479. return true;
  480. }
  481. let diagonal = generate_sliding_destinations(friends, others, king, false, true);
  482. let straight = generate_sliding_destinations(friends, others, king, true, false);
  483. if diagonal & game.get_piece(BISHOP, !side) != 0 {
  484. return true;
  485. }
  486. if diagonal & game.get_piece(QUEEN, !side) != 0 {
  487. return true;
  488. }
  489. if straight & game.get_piece(ROOK, !side) != 0 {
  490. return true;
  491. }
  492. if straight & game.get_piece(QUEEN, !side) != 0 {
  493. return true;
  494. }
  495. if side == BLACK {
  496. if ((southeast_one(king) | southwest_one(king)) & game.get_piece(PAWN, !side)) != 0 {
  497. return true;
  498. }
  499. }
  500. else {
  501. if ((northeast_one(king) | northwest_one(king)) & game.get_piece(PAWN, !side)) != 0 {
  502. return true;
  503. }
  504. }
  505. let king_area = north_one(king)
  506. | south_one(king)
  507. | east_one(king)
  508. | west_one(king)
  509. | northeast_one(king)
  510. | northwest_one(king)
  511. | southwest_one(king)
  512. | southeast_one(king);
  513. if king_area & game.get_piece(KING, !side) != 0 {
  514. return true;
  515. }
  516. return false;
  517. }
  518. /**
  519. * checks if side's king is in check
  520. */
  521. pub fn is_check_old(game: &Game, side: Side) -> bool {
  522. let king = game.get_piece(KING, side);
  523. let king_square = square(king);
  524. let possible_attacks = generate_possattacking_moves(game, !side);
  525. for mov in possible_attacks {
  526. if let Move::Default{ mov, piece_type: _, captured: _ } = mov {
  527. if mov.to == king_square {
  528. if !is_check(game, side) {
  529. panic!("incorrect non-check {}", game.beautiful_print());
  530. }
  531. return true;
  532. }
  533. }
  534. else if let Move::Promotion{ mov, promote_to: _, captured: _ } = mov {
  535. if mov.to == king_square {
  536. if !is_check(game, side) {
  537. panic!("incorrect non-check {}", game.beautiful_print());
  538. }
  539. return true;
  540. }
  541. }
  542. }
  543. if is_check(game, side) {
  544. panic!("incorrect check {}", game.beautiful_print());
  545. }
  546. false
  547. }
  548. /*
  549. #[cfg(test)]
  550. mod tests {
  551. use search::Game;
  552. use movegen::*;
  553. #[test]
  554. fn pawn_pushes() {
  555. let mut game: Game = Game::default();
  556. let pawn_moves = generate_pawn_moves(&game, WHITE);
  557. assert_eq!(pawn_moves, ());
  558. }
  559. }
  560. */