movegen.rs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999
  1. use bitboard::Bitboard;
  2. use bitboard::Square;
  3. use bitboard::*;
  4. use game::Game;
  5. use hash::{Cache, EntryType};
  6. use std::iter::Iterator;
  7. use crate::evaluate::evaluate;
  8. use crate::hash::CacheEntry;
  9. pub type Side = bool;
  10. pub const WHITE: Side = false;
  11. pub const BLACK: Side = true;
  12. pub type PieceType = u8;
  13. pub const NO_PIECE: PieceType = 255;
  14. pub const PAWN: PieceType = 0;
  15. pub const KNIGHT: PieceType = 1;
  16. pub const BISHOP: PieceType = 2;
  17. pub const ROOK: PieceType = 3;
  18. pub const QUEEN: PieceType = 4;
  19. pub const KING: PieceType = 5;
  20. #[derive(Copy, Clone, Debug, PartialEq, Eq)]
  21. pub struct SimpleMove {
  22. pub from: Square,
  23. pub to: Square,
  24. }
  25. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  26. pub enum Move {
  27. Default { mov: SimpleMove, piece_type: PieceType, captured: Option<PieceType> },
  28. Castling { side: Side, left: bool },
  29. EnPassant { mov: SimpleMove, beaten: Square },
  30. Promotion { mov: SimpleMove, promote_to: PieceType, captured: Option<PieceType> },
  31. Nullmove
  32. }
  33. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  34. pub struct MoveUndo {
  35. pub castling_rights_before: [bool; 4],
  36. pub halfmoves_since_last_event_before: i8,
  37. pub en_passant_before: Option<u8>,
  38. pub mov: Move
  39. }
  40. impl Default for Move {
  41. fn default() -> Move {
  42. Move::Nullmove
  43. }
  44. }
  45. impl Move {
  46. pub fn parse_square(sq: &str) -> Option<Square> {
  47. let col = sq.chars().nth(0)?;
  48. let row = sq.chars().nth(1)?;
  49. Some((row as u8 - '1' as u8) * 8 + 7 - (col as u8 - 'a' as u8))
  50. }
  51. pub fn square_to_string(sq: Square) -> String {
  52. let col = 7 - (sq % 8);
  53. let row = sq / 8;
  54. let colchar = (('a' as u8) + col) as char;
  55. let rowchar = (('1' as u8) + row) as char;
  56. let chars = [colchar, rowchar];
  57. //println!("{} {}", col, row);
  58. chars.iter().collect()
  59. }
  60. pub fn is_null(&self) -> bool {
  61. *self == Move::Nullmove
  62. }
  63. pub fn to_string(&self) -> String {
  64. match self {
  65. Move::Default{ mov, piece_type: _pt, captured: _c } => {
  66. Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
  67. },
  68. Move::Castling{ side, left } => {
  69. match (side, left) {
  70. (&WHITE, false) => {
  71. Self::square_to_string(3) + &Self::square_to_string(1)
  72. },
  73. (&WHITE, true) => {
  74. Self::square_to_string(3) + &Self::square_to_string(5)
  75. },
  76. (&BLACK, false) => {
  77. Self::square_to_string(56 + 3) + &Self::square_to_string(56 + 1)
  78. },
  79. (&BLACK, true) => {
  80. Self::square_to_string(56 + 3) + &Self::square_to_string(56 + 5)
  81. }
  82. }
  83. },
  84. Move::EnPassant{ mov, beaten: _ } => {
  85. Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
  86. },
  87. Move::Promotion{ mov, promote_to, captured: _c } => {
  88. Self::square_to_string(mov.from) + &Self::square_to_string(mov.to) +
  89. if *promote_to == QUEEN { "q" }
  90. else if *promote_to == ROOK { "r" }
  91. else if *promote_to == KNIGHT { "n" }
  92. else if *promote_to == BISHOP { "b" }
  93. else { "" }
  94. },
  95. Move::Nullmove => {
  96. String::from("0000")
  97. }
  98. }
  99. }
  100. pub fn is_capture(&self) -> bool {
  101. match self {
  102. Move::Default{ mov: _, piece_type: _, captured: c } => c.is_some(),
  103. Move::Promotion{ mov: _, promote_to: _, captured: c } => c.is_some(),
  104. Move::EnPassant{ mov: _, beaten: _ } => true,
  105. Move::Castling{ side: _, left: _ } => false,
  106. Move::Nullmove => false
  107. }
  108. }
  109. }
  110. /**
  111. * @brief Iterator to serialize bitboard bit for bit
  112. *
  113. * Extracts every bit out of the bitboard and returns each one as a separate bitboard.
  114. */
  115. pub struct BitboardIterator (pub Bitboard);
  116. impl Iterator for BitboardIterator {
  117. type Item = Bitboard;
  118. fn next(&mut self) -> Option<Bitboard> {
  119. if self.0 != 0 {
  120. let lsb = self.0 & (self.0.wrapping_neg());
  121. self.0 ^= lsb;
  122. //Some(lsb.trailing_zeros())
  123. Some(lsb)
  124. } else {
  125. None
  126. }
  127. }
  128. }
  129. impl SimpleMove {
  130. pub fn apply_to(self, bitboard: Bitboard) -> Bitboard {
  131. (bitboard & !from_square(self.from)) | from_square(self.to)
  132. }
  133. }
  134. #[derive(PartialEq)]
  135. enum SortingState {
  136. PvMove,
  137. Captures,
  138. Killers,
  139. Quiets
  140. }
  141. ///
  142. /// generates and sorts moves which can then be extracted via an Iterator interface
  143. ///
  144. pub struct MoveGenerator {
  145. game: Game,
  146. moves: Vec<Move>,
  147. captures: Vec<Move>,
  148. quiets: Vec<Move>,
  149. state: SortingState,
  150. pv_move: Option<Move>,
  151. killers: Vec<Move>
  152. }
  153. impl MoveGenerator {
  154. pub fn generate_legal_moves(game: &mut Game, ce: Option<&CacheEntry>, killers: &[Move], side: Side) -> Self {
  155. MoveGenerator {
  156. game: game.clone(),
  157. moves: generate_legal_moves(game, side, false),
  158. captures: Vec::new(),
  159. quiets: Vec::new(),
  160. state: if ce.is_some() { SortingState::PvMove } else { SortingState::Captures },
  161. pv_move: ce.map(|e| e.mov),
  162. killers: killers.to_vec()
  163. }
  164. }
  165. pub fn is_empty(&self) -> bool {
  166. return self.moves.is_empty() && self.captures.is_empty() && self.quiets.is_empty();
  167. }
  168. }
  169. impl Iterator for MoveGenerator {
  170. type Item = Move;
  171. fn next(&mut self) -> Option<Move> {
  172. while self.state != SortingState::Quiets || !self.is_empty() {
  173. match self.state {
  174. SortingState::PvMove => {
  175. self.state = SortingState::Captures;
  176. if let Some(pv) = self.pv_move {
  177. if self.moves.contains(&pv) {
  178. self.moves.retain(|m| *m != pv);
  179. return Some(pv);
  180. }
  181. }
  182. },
  183. SortingState::Captures => {
  184. if self.captures.is_empty() {
  185. self.captures = self.moves.iter().filter(|m| m.is_capture()).map(|m| m.clone()).collect();
  186. self.quiets = self.moves.iter().filter(|m| !m.is_capture()).map(|m| m.clone()).collect();
  187. self.moves.clear();
  188. if self.captures.is_empty() {
  189. self.state = SortingState::Killers;
  190. continue;
  191. }
  192. }
  193. // lower mvvlva score is better
  194. let mut best_mvv_lva = crate::evaluate::MAX_VALUE;
  195. let mut best_move: Option<Move> = None;
  196. for c in &self.captures {
  197. let score = mvv_lva_score(c);
  198. if score < best_mvv_lva {
  199. best_move = Some(*c);
  200. best_mvv_lva = score;
  201. }
  202. }
  203. self.captures.retain(|m| Some(*m) != best_move);
  204. if self.captures.is_empty() {
  205. self.state = SortingState::Killers;
  206. }
  207. return best_move;
  208. },
  209. SortingState::Killers => {
  210. for k in &self.killers {
  211. if self.quiets.contains(k) {
  212. self.quiets.retain(|m| *m != *k);
  213. return Some(*k);
  214. }
  215. }
  216. self.state = SortingState::Quiets;
  217. },
  218. SortingState::Quiets => {
  219. return self.quiets.pop();
  220. },
  221. }
  222. }
  223. return None;
  224. }
  225. }
  226. pub fn generate_moves(game: &Game, side: Side) -> Vec<Move> {
  227. let mut moves: Vec<Move> = Vec::with_capacity(128);
  228. generate_pawn_pushes(game, side, &mut moves);
  229. generate_pawn_doublepushes(game, side, &mut moves);
  230. generate_pawn_captures(game, side, &mut moves);
  231. generate_promotions(game, side, &mut moves);
  232. generate_en_passant(game, side, &mut moves);
  233. generate_knight_moves(game, side, &mut moves, false);
  234. generate_bishop_moves(game, side, &mut moves, false);
  235. generate_rook_moves(game, side, &mut moves, false);
  236. generate_queen_moves(game, side, &mut moves, false);
  237. generate_king_moves(game, side, &mut moves, false);
  238. generate_castling_moves(game, side, &mut moves);
  239. return moves;
  240. }
  241. /**
  242. * generates moves that could possibly attack a king,
  243. * this function is used to check if the king is in check
  244. */
  245. pub fn generate_possattacking_moves(game: &Game, side: Side) -> Vec<Move> {
  246. let mut moves: Vec<Move> = Vec::with_capacity(32);
  247. generate_pawn_captures(game, side, &mut moves);
  248. generate_promotions(game, side, &mut moves);
  249. generate_knight_moves(game, side, &mut moves, true);
  250. generate_bishop_moves(game, side, &mut moves, true);
  251. generate_rook_moves(game, side, &mut moves, true);
  252. generate_queen_moves(game, side, &mut moves, true);
  253. generate_king_moves(game, side, &mut moves, true);
  254. return moves;
  255. }
  256. pub fn generate_legal_moves_old(game: &mut Game, side: Side) -> Vec<Move> {
  257. let moves = generate_moves(game, side);
  258. let check_legality = |mov: &Move| {
  259. let undo = game.apply(*mov);
  260. let legal = !is_check(game, side);
  261. game.undo_move(undo);
  262. return legal;
  263. };
  264. moves.into_iter().filter(check_legality).collect::<Vec<Move>>()
  265. }
  266. fn pinned_rays(king: Bitboard, friends: Bitboard, diag_enemies: Bitboard, straight_enemies: Bitboard, all_enemies: Bitboard) -> [Bitboard; 8] {
  267. let check_ray = |ray_func: fn(Bitboard) -> Bitboard, diagonal: bool| -> Bitboard {
  268. let mut pos = king;
  269. let mut ray = 0;
  270. let mut one_friend = false;
  271. let enemies = if diagonal { diag_enemies } else { straight_enemies };
  272. let blockers = friends | all_enemies;
  273. for _ in 0..7 {
  274. pos = ray_func(pos);
  275. ray |= pos;
  276. if pos & friends != 0 && !one_friend {
  277. one_friend = true;
  278. } else if pos & enemies != 0 && one_friend {
  279. return ray;
  280. } else if pos & blockers != 0 && !one_friend {
  281. return 0;
  282. } else if pos & blockers != 0 && one_friend {
  283. return 0;
  284. }
  285. }
  286. return 0;
  287. };
  288. return [check_ray(north_one, false),
  289. check_ray(south_one, false),
  290. check_ray(east_one, false),
  291. check_ray(west_one, false),
  292. check_ray(northeast_one, true),
  293. check_ray(northwest_one, true),
  294. check_ray(southeast_one, true),
  295. check_ray(southwest_one, true)];
  296. }
  297. pub fn generate_legal_moves(game: &mut Game, side: Side, captures_only: bool) -> Vec<Move> {
  298. let moves =
  299. if captures_only {
  300. generate_attacking_moves(game, side)
  301. } else {
  302. generate_moves(game, side)
  303. };
  304. let check = is_check(game, side);
  305. let king = game.kings(side);
  306. let straight_enemies = game.queens(!side) | game.rooks(!side);
  307. let diag_enemies = game.queens(!side) | game.bishops(!side);
  308. let pin_rays = pinned_rays(king, game.get_all_side(side), diag_enemies, straight_enemies, game.get_all_side(!side));
  309. let possible_pins = king | pin_rays.iter().fold(0, |a, b| a | b);
  310. let check_legality = |m: &Move| {
  311. if !check {
  312. match m {
  313. Move::Default { mov, piece_type: _, captured: _ } |
  314. Move::Promotion { mov, promote_to: _, captured: _ } => {
  315. let from = from_square(mov.from);
  316. if from & possible_pins == 0 && from != king {
  317. return true;
  318. }
  319. else {
  320. let to = from_square(mov.to);
  321. for pin_ray in pin_rays {
  322. if from & pin_ray != 0 {
  323. if to & pin_ray != 0 {
  324. return true;
  325. }
  326. else {
  327. return false;
  328. }
  329. }
  330. }
  331. }
  332. },
  333. _ => {}
  334. }
  335. }
  336. let undo = game.apply(*m);
  337. let legal = !is_check(game, side);
  338. game.undo_move(undo);
  339. return legal;
  340. };
  341. moves.into_iter().filter(check_legality).collect::<Vec<Move>>()
  342. }
  343. pub fn generate_legal_sorted_moves(game: &mut Game, _hash: &mut Cache, killers: &[Move], ce: Option<CacheEntry>, side: Side) -> Vec<Move> {
  344. let mut moves = generate_legal_moves(game, side, false);
  345. let mov_val= |mov: &Move| {
  346. // if its a pv move from previously
  347. if let Some(c) = &ce {
  348. if &c.mov == mov {
  349. return -2000;
  350. }
  351. };
  352. let killer_bonus = if killers.contains(mov) { 300 } else { 0 };
  353. let capture_bonus: i32 = if mov.is_capture() { 400 } else { 0 } - mvv_lva_score(mov) / 16;
  354. let eval = -killer_bonus - capture_bonus;
  355. return eval;
  356. };
  357. moves.sort_by_cached_key(|m| mov_val(m));
  358. return moves;
  359. }
  360. pub fn generate_attacking_moves(game: &Game, side: Side) -> Vec<Move> {
  361. let mut moves: Vec<Move> = Vec::with_capacity(32);
  362. generate_pawn_captures(game, side, &mut moves);
  363. generate_knight_moves(game, side, &mut moves, true);
  364. generate_bishop_moves(game, side, &mut moves, true);
  365. generate_rook_moves(game, side, &mut moves, true);
  366. generate_queen_moves(game, side, &mut moves, true);
  367. generate_king_moves(game, side, &mut moves, true);
  368. return moves;
  369. }
  370. pub fn sort_moves(game: &mut Game, hash: &mut Cache, killers: &[Move], move_list: &mut Vec<Move>) {
  371. move_list.sort_by_cached_key(|mov| {
  372. let undo = game.apply(*mov);
  373. if let Some(e) = hash.lookup(game) {
  374. game.undo_move(undo);
  375. if let EntryType::Value = e.entry_type {
  376. return e.value;
  377. }
  378. else if let EntryType::LowerBound = e.entry_type {
  379. return e.value - 1000;
  380. }
  381. else if let EntryType::UpperBound = e.entry_type {
  382. return e.value + 1000;
  383. }
  384. else {
  385. return crate::evaluate::evaluate(game) - if killers.contains(mov) { 200 } else { 0 };
  386. }
  387. }
  388. else {
  389. let eval = crate::evaluate::evaluate(game) - if killers.contains(mov) { 200 } else { 0 };
  390. game.undo_move(undo);
  391. return eval;
  392. }
  393. });
  394. }
  395. ///
  396. /// assigns a score to capture moves lower the more valuable the captured piece. Secondly
  397. /// also higher the more the attacking piece is worth.
  398. ///
  399. fn mvv_lva_score(mov: &Move) -> i32 {
  400. const PIECE_VALUES: [i32; 6] = [
  401. 100, // Pawn
  402. 220, // Knight
  403. 320, // Bishop
  404. 400, // Rook
  405. 800, // Queen
  406. 100000 // King
  407. ];
  408. match mov {
  409. Move::Default { mov: _, piece_type, captured } => {
  410. let attack = PIECE_VALUES[*piece_type as usize];
  411. let victim = captured.map(|ct| PIECE_VALUES[ct as usize]).unwrap_or(0);
  412. attack - victim * 5
  413. },
  414. Move::Promotion { mov: _, promote_to: _, captured } => {
  415. let victim = captured.map(|ct| PIECE_VALUES[ct as usize]).unwrap_or(0);
  416. PIECE_VALUES[PAWN as usize] - victim * 5
  417. },
  418. _ => 0
  419. }
  420. }
  421. pub fn sort_moves_least_valuable_attacker(_game: &mut Game, move_list: &mut Vec<Move>) {
  422. move_list.sort_by_cached_key(mvv_lva_score)
  423. }
  424. pub fn sort_moves_no_hash(game: &mut Game, move_list: &mut Vec<Move>) {
  425. move_list.sort_by_cached_key(|mov| {
  426. let undo = game.apply(*mov);
  427. let our_material = crate::evaluate::material_value(game, game.turn);
  428. let their_material = crate::evaluate::material_value(game, !game.turn);
  429. let eval = our_material - their_material;
  430. game.undo_move(undo);
  431. return eval;
  432. });
  433. }
  434. fn generate_pawn_pushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  435. let pawns = game.pawns(side);
  436. let others = game.get_all_side(!side);
  437. let pieces = game.get_all_side(side);
  438. let moved_pawns =
  439. match side {
  440. WHITE => north_one(pawns),
  441. BLACK => south_one(pawns)
  442. } & !(ROW_1 | ROW_8) & !(others | pieces);
  443. let iter = BitboardIterator(moved_pawns & !others);
  444. for p in iter {
  445. let origin = match side {
  446. WHITE => south_one(p),
  447. BLACK => north_one(p)
  448. };
  449. move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN, captured: None });
  450. }
  451. }
  452. fn generate_pawn_doublepushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  453. let pawns = game.pawns(side) & match side { WHITE => ROW_2, BLACK => ROW_7 };
  454. let others = game.get_all_side(!side);
  455. let pieces = game.get_all_side(side);
  456. let all_pieces = others | pieces;
  457. let moved_pawns =
  458. match side {
  459. WHITE => north_one(north_one(pawns) & !all_pieces),
  460. BLACK => south_one(south_one(pawns) & !all_pieces)
  461. } & !all_pieces;
  462. let iter = BitboardIterator(moved_pawns & !others);
  463. for p in iter {
  464. let origin = match side {
  465. WHITE => south_one(south_one(p)),
  466. BLACK => north_one(north_one(p))
  467. };
  468. move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN, captured: None });
  469. }
  470. }
  471. fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  472. let pawns = game.pawns(side);
  473. let others = game.get_all_side(!side);
  474. let promotion_mask = ROW_1 | ROW_8;
  475. let pawn_iterator = BitboardIterator(pawns);
  476. for pawn in pawn_iterator {
  477. let left_cap = match side {
  478. WHITE => northeast_one(pawn),
  479. BLACK => southeast_one(pawn)
  480. };
  481. let right_cap = match side {
  482. WHITE => northwest_one(pawn),
  483. BLACK => southwest_one(pawn)
  484. };
  485. for cap in [left_cap, right_cap].iter() {
  486. if cap & others != 0 {
  487. let captured = game.find_piece(*cap);
  488. let simple_move = SimpleMove { from: square(pawn), to: square(*cap)};
  489. if cap & promotion_mask != 0 {
  490. move_list.push(Move::Promotion { mov: simple_move, promote_to: QUEEN, captured: captured });
  491. move_list.push(Move::Promotion { mov: simple_move, promote_to: ROOK, captured: captured });
  492. move_list.push(Move::Promotion { mov: simple_move, promote_to: BISHOP, captured: captured });
  493. move_list.push(Move::Promotion { mov: simple_move, promote_to: KNIGHT, captured: captured });
  494. } else {
  495. move_list.push(Move::Default { mov: simple_move, piece_type: PAWN, captured: captured });
  496. }
  497. }
  498. }
  499. }
  500. }
  501. fn generate_promotions(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  502. let pawns = game.pawns(side);
  503. let others = game.get_all_side(!side);
  504. let pieces = game.get_all_side(side);
  505. let moved_pawns =
  506. match side {
  507. WHITE => north_one(pawns),
  508. BLACK => south_one(pawns)
  509. } & (ROW_1 | ROW_8) & !(others | pieces);
  510. let iter = BitboardIterator(moved_pawns);
  511. for p in iter {
  512. let origin = match side {
  513. WHITE => south_one(p),
  514. BLACK => north_one(p)
  515. };
  516. let movement = SimpleMove { from: square(origin), to: square(p) };
  517. //move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN });
  518. move_list.push(Move::Promotion { mov: movement, promote_to: QUEEN, captured: None });
  519. move_list.push(Move::Promotion { mov: movement, promote_to: ROOK, captured: None });
  520. move_list.push(Move::Promotion { mov: movement, promote_to: BISHOP, captured: None });
  521. move_list.push(Move::Promotion { mov: movement, promote_to: KNIGHT, captured: None });
  522. }
  523. }
  524. fn generate_en_passant(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  525. if let Some(ep) = game.en_passant {
  526. let pawncolumn = FILE_A >> ep;
  527. let pawnrow: Bitboard = match side {
  528. WHITE => ROW_5,
  529. BLACK => ROW_4
  530. };
  531. let beaten_pawn = pawncolumn & pawnrow;
  532. if beaten_pawn & game.get_piece(PAWN, !side) == 0 {
  533. return;
  534. }
  535. let pawn_left = (beaten_pawn << 1) & pawnrow;
  536. let pawn_right = (beaten_pawn >> 1) & pawnrow;
  537. let attacking_pawns = game.get_piece(PAWN, side);
  538. let target_square = pawncolumn & match side {
  539. WHITE => ROW_6,
  540. BLACK => ROW_3
  541. };
  542. if pawn_left & attacking_pawns != 0 {
  543. let mov = Move::EnPassant{ mov: SimpleMove{ from: square(pawn_left), to: square(target_square) }, beaten: square(beaten_pawn) };
  544. move_list.push(mov);
  545. }
  546. if pawn_right & attacking_pawns != 0 {
  547. let mov = Move::EnPassant{ mov: SimpleMove{ from: square(pawn_right), to: square(target_square) }, beaten: square(beaten_pawn) };
  548. move_list.push(mov);
  549. }
  550. }
  551. }
  552. fn generate_knight_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  553. let friends = game.get_all_side(side);
  554. let others = game.get_all_side(!side);
  555. let knights = game.knights(side);
  556. let knight_iter = BitboardIterator(knights);
  557. for k in knight_iter {
  558. let cap_targets = BitboardIterator(get_knight_targets(square(k)) & (!friends & others));
  559. let nocap_targets = BitboardIterator(get_knight_targets(square(k)) & (!friends & !others));
  560. for target in cap_targets {
  561. let simple_move = SimpleMove { from: square(k), to: square(target) };
  562. let captured = game.find_piece(target);
  563. move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT, captured });
  564. }
  565. if !captures_only {
  566. for target in nocap_targets {
  567. let simple_move = SimpleMove { from: square(k), to: square(target) };
  568. move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT, captured: None });
  569. }
  570. }
  571. }
  572. }
  573. pub fn get_knight_targets(square: Square) -> Bitboard {
  574. /// @brief array containing the possible targets for a knight on each square.
  575. /// entry at index i is a bitboard with all bits set where a knight on square i can jump
  576. const TARGETS: [Bitboard; 64] = [132096, 329728, 659712, 1319424, 2638848, 5277696, 10489856,
  577. 4202496, 33816580, 84410376, 168886289, 337772578, 675545156, 1351090312, 2685403152,
  578. 1075839008, 8657044482, 21609056261, 43234889994, 86469779988, 172939559976, 345879119952,
  579. 687463207072, 275414786112, 2216203387392, 5531918402816, 11068131838464, 22136263676928,
  580. 44272527353856, 88545054707712, 175990581010432, 70506185244672, 567348067172352,
  581. 1416171111120896, 2833441750646784, 5666883501293568, 11333767002587136, 22667534005174272,
  582. 45053588738670592, 18049583422636032, 145241105196122112, 362539804446949376,
  583. 725361088165576704, 1450722176331153408, 2901444352662306816, 5802888705324613632,
  584. 11533718717099671552, 4620693356194824192, 288234782788157440, 576469569871282176,
  585. 1224997833292120064, 2449995666584240128, 4899991333168480256, 9799982666336960512,
  586. 1152939783987658752, 2305878468463689728, 1128098930098176, 2257297371824128, 4796069720358912,
  587. 9592139440717824, 19184278881435648, 38368557762871296, 4679521487814656, 9077567998918656];
  588. TARGETS[square as usize]
  589. }
  590. fn generate_bishop_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  591. let friends = game.get_all_side(side);
  592. let others = game.get_all_side(!side);
  593. generate_sliding_moves(game, friends, others, game.bishops(side), BISHOP, false, true, move_list, captures_only);
  594. }
  595. fn generate_rook_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  596. let friends = game.get_all_side(side);
  597. let others = game.get_all_side(!side);
  598. generate_sliding_moves(game, friends, others, game.rooks(side), ROOK, true, false, move_list, captures_only);
  599. }
  600. fn generate_queen_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  601. let friends = game.get_all_side(side);
  602. let others = game.get_all_side(!side);
  603. generate_sliding_moves(game, friends, others, game.queens(side), QUEEN, true, true, move_list, captures_only);
  604. }
  605. pub fn count_sliding_move_bitboard(friends: Bitboard, others: Bitboard, pieces: Bitboard, straight: bool, diagonal: bool, captures_only: bool) -> u32 {
  606. let pieces_iter = BitboardIterator(pieces);
  607. let mask = if captures_only { others } else { !(0 as Bitboard) };
  608. let mut sum = 0;
  609. for piece in pieces_iter {
  610. let destinations = generate_sliding_destinations(friends, others, piece, straight, diagonal);
  611. sum += (destinations & mask).count_ones();
  612. }
  613. return sum;
  614. }
  615. fn generate_sliding_moves(game: &Game, friends: Bitboard, others: Bitboard, pieces: Bitboard, piece_type: PieceType,
  616. straight: bool, diagonal: bool, move_list: &mut Vec<Move>, captures_only: bool) {
  617. let pieces_iter = BitboardIterator(pieces);
  618. let mask = if captures_only { others } else { !(0 as Bitboard) };
  619. for piece in pieces_iter {
  620. let destinations = generate_sliding_destinations(friends, others, piece, straight, diagonal);
  621. let dest_iter = BitboardIterator(destinations & mask);
  622. for dest in dest_iter {
  623. let smove = SimpleMove{ from: square(piece), to: square(dest) };
  624. if dest & others != 0 {
  625. move_list.push(Move::Default { mov: smove, piece_type: piece_type, captured: game.find_piece(dest) });
  626. }
  627. else {
  628. move_list.push(Move::Default { mov: smove, piece_type: piece_type, captured: None });
  629. }
  630. }
  631. }
  632. }
  633. fn generate_sliding_destinations(friends: Bitboard, others: Bitboard,
  634. piece: Bitboard, straight: bool,
  635. diagonal: bool) -> Bitboard {
  636. let occupied = friends | others;
  637. let straights = [north_one, south_one, east_one, west_one];
  638. let diagonals = [northeast_one, southeast_one, northwest_one, southwest_one];
  639. let mut result: Bitboard = 0;
  640. if straight {
  641. for direction in straights.iter() {
  642. result |= generate_direction(piece, *direction, occupied);
  643. }
  644. }
  645. if diagonal {
  646. for direction in diagonals.iter() {
  647. result |= generate_direction(piece, *direction, occupied);
  648. }
  649. }
  650. return result & !friends;
  651. }
  652. fn generate_direction(piece: Bitboard, direction: fn(Bitboard) -> Bitboard, occupied: Bitboard) -> Bitboard {
  653. let mut result: Bitboard = 0;
  654. let mut b = piece;
  655. loop {
  656. b = direction(b);
  657. result |= b;
  658. if b & (occupied) != 0 || b == 0 {
  659. break;
  660. }
  661. }
  662. return result;
  663. }
  664. fn generate_king_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  665. let friends = game.get_all_side(side);
  666. let others = game.get_all_side(!side);
  667. let king = game.kings(side);
  668. //assert_eq!(king.count_ones(), 1); // assume only one king per player
  669. if king.count_ones() != 1 { return; }
  670. let mask =
  671. if captures_only {
  672. !friends & others
  673. }
  674. else {
  675. !friends
  676. };
  677. let area = (north_one(king)
  678. | south_one(king)
  679. | east_one(king)
  680. | west_one(king)
  681. | northeast_one(king)
  682. | northwest_one(king)
  683. | southwest_one(king)
  684. | southeast_one(king))
  685. & mask;
  686. let area_iter = BitboardIterator(area);
  687. for destination in area_iter {
  688. let simple_move = SimpleMove{ from: square(king), to: square(destination) };
  689. let captured = game.find_piece(destination);
  690. move_list.push(Move::Default { mov: simple_move, piece_type: KING, captured });
  691. }
  692. }
  693. fn generate_castling_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  694. let c1 = Move::Castling{ side: side, left: false };
  695. let c2 = Move::Castling{ side: side, left: true };
  696. let legal_castlings: &[bool] = match side {
  697. WHITE => &game.castling_rights[0..2],
  698. BLACK => &game.castling_rights[2..4],
  699. };
  700. let all_pieces = game.get_all_side(WHITE) | game.get_all_side(BLACK);
  701. // kingside castling
  702. if legal_castlings[0] {
  703. //info!("possible castling? {} {} {}", game.get_piece(KING, side), game.get_piece(ROOK, side), ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)));
  704. if ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)) != 0 &&
  705. ((game.get_piece(KING, side) >> 1) | (game.get_piece(KING, side) >> 2)) & all_pieces == 0 {
  706. let mut tg1 = game.clone();
  707. *tg1.get_piece_mut(KING, side) = game.get_piece(KING, side) >> 1;
  708. if !is_check(game, side) && !is_check(&tg1, side) {
  709. move_list.push(c1);
  710. }
  711. }
  712. }
  713. // queenside
  714. if legal_castlings[1] {
  715. //info!("possible castling? {} {} {}", game.get_piece(KING, side), game.get_piece(ROOK, side), ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)));
  716. if ((game.get_piece(KING, side) << 4) & game.get_piece(ROOK, side)) != 0 &&
  717. ((game.get_piece(KING, side) << 1) | (game.get_piece(KING, side) << 2) | (game.get_piece(KING, side) << 3)) & all_pieces == 0 {
  718. let mut tg1 = game.clone();
  719. let mut tg2 = game.clone();
  720. *tg1.get_piece_mut(KING, side) = game.get_piece(KING, side) << 1;
  721. *tg2.get_piece_mut(KING, side) = game.get_piece(KING, side) << 2;
  722. if !is_check(game, side) && !is_check(&tg1, side) && !is_check(&tg2, side) {
  723. move_list.push(c2);
  724. }
  725. }
  726. }
  727. }
  728. pub fn is_check(game: &Game, side: Side) -> bool {
  729. let king = game.get_piece(KING, side);
  730. let king_square = square(king);
  731. let friends = game.get_all_side(side);
  732. let others = game.get_all_side(!side);
  733. let knights = get_knight_targets(king_square);
  734. if knights & game.get_piece(KNIGHT, !side) != 0 {
  735. return true;
  736. }
  737. let diagonal = generate_sliding_destinations(friends, others, king, false, true);
  738. let straight = generate_sliding_destinations(friends, others, king, true, false);
  739. if diagonal & game.get_piece(BISHOP, !side) != 0 {
  740. return true;
  741. }
  742. if diagonal & game.get_piece(QUEEN, !side) != 0 {
  743. return true;
  744. }
  745. if straight & game.get_piece(ROOK, !side) != 0 {
  746. return true;
  747. }
  748. if straight & game.get_piece(QUEEN, !side) != 0 {
  749. return true;
  750. }
  751. if side == BLACK {
  752. if ((southeast_one(king) | southwest_one(king)) & game.get_piece(PAWN, !side)) != 0 {
  753. return true;
  754. }
  755. }
  756. else {
  757. if ((northeast_one(king) | northwest_one(king)) & game.get_piece(PAWN, !side)) != 0 {
  758. return true;
  759. }
  760. }
  761. let king_area = north_one(king)
  762. | south_one(king)
  763. | east_one(king)
  764. | west_one(king)
  765. | northeast_one(king)
  766. | northwest_one(king)
  767. | southwest_one(king)
  768. | southeast_one(king);
  769. if king_area & game.get_piece(KING, !side) != 0 {
  770. return true;
  771. }
  772. return false;
  773. }
  774. ///
  775. /// checks wether the square sq is attacked by the specified side
  776. ///
  777. pub fn is_attacked(game: &Game, sq: Square, side: Side) -> bool {
  778. let others = game.get_all_side(!side);
  779. let friends = game.get_all_side(side);
  780. let sq_bb = from_square(sq);
  781. let knights = get_knight_targets(sq);
  782. if knights & game.get_piece(KNIGHT, side) != 0 {
  783. return true;
  784. }
  785. let diagonal = generate_sliding_destinations(others, friends, sq_bb, false, true);
  786. let straight = generate_sliding_destinations(others, friends, sq_bb, true, false);
  787. if diagonal & game.get_piece(BISHOP, side) != 0 {
  788. return true;
  789. }
  790. if diagonal & game.get_piece(QUEEN, side) != 0 {
  791. return true;
  792. }
  793. if straight & game.get_piece(ROOK, side) != 0 {
  794. return true;
  795. }
  796. if straight & game.get_piece(QUEEN, side) != 0 {
  797. return true;
  798. }
  799. if side == WHITE {
  800. if ((southeast_one(sq_bb) | southwest_one(sq_bb)) & game.get_piece(PAWN, side)) != 0 {
  801. return true;
  802. }
  803. }
  804. else {
  805. if ((northeast_one(sq_bb) | northwest_one(sq_bb)) & game.get_piece(PAWN, side)) != 0 {
  806. return true;
  807. }
  808. }
  809. let sq_lr = east_one(sq_bb) | sq_bb | west_one(sq_bb);
  810. let sq_area = north_one(sq_lr) | sq_lr | south_one(sq_lr);
  811. if sq_area & game.get_piece(KING, side) != 0 {
  812. return true;
  813. }
  814. return false;
  815. }
  816. #[cfg(test)]
  817. mod tests {
  818. use movegen::*;
  819. use crate::{search::{perft, SearchControl}, hash::RepetitionTable};
  820. ///
  821. /// tests the move generation from some positions to depth 4 and checks wether the correct
  822. /// amount of moves has been generated
  823. ///
  824. #[test]
  825. fn some_positions_perft() {
  826. assert_eq!(nodes_from_pos("5bk1/5p2/7p/q2r1p2/2Q5/P4N2/3prPPP/1R3RK1 b - - 1 34", 4), 3773096);
  827. assert_eq!(nodes_from_pos("r1bqkbnr/1p1p1ppp/p1N1p3/8/4P3/2N5/PPP2PPP/R1BQKB1R b KQkq - 0 6", 4), 2008894);
  828. assert_eq!(nodes_from_pos("1r5r/p2b2p1/1p1k1bp1/2pBpp2/1P1n1P2/P1NP3P/2PB2P1/R2KR3 w - - 1 23", 4), 1971751);
  829. // some positions from https://www.chessprogramming.org/Perft_Results
  830. assert_eq!(nodes_from_pos("rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8", 4), 2103487);
  831. assert_eq!(nodes_from_pos("r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1", 5), 15833292);
  832. assert_eq!(nodes_from_pos("r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1", 5), 15833292);
  833. }
  834. fn nodes_from_pos(fen: &str, depth: i32) -> usize {
  835. let mut game: Game = Game::from_fen_str(fen).unwrap();
  836. let mut check = || false;
  837. let mut rt = &mut RepetitionTable::new();
  838. let mut sc = SearchControl::new(&mut check, &mut rt, depth);
  839. perft(&mut game, &mut sc, depth);
  840. return sc.nodes;
  841. }
  842. }