movegen.rs 46 KB

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