movegen.rs 37 KB

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