movegen.rs 26 KB

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