Guest User

Untitled

a guest
Jan 18th, 2019
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 64.00 KB | None | 0 0
  1. #[macro_use]
  2. extern crate lazy_static;
  3. extern crate rand;
  4.  
  5. mod game_state;
  6. mod misc;
  7. mod bitboards;
  8. mod movegen;
  9.  
  10. use self::game_state::GameState;
  11. use std::time::Instant;
  12.  
  13. fn main() {
  14. let now = Instant::now();
  15. bitboards::init_all();
  16. println!("Should have initialized everything!");
  17.  
  18. let new_now = Instant::now();
  19. println!("Initialization Time: {}ms", new_now.duration_since(now).as_secs() * 1000 + new_now.duration_since(now).subsec_millis() as u64);
  20. let now = Instant::now();
  21.  
  22. let g = GameState::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
  23. //let g= GameState::from_fen("r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1");
  24. let nodes = perft_div(&g, 6);
  25. println!("{}", nodes);
  26. //misc::STD_FEN);
  27. let new_now = Instant::now();
  28. let time_passed = new_now.duration_since(now).as_secs() as f64 + new_now.duration_since(now).subsec_millis() as f64 / 1000.0;
  29. println!("Time: {}ms", new_now.duration_since(now).as_secs() * 1000 + new_now.duration_since(now).subsec_millis() as u64);
  30. println!("NPS: {}", nodes as f64 / time_passed);
  31. }
  32.  
  33. pub fn perft_div(g: &GameState, depth: usize) -> u64 {
  34. let mut count = 0u64;
  35. let (valid_moves, in_check) = movegen::generate_moves(&g);
  36. for mv in valid_moves {
  37. let next_g = movegen::make_move(&g, &mv);
  38. let res = perft(&next_g, depth - 1);
  39. println!("{:?}: {}", mv, res);
  40. count += res;
  41. }
  42. count
  43. }
  44.  
  45. pub fn perft(g: &GameState, depth: usize) -> u64 {
  46. if depth == 1 {
  47. let (vm, _ic) = movegen::generate_moves(&g);
  48. return vm.len() as u64;
  49. } else {
  50. let mut res = 0;
  51. let (valid_moves, incheck) = movegen::generate_moves(&g);
  52. for mv in valid_moves {
  53. res += perft(&movegen::make_move(&g, &mv), depth - 1);
  54. }
  55. res
  56. }
  57. }
  58.  
  59. use std::fmt::{Formatter, Display, Result, Debug};
  60.  
  61. #[derive(Clone)]
  62. pub enum GameMoveType {
  63. Quiet,
  64. Capture,
  65. EnPassant,
  66. Castle,
  67. Promotion(PieceType),
  68. }
  69.  
  70. #[derive(Clone, Debug)]
  71. pub enum PieceType {
  72. King,
  73. Pawn,
  74. Knight,
  75. Bishop,
  76. Rook,
  77. Queen,
  78. }
  79.  
  80. pub struct GameMove {
  81. pub from: usize,
  82. pub to: usize,
  83. pub move_type: GameMoveType,
  84. pub piece_type: PieceType,
  85. }
  86.  
  87. impl Debug for GameMove {
  88. fn fmt(&self, formatter: &mut Formatter) -> Result {
  89. let mut res_str: String = String::new();
  90. res_str.push_str(&format!("{}{}{}{}", file_to_string(self.from % 8), self.from / 8 + 1, file_to_string(self.to % 8), self.to / 8 + 1));
  91. match &self.move_type {
  92. GameMoveType::Quiet => { res_str.push_str("") }
  93. _ => {}
  94. };
  95. write!(formatter, "{}", res_str)
  96. }
  97. }
  98.  
  99. fn file_to_string(file: usize) -> &'static str {
  100. match file {
  101. 0 => "a",
  102. 1 => "b",
  103. 2 => "c",
  104. 3 => "d",
  105. 4 => "e",
  106. 5 => "f",
  107. 6 => "g",
  108. 7 => "h",
  109. _ => panic!("invalid file")
  110. }
  111. }
  112.  
  113. pub struct GameState {
  114. // 0 = white
  115. // 1 = black
  116. pub color_to_move: usize,
  117.  
  118. //Array saving all the bitboards
  119. //Index 1:
  120. // 0 -> Pawns
  121. // 1 -> Knights
  122. // 2 -> Bishops
  123. // 3 -> Rooks
  124. // 4 -> Queens
  125. // 5 -> King
  126. //Index 2:
  127. // 0 -> White
  128. // 1 -> Black
  129. pub pieces: [[u64; 2]; 6],
  130.  
  131. //Castle flags
  132. pub castle_white_kingside: bool,
  133. pub castle_white_queenside: bool,
  134. pub castle_black_kingside: bool,
  135. pub castle_black_queenside: bool,
  136.  
  137. //En passant flag
  138. pub en_passant: u64,
  139. //50 move draw counter
  140. pub half_moves: usize,
  141. pub full_moves: usize,
  142. //Move-Gen
  143. //King/Knight lookup
  144. //Sliding by magic
  145. }
  146.  
  147. impl GameState {
  148. pub fn from_fen(fen: &str) -> GameState {
  149. let vec: Vec<&str> = fen.split(" ").collect();
  150. if vec.len() < 4 {
  151. panic!("Invalid FEN");
  152. }
  153. //Parse through FEN
  154. //Piecess
  155. let pieces: Vec<&str> = vec[0].split("/").collect();
  156. if pieces.len() != 8 {
  157. panic!("Invalid FEN");
  158. }
  159. //Iterate over all 8 ranks
  160. let mut pieces_arr: [[u64; 2]; 6] = [[0u64; 2]; 6];
  161. for rank in 0..8 {
  162. let rank_str = pieces[rank];
  163. let mut file: usize = 0;
  164. let mut rank_str_idx: usize = 0;
  165. while file < 8 {
  166. let idx = (7 - rank) * 8 + file;
  167. let next_char = rank_str.chars().nth(rank_str_idx);
  168. rank_str_idx += 1;
  169. match next_char {
  170. Some(x) => {
  171. match x {
  172. 'P' => {
  173. pieces_arr[0][0] |= 1u64 << idx;
  174. file += 1;
  175. }
  176. 'p' => {
  177. pieces_arr[0][1] |= 1u64 << idx;
  178. file += 1;
  179. }
  180. 'N' => {
  181. pieces_arr[1][0] |= 1u64 << idx;
  182. file += 1;
  183. }
  184. 'n' => {
  185. pieces_arr[1][1] |= 1u64 << idx;
  186. file += 1;
  187. }
  188. 'B' => {
  189. pieces_arr[2][0] |= 1u64 << idx;
  190. file += 1;
  191. }
  192. 'b' => {
  193. pieces_arr[2][1] |= 1u64 << idx;
  194. file += 1;
  195. }
  196. 'R' => {
  197. pieces_arr[3][0] |= 1u64 << idx;
  198. file += 1;
  199. }
  200. 'r' => {
  201. pieces_arr[3][1] |= 1u64 << idx;
  202. file += 1;
  203. }
  204. 'Q' => {
  205. pieces_arr[4][0] |= 1u64 << idx;
  206. file += 1;
  207. }
  208. 'q' => {
  209. pieces_arr[4][1] |= 1u64 << idx;
  210. file += 1;
  211. }
  212. 'K' => {
  213. pieces_arr[5][0] |= 1u64 << idx;
  214. file += 1;
  215. }
  216. 'k' => {
  217. pieces_arr[5][1] |= 1u64 << idx;
  218. file += 1;
  219. }
  220. '1' => {
  221. file += 1;
  222. }
  223. '2' => {
  224. file += 2;
  225. }
  226. '3' => {
  227. file += 3;
  228. }
  229. '4' => {
  230. file += 4;
  231. }
  232. '5' => {
  233. file += 5;
  234. }
  235. '6' => {
  236. file += 6;
  237. }
  238. '7' => {
  239. file += 7;
  240. }
  241. '8' => {
  242. file += 8;
  243. }
  244. _ => {
  245. panic!("Invalid FEN");
  246. }
  247. }
  248. }
  249. None => panic!("Invalid FEN"),
  250. }
  251. }
  252. }
  253.  
  254. //Side to move
  255. let color_to_move = match vec[1] {
  256. "w" => 0,
  257. "b" => 1,
  258. _ => panic!("Invalid FEN!")
  259. };
  260.  
  261. //CastlingAbilities
  262. let castle_white_kingside = vec[2].contains("K");
  263. let castle_white_queenside = vec[2].contains("Q");
  264. let castle_black_kingside = vec[2].contains("k");
  265. let castle_black_queenside = vec[2].contains("q");
  266.  
  267. //En Passant target square //Ignore
  268. let mut en_passant: u64 = 0u64;
  269. if vec[3] != "-" {
  270. let mut idx: usize = 0usize;
  271. let file = vec[3].chars().nth(0);
  272. let rank = vec[3].chars().nth(1);
  273. match file {
  274. Some(x) => {
  275. match x {
  276. 'a' | 'A' => {}
  277. 'b' | 'B' => {
  278. idx += 1;
  279. }
  280. 'c' | 'C' => {
  281. idx += 2;
  282. }
  283. 'd' | 'D' => {
  284. idx += 3;
  285. }
  286. 'e' | 'E' => {
  287. idx += 4;
  288. }
  289. 'f' | 'F' => {
  290. idx += 5;
  291. }
  292. 'g' | 'G' => {
  293. idx += 6;
  294. }
  295. 'h' | 'H' => {
  296. idx += 7;
  297. }
  298. _ => {
  299. panic!("Invalid FEN!");
  300. }
  301. }
  302. }
  303. None => { panic!("Invalid FEN!"); }
  304. }
  305. match rank {
  306. Some(x) => {
  307. match x {
  308. '1' => {}
  309. '2' => {
  310. idx += 8;
  311. }
  312. '3' => {
  313. idx += 16;
  314. }
  315. '4' => {
  316. idx += 24;
  317. }
  318. '5' => {
  319. idx += 32;
  320. }
  321. '6' => {
  322. idx += 40;
  323. }
  324. '7' => {
  325. idx += 48;
  326. }
  327. '8' => {
  328. idx += 56;
  329. }
  330. _ => {
  331. panic!("Invalid FEN!");
  332. }
  333. }
  334. }
  335. None => {
  336. panic!("Invalid FEN!");
  337. }
  338. }
  339. en_passant = 1u64 << idx;
  340. }
  341. let mut half_moves = 0;
  342. let mut full_moves = 0;
  343. if vec.len() > 4 {
  344. //HalfMoveClock
  345. half_moves = vec[4].parse().unwrap();
  346.  
  347. full_moves = vec[5].parse().unwrap();
  348. }
  349. GameState {
  350. color_to_move,
  351. pieces: pieces_arr,
  352. castle_white_kingside,
  353. castle_white_queenside,
  354. castle_black_kingside,
  355. castle_black_queenside,
  356. half_moves,
  357. full_moves,
  358. en_passant,
  359. }
  360. }
  361. pub fn standard() -> GameState {
  362. GameState {
  363. color_to_move: 0usize,
  364. pieces: [[0xff00u64, 0xff000000000000u64], [0x42u64, 0x4200000000000000u64], [0x24u64, 0x2400000000000000u64], [0x81u64, 0x8100000000000000u64],
  365. [0x8u64, 0x800000000000000u64], [0x10u64, 0x1000000000000000u64]],
  366. castle_white_kingside: true,
  367. castle_white_queenside: true,
  368. castle_black_kingside: true,
  369. castle_black_queenside: true,
  370. en_passant: 0u64,
  371. half_moves: 0usize,
  372. full_moves: 1usize,
  373. }
  374. }
  375. }
  376.  
  377. pub const STD_FEN:&str ="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
  378.  
  379. use rand::Rng;
  380.  
  381. static mut ROOK_BITS: [usize; 64] = [
  382. 12, 11, 11, 11, 11, 11, 11, 12,
  383. 11, 10, 10, 10, 10, 10, 10, 11,
  384. 11, 10, 10, 10, 10, 10, 10, 11,
  385. 11, 10, 10, 10, 10, 10, 10, 11,
  386. 11, 10, 10, 10, 10, 10, 10, 11,
  387. 11, 10, 10, 10, 10, 10, 10, 11,
  388. 11, 10, 10, 10, 10, 10, 10, 11,
  389. 12, 11, 11, 11, 11, 11, 11, 12
  390. ];
  391. static mut BISHOP_BITS: [usize; 64] = [
  392. 6, 5, 5, 5, 5, 5, 5, 6,
  393. 5, 5, 5, 5, 5, 5, 5, 5,
  394. 5, 5, 7, 7, 7, 7, 5, 5,
  395. 5, 5, 7, 9, 9, 7, 5, 5,
  396. 5, 5, 7, 9, 9, 7, 5, 5,
  397. 5, 5, 7, 7, 7, 7, 5, 5,
  398. 5, 5, 5, 5, 5, 5, 5, 5,
  399. 6, 5, 5, 5, 5, 5, 5, 6
  400. ];
  401. const MAGIC_NUMS_ROOKS: [u64; 64] = [
  402. 0x2180028011204008u64, 0x21400190002000c0u64, 0x8480100020000b80u64, 0x80100080061800u64, 0xc100080004030010u64, 0x200084430120001u64, 0x1880110006800200u64, 0x100006200804100u64, 0x4084800280400020u64, 0x8400400050002000u64, 0xd001020010342u64, 0x20040102008040u64, 0x8000802400810800u64, 0x2922002804100a01u64, 0x4109002a0099000cu64, 0x40020000840e0841u64, 0x800848000204011u64, 0x900444000201008u64, 0x5201010020049142u64, 0x80620009c20030u64, 0x45310004080100u64, 0x808002001400u64, 0x1090840002100328u64, 0x8022000184085bu64, 0x401080028020u64, 0x4910400080802000u64, 0x1400403100200100u64, 0x910008080180450u64, 0x200040080800800u64, 0x1052000200100429u64, 0x2004e80c000a1110u64, 0x1423000100005282u64, 0x8088834000800aa0u64, 0x10080c000806000u64, 0x8010200082805002u64, 0x82101003000u64, 0x7040080280800400u64, 0x610c004100401200u64, 0x5700010804001002u64, 0x1000008042000904u64, 0x21049460c0008000u64, 0x410014020004002u64, 0x20100a001410013u64, 0x401000810010020u64, 0x4008012400808008u64, 0x808200440480110u64, 0x1b81040200010100u64, 0x8020040040820003u64, 0x80002108508100u64, 0x10242082b008200u64, 0x801004090200100u64, 0x4003002008100100u64, 0x8180080440080u64, 0x890c0004800a0080u64, 0x104020108102400u64, 0x41111040840200u64, 0x1010201601008042u64, 0x127002440013181u64, 0x102104209220082u64, 0xa011009001242009u64, 0x81000228001085u64, 0x5022001008011c02u64, 0x100821000810804u64, 0x100002280d601u64, ];
  403. const MAGIC_NUMS_BISHOPS: [u64; 64] = [
  404. 0x6040422a14086080u64, 0x4084800408020u64, 0x400c080210440010u64, 0x44042080000000u64, 0x2610882002100a00u64, 0x9030080c0080u64, 0xc140841048148004u64, 0x200844c100442u64, 0x40042004042682u64, 0x4200100608410a28u64, 0x802010052a202108u64, 0x800c080601410802u64, 0xc001011040020004u64, 0x488811002902400u64, 0xa008024210106808u64, 0x1004a100e9042004u64, 0x2030002102e20800u64, 0x510a5810210042u64, 0x68010408089830u64, 0x41c800802044200u64, 0x4004080a04000u64, 0x4004080203040a00u64, 0x830642382040u64, 0x8200401101c23040u64, 0x8400248108110u64, 0x4440020289080u64, 0x3008040408004050u64, 0x8004004004010002u64, 0x921004024044016u64, 0x201840802020a00u64, 0x20222c0000414811u64, 0x5802068602404810u64, 0x2791200810a29848u64, 0x2650821000081000u64, 0x415000480322u64, 0x2041401820060200u64, 0x1020200240104u64, 0x10802000c2212u64, 0xe002880a00005200u64, 0x2001062200402100u64, 0x52105044000850u64, 0x204590820800818u64, 0x1201410082a00u64, 0x440004200810800u64, 0x20080100442401u64, 0x200b200214100880u64, 0x2810108100400100u64, 0x8824640052011048u64, 0x4281040114400060u64, 0x988824040208001du64, 0x806081c40c040909u64, 0x20090084110014u64, 0x304006022440118u64, 0x1011400304010004u64, 0xa1020010410a048u64, 0x8110020809002809u64, 0x40010022100c0413u64, 0x2800020125011014u64, 0x46082400u64, 0x60408400840401u64, 0x8001020010021204u64, 0x4c00100812084200u64, 0x20000420440c1098u64, 0x802200c01120060u64, ];
  405. lazy_static! {
  406. pub static ref FILES: [u64;8] = initialize_files();
  407. pub static ref NOT_FILES: [u64;8] = initialize_not_files();
  408. pub static ref RANKS: [u64;8] = initialize_ranks();
  409. pub static ref SQUARES: [u64;64]= initialize_squares();
  410. pub static ref NOT_SQUARES: [u64;64]= initialize_not_squares();
  411. pub static ref MAGICS_ROOKS: Vec<Magic>= init_magics_rooks();
  412. pub static ref MAGICS_BISHOPS:Vec<Magic>= init_magics_bishops();
  413. pub static ref KING_ATTACKS:[u64;64] = init_king_attacks();
  414. pub static ref KNIGHT_ATTACKS:[u64;64] = init_knight_attacks();
  415. pub static ref FILES_LESS_THAN:[u64;8]= init_files_less_than();
  416. pub static ref FILES_GREATER_THAN:[u64;8]= init_files_greater_than();
  417. pub static ref RANKS_LESS_THAN:[u64;8]= init_ranks_less_than();
  418. pub static ref RANKS_GREATER_THAN:[u64;8]= init_ranks_greater_than();
  419. }
  420. pub struct Magic {
  421. pub occupancy_mask: u64,
  422. pub shift: usize,
  423. pub magic_num: u64,
  424. pub lookup_table: Vec<u64>,
  425. }
  426.  
  427. impl Magic {
  428. pub fn get_attacks(&self, all_pieces_board: u64) -> u64 {
  429. self.lookup_table[(((all_pieces_board & self.occupancy_mask).wrapping_mul(self.magic_num)) >> (64 - self.shift)) as usize]
  430. }
  431. }
  432.  
  433. pub fn init_all() {
  434. FILES.len();
  435. NOT_FILES.len();
  436. RANKS.len();
  437. SQUARES.len();
  438. NOT_SQUARES.len();
  439. //Override Magics with better magic nums
  440. MAGICS_ROOKS.len();
  441. MAGICS_BISHOPS.len();
  442. KING_ATTACKS.len();
  443. KNIGHT_ATTACKS.len();
  444. FILES_LESS_THAN.len();
  445. FILES_GREATER_THAN.len();
  446. RANKS_LESS_THAN.len();
  447. RANKS_GREATER_THAN.len();
  448. }
  449.  
  450. //Rook-specific magic
  451. pub fn init_magics_rooks() -> Vec<Magic> {
  452. let mut res: Vec<Magic> = Vec::with_capacity(64);
  453. for square in 0..64 {
  454. let shift;
  455. unsafe {
  456. shift = ROOK_BITS[square];
  457. }
  458. let occupancy_mask = occupancy_mask_rooks(square);
  459. if occupancy_mask.count_ones() as usize != shift {
  460. panic!("Not good!");
  461. }
  462. let mut blockers_by_index: Vec<u64> = Vec::with_capacity(1 << shift);
  463. let mut attack_table: Vec<u64> = Vec::with_capacity(1 << shift);
  464. //Initialize lookup table
  465. for i in 0..(1 << shift) {
  466. //i is index of lookup table
  467. blockers_by_index.push(blockers_to_bitboard(i, shift, occupancy_mask));
  468. attack_table.push(rook_attacks_slow(square, blockers_by_index[i]));
  469. }
  470. let magic_num = MAGIC_NUMS_ROOKS[square];
  471. let mut lookup_table = Vec::with_capacity(1 << shift);
  472. for _i in 0..(1 << shift) {
  473. lookup_table.push(0u64);
  474. }
  475. //Calculate look-up table
  476. for i in 0..(1 << shift) {
  477. let j = transform(blockers_by_index[i], magic_num, shift);
  478. if lookup_table[j] == 0u64 {
  479. lookup_table[j] = attack_table[i];
  480. } else {
  481. panic!("Isn't valid num!")
  482. }
  483. }
  484. res.push(Magic {
  485. occupancy_mask,
  486. shift,
  487. magic_num,
  488. lookup_table,
  489. })
  490. }
  491. println!("Finished Initializing Rook Attacks!");
  492. res
  493. }
  494.  
  495. pub fn occupancy_mask_rooks(square: usize) -> u64 {
  496. (((RANKS[square / 8] & !(FILES[0] | FILES[7])) | (FILES[square % 8] & !(RANKS[0] | RANKS[7]))) & NOT_SQUARES[square])
  497. }
  498.  
  499. pub fn rook_attacks_slow(square: usize, blocks: u64) -> u64 {
  500. let mut res = 0u64;
  501. let rank: isize = (square / 8) as isize;
  502. let file: isize = (square % 8) as isize;
  503. let dirs: [(isize, isize); 4] = [(0, 1), (0, -1), (1, 0), (-1, 0)];
  504. for dir in dirs.iter() {
  505. let (file_i, rank_i) = dir;
  506. let mut rn = rank + rank_i;
  507. let mut fnn = file + file_i;
  508. while rn >= 0 && rn <= 7 && fnn >= 0 && fnn <= 7 {
  509. res |= 1u64 << (rn * 8 + fnn);
  510. if (blocks & (1u64 << (rn * 8 + fnn))) != 0 {
  511. break;
  512. }
  513. rn += rank_i;
  514. fnn += file_i;
  515. }
  516. }
  517. res
  518. }
  519. //Bishop-specific magic
  520. pub fn init_magics_bishops() -> Vec<Magic> {
  521. let mut res: Vec<Magic> = Vec::with_capacity(64);
  522. for square in 0..64 {
  523. let shift;
  524. unsafe {
  525. shift = BISHOP_BITS[square];
  526. }
  527.  
  528. let occupancy_mask = occupancy_mask_bishops(square);
  529. if occupancy_mask.count_ones() as usize != shift {
  530. panic!("Not good!");
  531. }
  532.  
  533. let mut blockers_by_index: Vec<u64> = Vec::with_capacity(1 << shift);
  534. let mut attack_table: Vec<u64> = Vec::with_capacity(1 << shift);
  535. //Initialize lookup table
  536. for i in 0..(1 << shift) {
  537. //i is index of lookup table
  538. blockers_by_index.push(blockers_to_bitboard(i, shift, occupancy_mask));
  539. attack_table.push(bishop_attacks_slow(square, blockers_by_index[i]));
  540. }
  541.  
  542. let magic_num = MAGIC_NUMS_BISHOPS[square];
  543. let mut lookup_table = Vec::with_capacity(1 << shift);
  544. for _i in 0..(1 << shift) {
  545. lookup_table.push(0u64);
  546. }
  547. //Calculate look-up table
  548. for i in 0..(1 << shift) {
  549. let j = transform(blockers_by_index[i], magic_num, shift);
  550. if lookup_table[j] == 0u64 {
  551. lookup_table[j] = attack_table[i];
  552. } else {
  553. panic!("Isn't valid num!")
  554. }
  555. }
  556. res.push(Magic {
  557. occupancy_mask,
  558. shift,
  559. magic_num,
  560. lookup_table,
  561. })
  562. }
  563. println!("Finished Initializing Bishop Attacks!");
  564. res
  565. }
  566.  
  567. pub fn occupancy_mask_bishops(square: usize) -> u64 {
  568. let mut res = 0u64;
  569. let rk = (square / 8) as isize;
  570. let fl = (square % 8) as isize;
  571. let dirs: [(isize, isize); 4] = [(1, 1), (-1, -1), (1, -1), (-1, 1)];
  572. for dir in dirs.iter() {
  573. let (file_i, rank_i) = dir;
  574. let mut rn = rk + rank_i;
  575. let mut fnn = fl + file_i;
  576. while rn >= 1 && rn <= 6 && fnn >= 1 && fnn <= 6 {
  577. res |= 1u64 << (rn * 8 + fnn);
  578. rn += rank_i;
  579. fnn += file_i;
  580. }
  581. }
  582. res
  583. }
  584.  
  585. pub fn bishop_attacks_slow(square: usize, blocks: u64) -> u64 {
  586. let mut res = 0u64;
  587. let rank: isize = (square / 8) as isize;
  588. let file: isize = (square % 8) as isize;
  589. let dirs: [(isize, isize); 4] = [(1, 1), (-1, -1), (1, -1), (-1, 1)];
  590. for dir in dirs.iter() {
  591. let (file_i, rank_i) = dir;
  592. let mut rn = rank + rank_i;
  593. let mut fnn = file + file_i;
  594. while rn >= 0 && rn <= 7 && fnn >= 0 && fnn <= 7 {
  595. res |= 1u64 << (rn * 8 + fnn);
  596. if (blocks & (1u64 << (rn * 8 + fnn))) != 0 {
  597. break;
  598. }
  599. rn += rank_i;
  600. fnn += file_i;
  601. }
  602. }
  603. res
  604. }
  605. //General Magic stuff
  606. pub fn transform(blockers: u64, magic: u64, n_bits: usize) -> usize {
  607. ((blockers.wrapping_mul(magic)) >> (64 - n_bits)) as usize
  608. }
  609.  
  610. pub fn generate_magic(blockers_by_index: &Vec<u64>, attack_table: &Vec<u64>, n_bits: usize, occ_mask: u64) -> u64 {
  611. for _iterations in 0..100000000 {
  612. let random_magic = random_u64_fewbits();
  613. if ((occ_mask.wrapping_mul(random_magic)) & 0xFF00000000000000u64) < 6 {
  614. continue;
  615. }
  616. if is_valid_magic(random_magic, n_bits, blockers_by_index, attack_table) {
  617. return random_magic;
  618. }
  619. }
  620. panic!("No Magic found!");
  621. }
  622.  
  623. pub fn is_valid_magic(magic: u64, n_bits: usize, blockers_by_index: &Vec<u64>, attack_table: &Vec<u64>) -> bool {
  624. let mut used = Vec::with_capacity(1 << n_bits);
  625. for _i in 0..(1 << n_bits) {
  626. used.push(0u64);
  627. }
  628. for i in 0..(1 << n_bits) {
  629. let j = transform(blockers_by_index[i], magic, n_bits);
  630. if used[j] == 0u64 {
  631. used[j] = attack_table[i];
  632. } else if used[j] != attack_table[i] {
  633. return false;
  634. }
  635. }
  636. return true;
  637. }
  638.  
  639. pub fn random_u64() -> u64 {
  640. rand::thread_rng().gen::<u64>()
  641. }
  642.  
  643. pub fn random_u64_fewbits() -> u64 {
  644. random_u64() & random_u64() & random_u64()
  645. }
  646.  
  647. pub fn blockers_to_bitboard(block_index: usize, n_bits: usize, mut mask: u64) -> u64 {
  648. let mut res = 0u64;
  649. for i in 0..n_bits {
  650. let j = mask.trailing_zeros();
  651. mask &= !(1 << j);
  652. if (block_index & (1 << i)) != 0 {
  653. res |= 1u64 << j;
  654. }
  655. }
  656. res
  657. }
  658.  
  659. //Initializing General BitBoards
  660.  
  661. pub fn initialize_files() -> [u64; 8] {
  662. let mut res = [0u64; 8];
  663. for file in 0..8 {
  664. if file == 0 {
  665. res[0] = 1u64 << 0 | 1u64 << 8 | 1u64 << 16 | 1u64 << 24 | 1u64 << 32 | 1u64 << 40 | 1u64 << 48 | 1u64 << 56;
  666. } else {
  667. res[file] = res[file - 1] << 1;
  668. }
  669. }
  670. println!("Finished Initializing Files!");
  671. res
  672. }
  673.  
  674. pub fn initialize_not_files() -> [u64; 8] {
  675. let mut res = [0u64; 8];
  676. for file in 0..8 {
  677. res[file] = !FILES[file];
  678. }
  679. println!("Finished Initializing NOT Files!");
  680. res
  681. }
  682.  
  683. pub fn initialize_ranks() -> [u64; 8] {
  684. let mut res = [0u64; 8];
  685. for rank in 0..8 {
  686. if rank == 0 {
  687. res[0] = 1u64 << 0 | 1u64 << 1 | 1u64 << 2 | 1u64 << 3 | 1u64 << 4 | 1u64 << 5 | 1u64 << 6 | 1u64 << 7;
  688. } else {
  689. res[rank] = res[rank - 1] << 8;
  690. }
  691. }
  692. println!("Finished Initializing Ranks!");
  693. res
  694. }
  695.  
  696. pub fn initialize_squares() -> [u64; 64] {
  697. let mut res = [0u64; 64];
  698. for squares in 0..64 {
  699. res[squares] = 1u64 << squares;
  700. }
  701. println!("Finished Initializing Squares!");
  702. res
  703. }
  704.  
  705. pub fn initialize_not_squares() -> [u64; 64] {
  706. let mut res = [0u64; 64];
  707. for squares in 0..64 {
  708. res[squares] = !(1u64 << squares);
  709. }
  710. println!("Finished Initializing NOT_Squares!");
  711. res
  712. }
  713.  
  714. pub fn north_one(board: u64) -> u64 {
  715. board << 8
  716. }
  717.  
  718. pub fn north_east_one(board: u64) -> u64 {
  719. (board & NOT_FILES[7]) << 9
  720. }
  721.  
  722. pub fn north_west_one(board: u64) -> u64 {
  723. (board & NOT_FILES[0]) << 7
  724. }
  725.  
  726. pub fn south_one(board: u64) -> u64 {
  727. board >> 8
  728. }
  729.  
  730. pub fn south_east_one(board: u64) -> u64 {
  731. (board & NOT_FILES[7]) >> 7
  732. }
  733.  
  734. pub fn south_west_one(board: u64) -> u64 {
  735. (board & NOT_FILES[0]) >> 9
  736. }
  737.  
  738. pub fn west_one(board: u64) -> u64 {
  739. (board & NOT_FILES[0]) >> 1
  740. }
  741.  
  742. pub fn east_one(board: u64) -> u64 {
  743. (board & NOT_FILES[7]) << 1
  744. }
  745.  
  746. pub fn king_attack(mut king_board: u64) -> u64 {
  747. let mut attacks = east_one(king_board) | west_one(king_board);
  748. king_board |= attacks;
  749. attacks |= south_one(king_board) | north_one(king_board);
  750. attacks
  751. }
  752.  
  753. pub fn init_king_attacks() -> [u64; 64] {
  754. let mut res = [0u64; 64];
  755. for square in 0..64 {
  756. res[square] = king_attack(1u64 << square);
  757. }
  758. println!("Finished Initializing King Attacks!");
  759. res
  760. }
  761.  
  762. pub fn knight_attack(knight: u64) -> u64 {
  763. let mut attacks;
  764. let mut east = east_one(knight);
  765. let mut west = west_one(knight);
  766. attacks = (east | west) << 16;
  767. attacks |= (east | west) >> 16;
  768. east = east_one(east);
  769. west = west_one(west);
  770. attacks |= (east | west) << 8;
  771. attacks |= (east | west) >> 8;
  772. attacks
  773. }
  774.  
  775. pub fn init_knight_attacks() -> [u64; 64] {
  776. let mut res = [0u64; 64];
  777. for square in 0..64 {
  778. res[square] = knight_attack(1u64 << square);
  779. }
  780. println!("Finished Initializing Knight Attacks!");
  781. res
  782. }
  783.  
  784. pub fn init_files_less_than() -> [u64; 8] {
  785. let mut res = [0u64; 8];
  786. for files in 0..8 {
  787. for files_less_than in 0..files {
  788. res[files] |= FILES[files_less_than];
  789. }
  790. }
  791. println!("Finished Initializing FilesLessThan!");
  792. res
  793. }
  794.  
  795. pub fn init_ranks_less_than() -> [u64; 8] {
  796. let mut res = [0u64; 8];
  797. for ranks in 0..8 {
  798. for ranks_less_than in 0..ranks {
  799. res[ranks] |= RANKS[ranks_less_than];
  800. }
  801. }
  802. println!("Finished Initializing RanksLessThan!");
  803. res
  804. }
  805.  
  806. pub fn init_files_greater_than() -> [u64; 8] {
  807. let mut res = [0u64; 8];
  808. for files in 0..8 {
  809. res[files] = !FILES_LESS_THAN[files] & !FILES[files];
  810. }
  811. println!("Finished Initializing FilesGreaterThan!");
  812. res
  813. }
  814.  
  815. pub fn init_ranks_greater_than() -> [u64; 8] {
  816. let mut res = [0u64; 8];
  817. for ranks in 0..8 {
  818. res[ranks] = !RANKS_LESS_THAN[ranks] & !RANKS[ranks];
  819. }
  820. println!("Finished Initializing FilesGreaterThan!");
  821. res
  822. }
  823.  
  824. //Misc
  825. pub fn to_string_board(board: u64) -> String {
  826. let mut res_str: String = String::new();
  827. res_str.push_str("+---+---+---+---+---+---+---+---+n");
  828. for rank in 0..8 {
  829. res_str.push_str("| ");
  830. for file in 0..8 {
  831. let idx = 8 * (7 - rank) + file;
  832. if ((board >> idx) & 1) != 0 {
  833. res_str.push_str("X");
  834. } else {
  835. res_str.push_str(" ");
  836. }
  837. res_str.push_str(" | ");
  838. }
  839. res_str.push_str("n+---+---+---+---+---+---+---+---+n");
  840. }
  841. res_str
  842. }
  843.  
  844. use super::bitboards;
  845. use super::game_state::{self, GameMove, GameMoveType, PieceType};
  846.  
  847. //Move GEn
  848. //King- Piece-Wise by lookup
  849. //Knight-Piece-Wise by lookup
  850. //Bishop/Queen/Rook - Piece-Wise by lookup in Magic
  851. //Pawn-SetWise by shift
  852. pub fn king_attack(square: usize) -> u64 {
  853. bitboards::KING_ATTACKS[square]
  854. }
  855.  
  856. pub fn bishop_attack(square: usize, all_pieces: u64) -> u64 {
  857. bitboards::Magic::get_attacks(&bitboards::MAGICS_BISHOPS[square], all_pieces)
  858. }
  859.  
  860. pub fn rook_attack(square: usize, all_pieces: u64) -> u64 {
  861. bitboards::Magic::get_attacks(&bitboards::MAGICS_ROOKS[square], all_pieces)
  862. }
  863.  
  864. pub fn knight_attack(square: usize) -> u64 {
  865. bitboards::KNIGHT_ATTACKS[square]
  866. }
  867.  
  868. pub fn w_single_push_pawn_targets(pawns: u64, empty: u64) -> u64 {
  869. bitboards::north_one(pawns) & empty
  870. }
  871.  
  872. pub fn w_double_push_pawn_targets(pawns: u64, empty: u64) -> u64 {
  873. bitboards::north_one(bitboards::north_one(pawns & bitboards::RANKS[1]) & empty) & empty
  874. }
  875.  
  876. pub fn b_single_push_pawn_targets(pawns: u64, empty: u64) -> u64 {
  877. bitboards::south_one(pawns) & empty
  878. }
  879.  
  880. pub fn b_double_push_pawn_targets(pawns: u64, empty: u64) -> u64 {
  881. bitboards::south_one(bitboards::south_one(pawns & bitboards::RANKS[6]) & empty) & empty
  882. }
  883.  
  884. //NorthEast = +9
  885. pub fn w_pawn_east_targets(pawns: u64) -> u64 {
  886. bitboards::north_east_one(pawns)
  887. }
  888.  
  889. //NorthWest = +7
  890. pub fn w_pawn_west_targets(pawns: u64) -> u64 {
  891. bitboards::north_west_one(pawns)
  892. }
  893.  
  894. //SouthEast = -7
  895. pub fn b_pawn_east_targets(pawns: u64) -> u64 {
  896. bitboards::south_west_one(pawns)
  897. }
  898.  
  899. //NorthWest = -9
  900. pub fn b_pawn_west_targets(pawns: u64) -> u64 {
  901. bitboards::south_east_one(pawns)
  902. }
  903.  
  904. pub fn add_moves(move_list: &mut Vec<GameMove>, from: usize, mut to_board: u64, piece_type: &PieceType, move_type: GameMoveType) {
  905. while to_board != 0u64 {
  906. let idx = to_board.trailing_zeros() as usize;
  907. let move_t_cl = move_type.clone();
  908. let pt_cl= piece_type.clone();
  909. move_list.push(GameMove {
  910. from,
  911. to: idx,
  912. move_type: move_t_cl,
  913. piece_type: pt_cl
  914. });
  915. to_board ^= 1u64 << idx;
  916. //to_board&= to_board-1;
  917. }
  918. }
  919.  
  920. pub fn add_quiet_pawn_single_pushes(mut single_push_board: u64, color_to_move: &usize, move_list: &mut Vec<GameMove>) {
  921. while single_push_board != 0u64 {
  922. let idx = single_push_board.trailing_zeros() as usize;
  923. move_list.push(GameMove {
  924. from: if *color_to_move == 0 { idx - 8 } else { idx + 8 },
  925. to: idx,
  926. move_type: GameMoveType::Quiet,
  927. piece_type: PieceType::Pawn,
  928. });
  929. single_push_board ^= 1 << idx;
  930. }
  931. }
  932.  
  933. pub fn add_quiet_pawn_double_pushes(mut double_push_board: u64, color_to_move: &usize, move_list: &mut Vec<GameMove>) {
  934. while double_push_board != 0u64 {
  935. let idx = double_push_board.trailing_zeros() as usize;
  936. move_list.push(GameMove {
  937. from: if *color_to_move == 0 { idx - 16 } else { idx + 16 },
  938. to: idx,
  939. move_type: GameMoveType::Quiet,
  940. piece_type: PieceType::Pawn,
  941. });
  942. double_push_board ^= 1 << idx;
  943. }
  944. }
  945.  
  946. pub fn add_promotion_push(mut promotion_board: u64, color_to_move: &usize, move_list: &mut Vec<GameMove>, source_shift: usize) {
  947. while promotion_board != 0u64 {
  948. let idx = promotion_board.trailing_zeros() as usize;
  949. move_list.push(GameMove {
  950. from: if *color_to_move == 0 { idx - source_shift } else { idx + source_shift },
  951. to: idx,
  952. move_type: GameMoveType::Promotion(PieceType::Queen),
  953. piece_type: PieceType::Pawn,
  954. });
  955. move_list.push(GameMove {
  956. from: if *color_to_move == 0 { idx - source_shift } else { idx + source_shift },
  957. to: idx,
  958. move_type: GameMoveType::Promotion(PieceType::Rook),
  959. piece_type: PieceType::Pawn,
  960. });
  961. move_list.push(GameMove {
  962. from: if *color_to_move == 0 { idx - source_shift } else { idx + source_shift },
  963. to: idx,
  964. move_type: GameMoveType::Promotion(PieceType::Bishop),
  965. piece_type: PieceType::Pawn,
  966. });
  967. move_list.push(GameMove {
  968. from: if *color_to_move == 0 { idx - source_shift } else { idx + source_shift },
  969. to: idx,
  970. move_type: GameMoveType::Promotion(PieceType::Knight),
  971. piece_type: PieceType::Pawn,
  972. });
  973. promotion_board ^= 1 << idx;
  974. }
  975. }
  976.  
  977. pub fn add_pawn_capture(mut capture_board: u64, color_to_move: &usize, move_list: &mut Vec<GameMove>, source_shift: usize) {
  978. while capture_board != 0u64 {
  979. let idx = capture_board.trailing_zeros() as usize;
  980. move_list.push(GameMove {
  981. from: if *color_to_move == 0 { idx - source_shift } else { idx + source_shift },
  982. to: idx,
  983. move_type: GameMoveType::Capture,
  984. piece_type: PieceType::Pawn,
  985. });
  986. capture_board ^= 1 << idx;
  987. }
  988. }
  989.  
  990. pub fn add_en_passants(mut enpassant_board: u64, color_to_move: &usize, move_list: &mut Vec<GameMove>, source_shift: usize, all_pieces_without_my_king: u64, enemy_rooks: u64, my_king_idx: usize) {
  991. while enpassant_board != 0u64 {
  992. let index = enpassant_board.trailing_zeros() as usize;
  993. enpassant_board ^= 1u64 << index;
  994. //Check if rare case didn't happen
  995. //Remove t-7,t-8 or t+7,t+8
  996. let all_pieces_without_en_passants = all_pieces_without_my_king & !bitboards::SQUARES[if *color_to_move == 0 { index - source_shift } else { index + source_shift }]
  997. & !bitboards::SQUARES[if *color_to_move == 0 { index - 8 } else { index + 8 }];
  998. if rook_attack(my_king_idx, all_pieces_without_en_passants) & (!bitboards::FILES[my_king_idx % 8]) & enemy_rooks != 0 {
  999. continue;
  1000. }
  1001. move_list.push(GameMove {
  1002. from: if *color_to_move == 0 { index - source_shift } else { index + source_shift },
  1003. to: index,
  1004. move_type: GameMoveType::EnPassant,
  1005. piece_type: PieceType::Pawn,
  1006. });
  1007. }
  1008. }
  1009.  
  1010. //Make moves
  1011. pub fn make_move(g: &game_state::GameState, mv: &game_state::GameMove) -> game_state::GameState {
  1012. match mv.move_type {
  1013. GameMoveType::Quiet => make_quiet_move(&g, &mv),
  1014. GameMoveType::Capture => make_capture_move(&g, &mv),
  1015. GameMoveType::EnPassant => make_enpassant_move(&g, &mv),
  1016. GameMoveType::Castle => make_castle_move(&g, &mv),
  1017. GameMoveType::Promotion(PieceType::Queen) | GameMoveType::Promotion(PieceType::Rook) | GameMoveType::Promotion(PieceType::Bishop) | GameMoveType::Promotion(PieceType::Knight)
  1018. => make_promotion_move(&g, &mv),
  1019. _ => panic!("Invalid move type")
  1020. }
  1021. }
  1022.  
  1023. pub fn move_piece(pieces: &mut [[u64; 2]; 6], mv: &game_state::GameMove, move_color: usize) {
  1024. let index = match mv.piece_type {
  1025. PieceType::Pawn => 0,
  1026. PieceType::Knight => 1,
  1027. PieceType::Bishop => 2,
  1028. PieceType::Rook => 3,
  1029. PieceType::Queen => 4,
  1030. PieceType::King => 5,
  1031. };
  1032. pieces[index][move_color] ^= bitboards::SQUARES[mv.from];
  1033. pieces[index][move_color] |= bitboards::SQUARES[mv.to];
  1034. //pieces[index][move_color] ^= 1u64<<mv.from;
  1035. //pieces[index][move_color] |= 1u64<<mv.to;
  1036. }
  1037.  
  1038. pub fn delete_piece(pieces: &mut [[u64; 2]; 6], delete_square: usize, delete_color: usize) {
  1039. pieces[0][delete_color] &= bitboards::NOT_SQUARES[delete_square];
  1040. pieces[1][delete_color] &= bitboards::NOT_SQUARES[delete_square];
  1041. pieces[2][delete_color] &= bitboards::NOT_SQUARES[delete_square];
  1042. pieces[3][delete_color] &= bitboards::NOT_SQUARES[delete_square];
  1043. pieces[4][delete_color] &= bitboards::NOT_SQUARES[delete_square];
  1044. }
  1045.  
  1046. pub fn check_castle_flags(ck: bool, cq: bool, mv: &game_state::GameMove, color_to_move: usize, pieces: [[u64; 2]; 6]) -> (bool, bool) {
  1047. match mv.piece_type {
  1048. PieceType::King => (false, false),
  1049. PieceType::Rook => {
  1050. let mut new_ck = ck;
  1051. if ck {
  1052. if color_to_move == 0 {
  1053. if pieces[3][0] & bitboards::SQUARES[7] == 0 {
  1054. new_ck = false;
  1055. }
  1056. } else {
  1057. if pieces[3][1] & bitboards::SQUARES[63] == 0 {
  1058. new_ck = false;
  1059. }
  1060. }
  1061. }
  1062. let mut new_cq = cq;
  1063. if cq {
  1064. if color_to_move == 0 {
  1065. if pieces[3][0] & bitboards::SQUARES[0] == 0 {
  1066. new_cq = false;
  1067. }
  1068. } else {
  1069. if pieces[3][1] & bitboards::SQUARES[56] == 0 {
  1070. new_cq = false;
  1071. }
  1072. }
  1073. }
  1074. (new_ck, new_cq)
  1075. }
  1076. _ => (ck, cq)
  1077. }
  1078. }
  1079.  
  1080. pub fn make_quiet_move(g: &game_state::GameState, mv: &game_state::GameMove) -> game_state::GameState {
  1081. let color_to_move = 1 - g.color_to_move;
  1082. let mut pieces = g.pieces.clone();
  1083. //Make the move
  1084. move_piece(&mut pieces, &mv, g.color_to_move);
  1085.  
  1086. //Check new castle rights
  1087. //The enemies castle right's can't change on a quiet move
  1088. let (castle_white_kingside, castle_white_queenside) = if g.color_to_move == 0 {
  1089. check_castle_flags(g.castle_white_kingside, g.castle_white_queenside, &mv, g.color_to_move, pieces)
  1090. } else { (g.castle_white_kingside, g.castle_white_queenside) };
  1091. let (castle_black_kingside, castle_black_queenside) = if g.color_to_move == 0 {
  1092. (g.castle_black_kingside, g.castle_black_queenside)
  1093. } else { check_castle_flags(g.castle_black_kingside, g.castle_black_queenside, &mv, g.color_to_move, pieces) };
  1094.  
  1095. //This will be taken care of later
  1096. let mut en_passant = 0u64;
  1097.  
  1098. let mut half_moves = g.half_moves + 1;
  1099.  
  1100. //Reset half moves if its a pawn move and also check if its a double pawn move, if so, set en passant flag
  1101. match mv.piece_type {
  1102. PieceType::Pawn => {
  1103. half_moves = 0;
  1104. if g.color_to_move == 0 && mv.to - mv.from == 16 {
  1105. en_passant = bitboards::SQUARES[mv.to - 8];
  1106. } else if g.color_to_move == 1 && mv.from - mv.to == 16 {
  1107. en_passant = bitboards::SQUARES[mv.to + 8];
  1108. }
  1109. }
  1110. _ => {}
  1111. };
  1112.  
  1113. //If black was to move, increase full moves by one
  1114. let full_moves = g.full_moves + g.color_to_move;
  1115. //Create new game state object
  1116. game_state::GameState {
  1117. color_to_move,
  1118. pieces,
  1119. castle_white_kingside,
  1120. castle_white_queenside,
  1121. castle_black_kingside,
  1122. castle_black_queenside,
  1123. en_passant,
  1124. half_moves,
  1125. full_moves,
  1126. }
  1127. }
  1128.  
  1129. pub fn make_capture_move(g: &game_state::GameState, mv: &game_state::GameMove) -> game_state::GameState {
  1130. let color_to_move = 1 - g.color_to_move;
  1131. let mut pieces = g.pieces.clone();
  1132. //Make the move
  1133. move_piece(&mut pieces, &mv, g.color_to_move);
  1134. //Delete to from enemy pieces
  1135. delete_piece(&mut pieces, mv.to, color_to_move);
  1136.  
  1137. let (mut castle_white_kingside, mut castle_white_queenside) = if g.color_to_move == 0 {
  1138. check_castle_flags(g.castle_white_kingside, g.castle_white_queenside, &mv, g.color_to_move, pieces)
  1139. } else { (g.castle_white_kingside, g.castle_white_queenside) };
  1140. let (mut castle_black_kingside, mut castle_black_queenside) = if g.color_to_move == 0 {
  1141. (g.castle_black_kingside, g.castle_black_queenside)
  1142. } else { check_castle_flags(g.castle_black_kingside, g.castle_black_queenside, &mv, g.color_to_move, pieces) };
  1143.  
  1144. if g.color_to_move == 0 {
  1145. //Check that blacks rook didn't get captured
  1146. if pieces[3][1] & bitboards::SQUARES[56] == 0 {
  1147. castle_black_queenside = false;
  1148. }
  1149. if pieces[3][1] & bitboards::SQUARES[63] == 0 {
  1150. castle_black_kingside = false;
  1151. }
  1152. } else {
  1153. if pieces[3][0] & bitboards::SQUARES[0] == 0 {
  1154. castle_white_queenside = false;
  1155. }
  1156. if pieces[3][0] & bitboards::SQUARES[7] == 0 {
  1157. castle_white_kingside = false;
  1158. }
  1159. }
  1160. let en_passant = 0u64;
  1161.  
  1162. let half_moves = 0usize;
  1163. let full_moves = g.full_moves + g.color_to_move;
  1164.  
  1165. game_state::GameState {
  1166. color_to_move,
  1167. pieces,
  1168. castle_white_kingside,
  1169. castle_white_queenside,
  1170. castle_black_kingside,
  1171. castle_black_queenside,
  1172. en_passant,
  1173. half_moves,
  1174. full_moves,
  1175. }
  1176. }
  1177.  
  1178. pub fn make_enpassant_move(g: &game_state::GameState, mv: &game_state::GameMove) -> game_state::GameState {
  1179. let color_to_move = 1 - g.color_to_move;
  1180. let mut pieces = g.pieces.clone();
  1181. //Make the move
  1182. move_piece(&mut pieces, &mv, g.color_to_move);
  1183. //Delete enemy pawn
  1184. delete_piece(&mut pieces, if g.color_to_move == 0 { mv.to - 8 } else { mv.to + 8 }, color_to_move);
  1185.  
  1186. let castle_white_kingside = g.castle_white_kingside;
  1187. let castle_white_queenside = g.castle_white_queenside;
  1188. let castle_black_kingside = g.castle_black_kingside;
  1189. let castle_black_queenside = g.castle_black_queenside;
  1190.  
  1191. let en_passant = 0u64;
  1192.  
  1193. let half_moves = 0usize;
  1194. let full_moves = g.full_moves + g.color_to_move;
  1195.  
  1196. game_state::GameState {
  1197. color_to_move,
  1198. pieces,
  1199. castle_white_kingside,
  1200. castle_white_queenside,
  1201. castle_black_kingside,
  1202. castle_black_queenside,
  1203. en_passant,
  1204. half_moves,
  1205. full_moves,
  1206. }
  1207. }
  1208.  
  1209. pub fn make_castle_move(g: &game_state::GameState, mv: &game_state::GameMove) -> game_state::GameState {
  1210. let color_to_move = 1 - g.color_to_move;
  1211. let mut pieces = g.pieces.clone();
  1212. //Move the king
  1213. move_piece(&mut pieces, &mv, g.color_to_move);
  1214.  
  1215. //Move the rook
  1216. //Determine if its kingside or queenside castle
  1217. //Kingside
  1218. if mv.to == 58 {
  1219. pieces[3][1] ^= bitboards::SQUARES[56];
  1220. pieces[3][1] |= bitboards::SQUARES[59];
  1221. } else if mv.to == 2 {
  1222. pieces[3][0] ^= bitboards::SQUARES[0];
  1223. pieces[3][0] |= bitboards::SQUARES[3];
  1224. } else if mv.to == 62 {//Queenside
  1225. pieces[3][1] ^= bitboards::SQUARES[63];
  1226. pieces[3][1] |= bitboards::SQUARES[61];
  1227. } else if mv.to == 6 {
  1228. pieces[3][0] ^= bitboards::SQUARES[7];
  1229. pieces[3][0] |= bitboards::SQUARES[5];
  1230. }
  1231.  
  1232. let (castle_white_kingside, castle_white_queenside) = if g.color_to_move == 0 { (false, false) } else {
  1233. (g.castle_white_kingside, g.castle_white_queenside)
  1234. };
  1235. let (castle_black_kingside, castle_black_queenside) = if g.color_to_move == 1 { (false, false) } else {
  1236. (g.castle_black_kingside, g.castle_black_queenside)
  1237. };
  1238.  
  1239. let en_passant = 0u64;
  1240.  
  1241. let half_moves = g.half_moves + 1;
  1242. let full_moves = g.full_moves + g.color_to_move;
  1243.  
  1244. game_state::GameState {
  1245. color_to_move,
  1246. pieces,
  1247. castle_white_kingside,
  1248. castle_white_queenside,
  1249. castle_black_kingside,
  1250. castle_black_queenside,
  1251. en_passant,
  1252. half_moves,
  1253. full_moves,
  1254. }
  1255. }
  1256.  
  1257. pub fn make_promotion_move(g: &game_state::GameState, mv: &game_state::GameMove) -> game_state::GameState {
  1258. let color_to_move = 1 - g.color_to_move;
  1259. let mut pieces = g.pieces.clone();
  1260. //Make the move
  1261. move_piece(&mut pieces, &mv, g.color_to_move);
  1262. //Delete enemy piece if any on there
  1263. delete_piece(&mut pieces, mv.to, color_to_move);
  1264. //Delete my pawn
  1265. pieces[0][g.color_to_move] ^= bitboards::SQUARES[mv.to];
  1266. //Add piece respectivly
  1267. pieces[match mv.move_type {
  1268. GameMoveType::Promotion(PieceType::Queen) => { 4 }
  1269. GameMoveType::Promotion(PieceType::Knight) => { 1 }
  1270. GameMoveType::Promotion(PieceType::Bishop) => { 2 }
  1271. GameMoveType::Promotion(PieceType::Rook) => { 3 }
  1272. _ => panic!("Invalid Type")
  1273. }][g.color_to_move] |= bitboards::SQUARES[mv.to];
  1274.  
  1275. let mut castle_white_kingside = g.castle_white_kingside;
  1276. let mut castle_white_queenside = g.castle_white_queenside;
  1277. let mut castle_black_kingside = g.castle_black_kingside;
  1278. let mut castle_black_queenside = g.castle_black_queenside;
  1279.  
  1280. if g.color_to_move == 0 {
  1281. //Check that blacks rook didn't get captured
  1282. if pieces[3][1] & bitboards::SQUARES[56] == 0 {
  1283. castle_black_queenside = false;
  1284. }
  1285. if pieces[3][1] & bitboards::SQUARES[63] == 0 {
  1286. castle_black_kingside = false;
  1287. }
  1288. } else {
  1289. if pieces[3][0] & bitboards::SQUARES[0] == 0 {
  1290. castle_white_queenside = false;
  1291. }
  1292. if pieces[3][0] & bitboards::SQUARES[7] == 0 {
  1293. castle_white_kingside = false;
  1294. }
  1295. }
  1296.  
  1297. let en_passant = 0u64;
  1298.  
  1299. let half_moves = 0usize;
  1300. let full_moves = g.full_moves + g.color_to_move;
  1301.  
  1302. game_state::GameState {
  1303. color_to_move,
  1304. pieces,
  1305. castle_white_kingside,
  1306. castle_white_queenside,
  1307. castle_black_kingside,
  1308. castle_black_queenside,
  1309. en_passant,
  1310. half_moves,
  1311. full_moves,
  1312. }
  1313. }
  1314.  
  1315. pub fn generate_moves(g: &game_state::GameState) -> (Vec<GameMove>, bool) {
  1316. //Following this guide:
  1317. // https://peterellisjones.com/posts/generating-legal-chess-moves-efficiently/
  1318.  
  1319. let mut move_list: Vec<GameMove> = Vec::with_capacity(60);
  1320. let color_to_move = g.color_to_move;
  1321. let enemy_color = 1 - color_to_move;
  1322.  
  1323. //Get my pieces
  1324. let my_king = g.pieces[5][color_to_move];
  1325. let my_king_idx = my_king.trailing_zeros() as usize;
  1326.  
  1327. let mut my_pawns = g.pieces[0][color_to_move];
  1328.  
  1329. let mut my_knights = g.pieces[1][color_to_move];
  1330.  
  1331. let mut my_bishops = g.pieces[2][color_to_move] | g.pieces[4][color_to_move];
  1332.  
  1333. let mut my_rooks = g.pieces[3][color_to_move] | g.pieces[4][color_to_move];
  1334. //Need this to xor out queens later, when we look at pinned pieces
  1335. let my_queens = g.pieces[4][color_to_move];
  1336.  
  1337. //Get enemy pieces
  1338. let enemy_king = g.pieces[5][enemy_color];
  1339. let enemy_king_idx = enemy_king.trailing_zeros() as usize;
  1340.  
  1341. let enemy_pawns = g.pieces[0][enemy_color];
  1342.  
  1343. let enemy_knights = g.pieces[1][enemy_color];
  1344.  
  1345. let enemy_bishops = g.pieces[2][enemy_color] | g.pieces[4][enemy_color];
  1346.  
  1347. let enemy_rooks = g.pieces[3][enemy_color] | g.pieces[4][enemy_color];
  1348.  
  1349. let my_pieces = my_king | my_pawns | my_knights | my_bishops | my_rooks;
  1350. let not_my_pieces = !my_pieces;
  1351. let enemy_sliders = enemy_bishops | enemy_rooks;
  1352. let enemy_pieces = enemy_pawns | enemy_knights | enemy_sliders | enemy_king;
  1353. let not_enemy_pieces = !enemy_pieces;
  1354. let all_pieces_without_my_king = enemy_pieces | (my_pieces & !my_king);
  1355. let all_pieces = all_pieces_without_my_king | my_king;
  1356. let empty = !all_pieces;
  1357.  
  1358. let unsafe_white_squares = if color_to_move == 0 {
  1359. get_b_attacked_squares(enemy_king_idx, enemy_pawns, enemy_knights, enemy_bishops, enemy_rooks
  1360. , all_pieces_without_my_king)
  1361. } else {
  1362. get_w_attacked_squares(enemy_king_idx, enemy_pawns, enemy_knights, enemy_bishops, enemy_rooks
  1363. , all_pieces_without_my_king)
  1364. };
  1365. let possible_king_moves = king_attack(my_king_idx) & !unsafe_white_squares & not_my_pieces;
  1366. add_moves(&mut move_list, my_king_idx, possible_king_moves & not_enemy_pieces, &PieceType::King, GameMoveType::Quiet);
  1367. add_moves(&mut move_list, my_king_idx, possible_king_moves & enemy_pieces, &PieceType::King, GameMoveType::Capture);
  1368. let (king_attackers_board, checking_piece_is_slider, checking_piece_slider_is_bishop) = if unsafe_white_squares & my_king == 0 {
  1369. (0u64, false, false)
  1370. } else {
  1371. if color_to_move == 0 {
  1372. attackers_from_black(my_king, my_king_idx, enemy_pawns, enemy_knights
  1373. , enemy_bishops, enemy_rooks, all_pieces)
  1374. } else {
  1375. attackers_from_white(my_king, my_king_idx, enemy_pawns, enemy_knights
  1376. , enemy_bishops, enemy_rooks, all_pieces)
  1377. }
  1378. };
  1379.  
  1380. let num_checkers = king_attackers_board.count_ones();
  1381. //Double check
  1382. if num_checkers > 1 { //Then only king moves are possible anyway
  1383. return (move_list, true);
  1384. }
  1385. //Calculate capture and push mask
  1386. let mut capture_mask = 0xFFFFFFFFFFFFFFFFu64;
  1387. let mut push_mask = 0xFFFFFFFFFFFFFFFFu64;
  1388. //Single-Check
  1389. {
  1390. if num_checkers == 1 {
  1391. capture_mask = king_attackers_board;
  1392. if checking_piece_is_slider {
  1393. let checking_piece_square = king_attackers_board.trailing_zeros() as usize;
  1394. if checking_piece_slider_is_bishop {
  1395. push_mask = get_bishop_ray(bishop_attack(checking_piece_square, 0u64), my_king_idx, checking_piece_square);
  1396. } else {
  1397. push_mask = get_rook_ray(rook_attack(checking_piece_square, 0u64), my_king_idx, checking_piece_square);
  1398. }
  1399. } else {
  1400. push_mask = 0u64;
  1401. }
  1402. }
  1403. }
  1404.  
  1405. //Pinned pieces
  1406. {//Pinned by rook
  1407. let rook_attacks_from_my_king_postion = rook_attack(my_king_idx, all_pieces);
  1408. //See one layer through my pieces
  1409. //If a rook is found seeing through one piece, the piece is pinned
  1410. let xray_rooks = xray_rook_attacks(rook_attacks_from_my_king_postion, all_pieces, my_pieces, my_king_idx);
  1411. //Go through all directions
  1412. //Find the rooks with xray
  1413. let mut rooks_on_xray = xray_rooks & enemy_rooks;
  1414. while rooks_on_xray != 0 {
  1415. let rook_position = rooks_on_xray.trailing_zeros() as usize;
  1416. rooks_on_xray &= rooks_on_xray - 1;
  1417. let ray = get_rook_ray(rook_attacks_from_my_king_postion | xray_rooks, rook_position, my_king_idx);
  1418. let pinned_piece = ray & my_pieces;
  1419. let pinned_piece_position = pinned_piece.trailing_zeros() as usize;
  1420. if pinned_piece & my_rooks != 0 {
  1421. let mut piece_type = PieceType::Rook;
  1422. if pinned_piece & my_queens != 0 {
  1423. my_bishops ^= pinned_piece;
  1424. piece_type = PieceType::Queen;
  1425. }
  1426. my_rooks ^= pinned_piece;
  1427. add_moves(&mut move_list, pinned_piece_position, ray & !pinned_piece & push_mask, &piece_type, GameMoveType::Quiet);
  1428. //Don't forget that we can capture the rook aswell
  1429. add_moves(&mut move_list, pinned_piece_position, bitboards::SQUARES[rook_position] & capture_mask, &piece_type, GameMoveType::Capture);
  1430. continue;
  1431. }
  1432. if pinned_piece & my_pawns != 0 {
  1433. my_pawns ^= pinned_piece;
  1434. let pawn_push_once = if color_to_move == 0 { w_single_push_pawn_targets(pinned_piece, empty) } else { b_single_push_pawn_targets(pinned_piece, empty) } & ray;
  1435. let pawn_push_twice = if color_to_move == 0 { w_double_push_pawn_targets(pinned_piece, empty) } else { b_double_push_pawn_targets(pinned_piece, empty) } & ray;
  1436. add_moves(&mut move_list, pinned_piece_position, (pawn_push_once | pawn_push_twice) & push_mask, &PieceType::Pawn, GameMoveType::Quiet);
  1437. continue;
  1438. }
  1439. if pinned_piece & my_knights != 0 {
  1440. my_knights ^= pinned_piece;
  1441. continue;
  1442. }
  1443. if pinned_piece & my_bishops != 0 {
  1444. my_bishops ^= pinned_piece;
  1445. }
  1446. }
  1447. //Pinned by bishop
  1448. let bishop_attacks_from_my_king_position = bishop_attack(my_king_idx, all_pieces);
  1449. let xray_bishops = xray_bishop_attacks(bishop_attacks_from_my_king_position, all_pieces, my_pieces, my_king_idx);
  1450. let mut bishops_on_xray = xray_bishops & enemy_bishops;
  1451. while bishops_on_xray != 0 {
  1452. let bishop_position = bishops_on_xray.trailing_zeros() as usize;
  1453. bishops_on_xray &= bishops_on_xray - 1;
  1454. let ray = get_bishop_ray(bishop_attacks_from_my_king_position | xray_bishops, bishop_position, my_king_idx);
  1455. let pinned_piece = ray & my_pieces;
  1456. let pinned_piece_position = pinned_piece.trailing_zeros() as usize;
  1457. if pinned_piece & my_bishops != 0 {
  1458. let mut piece_type = PieceType::Bishop;
  1459. if pinned_piece & my_queens != 0 {
  1460. my_rooks ^= pinned_piece;
  1461. piece_type = PieceType::Queen;
  1462. }
  1463. my_bishops ^= pinned_piece;
  1464.  
  1465. add_moves(&mut move_list, pinned_piece_position, ray & !pinned_piece & push_mask, &piece_type, GameMoveType::Quiet);
  1466. add_moves(&mut move_list, pinned_piece_position, bitboards::SQUARES[bishop_position] & capture_mask, &piece_type, GameMoveType::Capture);
  1467. continue;
  1468. }
  1469. if pinned_piece & my_pawns != 0 {
  1470. my_pawns ^= pinned_piece;
  1471. let pawn_targets = if color_to_move == 0 { w_pawn_east_targets(pinned_piece) } else { b_pawn_east_targets(pinned_piece) } | if color_to_move == 0 { w_pawn_west_targets(pinned_piece) } else { b_pawn_west_targets(pinned_piece) };
  1472. let pawn_captures = pawn_targets & bitboards::SQUARES[bishop_position] & capture_mask;
  1473. //let pawn_enpassants = pawn_targets & g.en_passant;
  1474. add_moves(&mut move_list, pinned_piece_position, pawn_captures, &PieceType::Pawn, GameMoveType::Capture);
  1475. //add_moves(&mut move_list, pinned_piece_position, pawn_enpassants, &PieceType::Pawn, GameMoveType::EnPassant);
  1476. continue;
  1477. }
  1478. if pinned_piece & my_knights != 0 {
  1479. my_knights ^= pinned_piece;
  1480. continue;
  1481. }
  1482. if pinned_piece & my_rooks != 0 {
  1483. my_rooks ^= pinned_piece;
  1484. }
  1485. }
  1486. }
  1487. //Calculate normal moves
  1488. //Pawns
  1489. {
  1490. //Single push
  1491. {
  1492. let my_pawns_single_push = if color_to_move == 0 { w_single_push_pawn_targets(my_pawns, empty) } else { b_single_push_pawn_targets(my_pawns, empty) } & push_mask;
  1493. let my_pawns_no_promotion = my_pawns_single_push & !bitboards::RANKS[if color_to_move == 0 { 7 } else { 0 }];
  1494. let my_pawns_promotion = my_pawns_single_push & bitboards::RANKS[if color_to_move == 0 { 7 } else { 0 }];
  1495. add_quiet_pawn_single_pushes(my_pawns_no_promotion, &color_to_move, &mut move_list);
  1496. add_promotion_push(my_pawns_promotion, &color_to_move, &mut move_list, 8usize);
  1497. }
  1498. //Double push
  1499. {
  1500. let my_pawns_double_push = if color_to_move == 0 { w_double_push_pawn_targets(my_pawns, empty) } else { b_double_push_pawn_targets(my_pawns, empty) } & push_mask;
  1501. add_quiet_pawn_double_pushes(my_pawns_double_push, &color_to_move, &mut move_list);
  1502. }
  1503. //Capture west
  1504. {
  1505. let my_pawns_west_targets = if color_to_move == 0 { w_pawn_west_targets(my_pawns) } else { b_pawn_west_targets(my_pawns) };
  1506. let my_pawns_west_normal_captures = my_pawns_west_targets & capture_mask & enemy_pieces;
  1507. //Checking for promotion on capture
  1508. let my_pawns_no_promotion = my_pawns_west_normal_captures & !bitboards::RANKS[if color_to_move == 0 { 7 } else { 0 }];
  1509. let my_pawns_promotion = my_pawns_west_normal_captures & bitboards::RANKS[if color_to_move == 0 { 7 } else { 0 }];
  1510. //Capture
  1511. add_pawn_capture(my_pawns_no_promotion, &color_to_move, &mut move_list, 7usize);
  1512. //Promotion capture
  1513. add_promotion_push(my_pawns_promotion, &color_to_move, &mut move_list, 7usize);
  1514.  
  1515.  
  1516. //En passant
  1517. //We can capture en passant, if its in capture mask aswell
  1518. let my_pawns_west_enpassants = my_pawns_west_targets & g.en_passant & if color_to_move == 0 { capture_mask << 8 } else { capture_mask >> 8 };
  1519. add_en_passants(my_pawns_west_enpassants, &color_to_move, &mut move_list, 7usize, all_pieces_without_my_king, enemy_rooks, my_king_idx);
  1520. }
  1521. //Capture east
  1522. {
  1523. let my_pawns_east_targets = if color_to_move == 0 { w_pawn_east_targets(my_pawns) } else { b_pawn_east_targets(my_pawns) };
  1524. let my_pawns_east_normal_captures = my_pawns_east_targets & capture_mask & enemy_pieces;
  1525. //Checking for promotion on capture
  1526. let my_pawns_no_promotion = my_pawns_east_normal_captures & !bitboards::RANKS[if color_to_move == 0 { 7 } else { 0 }];
  1527. let my_pawns_promotion = my_pawns_east_normal_captures & bitboards::RANKS[if color_to_move == 0 { 7 } else { 0 }];
  1528.  
  1529. add_pawn_capture(my_pawns_no_promotion, &color_to_move, &mut move_list, 9usize);
  1530. add_promotion_push(my_pawns_promotion, &color_to_move, &mut move_list, 9usize);
  1531. //En passants
  1532. let my_pawns_east_enpassants = my_pawns_east_targets & g.en_passant & if color_to_move == 0 { capture_mask << 8 } else { capture_mask >> 8 };
  1533. add_en_passants(my_pawns_east_enpassants, &color_to_move, &mut move_list, 9usize, all_pieces_without_my_king, enemy_rooks, my_king_idx);
  1534. }
  1535. }
  1536. //Knights
  1537. {
  1538. while my_knights != 0u64 {
  1539. let index = if color_to_move == 0 { 63usize - my_knights.leading_zeros() as usize } else { my_knights.trailing_zeros() as usize };
  1540. let my_knight_attacks = knight_attack(index) & not_my_pieces;
  1541. let my_knight_captures = my_knight_attacks & enemy_pieces & capture_mask;
  1542. add_moves(&mut move_list, index, my_knight_captures, &PieceType::Knight, GameMoveType::Capture);
  1543. let my_knight_quiets = my_knight_attacks & !enemy_pieces & push_mask;
  1544. add_moves(&mut move_list, index, my_knight_quiets, &PieceType::Knight, GameMoveType::Quiet);
  1545. my_knights ^= 1u64 << index;
  1546. }
  1547. }
  1548. //Bishops
  1549. {
  1550. while my_bishops != 0u64 {
  1551. let index = if color_to_move == 0 { 63usize - my_bishops.leading_zeros() as usize } else { my_bishops.trailing_zeros() as usize };
  1552. let my_bishop_attack = bishop_attack(index, all_pieces) & not_my_pieces;
  1553. let my_bishop_capture = my_bishop_attack & enemy_pieces & capture_mask;
  1554. let piece_type = if bitboards::SQUARES[index] & my_queens != 0 { PieceType::Queen } else { PieceType::Bishop };
  1555. add_moves(&mut move_list, index, my_bishop_capture, &piece_type, GameMoveType::Capture);
  1556. let my_bishop_quiet = my_bishop_attack & !enemy_pieces & push_mask;
  1557. add_moves(&mut move_list, index, my_bishop_quiet, &piece_type, GameMoveType::Quiet);
  1558. my_bishops ^= 1u64 << index;
  1559. }
  1560. }
  1561. //Rooks
  1562. {
  1563. while my_rooks != 0u64 {
  1564. let index = if color_to_move == 0 { 63usize - my_rooks.leading_zeros() as usize } else { my_rooks.trailing_zeros() as usize };
  1565. let my_rook_attack = rook_attack(index, all_pieces) & not_my_pieces;
  1566. let my_rook_capture = my_rook_attack & enemy_pieces & capture_mask;
  1567. let piece_type = if bitboards::SQUARES[index] & my_queens != 0 { PieceType::Queen } else { PieceType::Rook };
  1568. add_moves(&mut move_list, index, my_rook_capture, &piece_type, GameMoveType::Capture);
  1569. let my_rook_quiets = my_rook_attack & !enemy_pieces & push_mask;
  1570. add_moves(&mut move_list, index, my_rook_quiets, &piece_type, GameMoveType::Quiet);
  1571. my_rooks ^= 1u64 << index;
  1572. }
  1573. }
  1574. //Castles
  1575. if num_checkers == 0 {
  1576. if g.color_to_move == 0 {
  1577. //Make sure there is no piece in between and safe squares
  1578. if g.castle_white_kingside {
  1579. if (all_pieces | unsafe_white_squares) & (bitboards::SQUARES[5] | bitboards::SQUARES[6]) == 0 {
  1580. move_list.push(GameMove {
  1581. from: my_king_idx,
  1582. to: 6usize,
  1583. move_type: GameMoveType::Castle,
  1584. piece_type: PieceType::King,
  1585. });
  1586. }
  1587. }
  1588. if g.castle_white_queenside {
  1589. if ((all_pieces | unsafe_white_squares) & (bitboards::SQUARES[2] | bitboards::SQUARES[3]) | all_pieces & bitboards::SQUARES[1]) == 0 {
  1590. move_list.push(GameMove {
  1591. from: my_king_idx,
  1592. to: 2usize,
  1593. move_type: GameMoveType::Castle,
  1594. piece_type: PieceType::King,
  1595. });
  1596. }
  1597. }
  1598. } else {
  1599. if g.castle_black_kingside {
  1600. if (all_pieces | unsafe_white_squares) & (bitboards::SQUARES[61] | bitboards::SQUARES[62]) == 0 {
  1601. move_list.push(GameMove {
  1602. from: my_king_idx,
  1603. to: 62usize,
  1604. move_type: GameMoveType::Castle,
  1605. piece_type: PieceType::King,
  1606. });
  1607. }
  1608. }
  1609. if g.castle_black_queenside {
  1610. if ((all_pieces | unsafe_white_squares) & (bitboards::SQUARES[58] | bitboards::SQUARES[59]) | all_pieces & bitboards::SQUARES[57]) == 0 {
  1611. move_list.push(GameMove {
  1612. from: my_king_idx,
  1613. to: 58usize,
  1614. move_type: GameMoveType::Castle,
  1615. piece_type: PieceType::King,
  1616. });
  1617. }
  1618. }
  1619. }
  1620. }
  1621. (move_list, num_checkers > 0)
  1622. }
  1623.  
  1624. pub fn xray_rook_attacks(attacks: u64, occupied_square: u64, one_time_blockers: u64, rook_square: usize) -> u64 {
  1625. return attacks ^ rook_attack(rook_square, occupied_square ^ (one_time_blockers & attacks));
  1626. }
  1627.  
  1628. pub fn xray_bishop_attacks(attacks: u64, occupied_square: u64, one_time_blockers: u64, bishop_square: usize) -> u64 {
  1629. return attacks ^ bishop_attack(bishop_square, occupied_square ^ (one_time_blockers & attacks));
  1630. }
  1631.  
  1632. //Gets the ray of one rook into a specific direction
  1633. pub fn get_rook_ray(rook_attacks_in_all_directions: u64, target_square: usize, rook_square: usize) -> u64 {
  1634. let diff = target_square as isize - rook_square as isize;
  1635. let target_rank = target_square / 8;
  1636. let target_file = target_square % 8;
  1637. let rook_rank = rook_square / 8;
  1638. let rook_file = rook_square % 8;
  1639. if diff > 0 {
  1640. //Same vertical
  1641. if target_rank == rook_rank {
  1642. return bitboards::FILES_LESS_THAN[target_file] & bitboards::FILES_GREATER_THAN[rook_file] & rook_attacks_in_all_directions;
  1643. } else {
  1644. return bitboards::RANKS_LESS_THAN[target_rank] & bitboards::RANKS_GREATER_THAN[rook_rank] & rook_attacks_in_all_directions;
  1645. }
  1646. } else {
  1647. if target_rank == rook_rank {
  1648. return bitboards::FILES_GREATER_THAN[target_file] & bitboards::FILES_LESS_THAN[rook_file] & rook_attacks_in_all_directions;
  1649. } else {
  1650. return bitboards::RANKS_GREATER_THAN[target_rank] & bitboards::RANKS_LESS_THAN[rook_rank] & rook_attacks_in_all_directions;
  1651. }
  1652. }
  1653. }
  1654.  
  1655. //Gets the rof of one bishop into a specific direction
  1656. pub fn get_bishop_ray(bishop_attack_in_all_directions: u64, target_square: usize, bishop_square: usize) -> u64 {
  1657. let diff = target_square as isize - bishop_square as isize;
  1658. let target_rank = target_square / 8;
  1659. let target_file = target_square % 8;
  1660. let bishop_rank = bishop_square / 8;
  1661. let bishop_file = bishop_square % 8;
  1662. if diff > 0 {
  1663. if diff % 7 == 0 {
  1664. return bitboards::FILES_GREATER_THAN[target_file] & bitboards::FILES_LESS_THAN[bishop_file]
  1665. & bitboards::RANKS_LESS_THAN[target_rank] & bitboards::RANKS_GREATER_THAN[bishop_rank]
  1666. & bishop_attack_in_all_directions;
  1667. } else {
  1668. return bitboards::FILES_LESS_THAN[target_file] & bitboards::FILES_GREATER_THAN[bishop_file]
  1669. & bitboards::RANKS_LESS_THAN[target_rank] & bitboards::RANKS_GREATER_THAN[bishop_rank]
  1670. & bishop_attack_in_all_directions;
  1671. }
  1672. } else {
  1673. if diff % -7 == 0 {
  1674. return bitboards::FILES_LESS_THAN[target_file] & bitboards::FILES_GREATER_THAN[bishop_file]
  1675. & bitboards::RANKS_GREATER_THAN[target_rank] & bitboards::RANKS_LESS_THAN[bishop_rank]
  1676. & bishop_attack_in_all_directions;
  1677. } else {
  1678. return bitboards::FILES_GREATER_THAN[target_file] & bitboards::FILES_LESS_THAN[bishop_file]
  1679. & bitboards::RANKS_GREATER_THAN[target_rank] & bitboards::RANKS_LESS_THAN[bishop_rank]
  1680. & bishop_attack_in_all_directions;
  1681. }
  1682. }
  1683. }
  1684.  
  1685. pub fn attackers_from_white(square_board: u64, square: usize, white_pawns: u64, white_knights: u64, white_bishops: u64, white_rooks: u64, blockers: u64) -> (u64, bool, bool) {
  1686. let mut attackers = 0u64;
  1687. let mut slider_flag = false;
  1688. let mut bishop_slider = false;
  1689. attackers |= knight_attack(square) & white_knights;
Add Comment
Please, Sign In to add comment