build.rs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. use std::{io::{Write}, fs::File};
  2. extern crate rand;
  3. use rand::*;
  4. fn main() {
  5. println!("cargo:rerun-if-changed=build.rs");
  6. let mut file = std::fs::File::create("src/magic/tables.rs").unwrap();
  7. create_tables(&mut file);
  8. }
  9. type Bitboard = u64;
  10. type Square = u8;
  11. pub const FILE_A: Bitboard = 0x_8080_8080_8080_8080;
  12. pub const FILE_B: Bitboard = FILE_A >> 1;
  13. pub const FILE_C: Bitboard = FILE_A >> 2;
  14. pub const FILE_D: Bitboard = FILE_A >> 3;
  15. pub const FILE_E: Bitboard = FILE_A >> 4;
  16. pub const FILE_F: Bitboard = FILE_A >> 5;
  17. pub const FILE_G: Bitboard = FILE_A >> 6;
  18. pub const FILE_H: Bitboard = FILE_A >> 7;
  19. pub const ROW_1: Bitboard = 0x_0000_0000_0000_00FF;
  20. pub const ROW_2: Bitboard = 0x_0000_0000_0000_FF00;
  21. pub const ROW_3: Bitboard = 0x_0000_0000_00FF_0000;
  22. pub const ROW_4: Bitboard = 0x_0000_0000_FF00_0000;
  23. pub const ROW_5: Bitboard = 0x_0000_00FF_0000_0000;
  24. pub const ROW_6: Bitboard = 0x_0000_FF00_0000_0000;
  25. pub const ROW_7: Bitboard = 0x_00FF_0000_0000_0000;
  26. pub const ROW_8: Bitboard = 0x_FF00_0000_0000_0000;
  27. pub fn print_board(b: Bitboard) -> String {
  28. (0..8).map(
  29. |i| (0..8).map(
  30. |j| if bit_at(b, i, j) { "x " }
  31. else { ". " }
  32. ).collect::<String>() + "\n"
  33. ).collect::<String>()
  34. }
  35. pub fn bit_at(b: Bitboard, i: i32, j: i32) -> bool {
  36. ((b >> (7 - i) * 8 + 7 - j) & 1) == 1
  37. }
  38. pub fn from_square(s: Square) -> Bitboard {
  39. return 1_u64 << s;
  40. }
  41. pub fn north_one(b: Bitboard) -> Bitboard {
  42. b << 8
  43. }
  44. pub fn south_one(b: Bitboard) -> Bitboard {
  45. b >> 8
  46. }
  47. pub fn west_one(b: Bitboard) -> Bitboard {
  48. (b << 1) & !FILE_H
  49. }
  50. pub fn east_one(b: Bitboard) -> Bitboard {
  51. (b >> 1) & !FILE_A
  52. }
  53. pub fn northeast_one(b: Bitboard) -> Bitboard {
  54. (b << 7) & !FILE_A
  55. }
  56. pub fn northwest_one(b: Bitboard) -> Bitboard {
  57. (b << 9) & !FILE_H
  58. }
  59. pub fn southwest_one(b: Bitboard) -> Bitboard {
  60. (b >> 7) & !FILE_H
  61. }
  62. pub fn southeast_one(b: Bitboard) -> Bitboard {
  63. (b >> 9) & !FILE_A
  64. }
  65. pub fn generate_sliding_destinations(occupied: Bitboard,
  66. piece: Bitboard, straight: bool,
  67. diagonal: bool,
  68. only_occ: bool) -> Bitboard {
  69. let straights = [north_one, south_one, east_one, west_one];
  70. let diagonals = [northeast_one, southeast_one, northwest_one, southwest_one];
  71. let mut result: Bitboard = 0;
  72. if straight {
  73. for direction in straights.iter() {
  74. result |= generate_direction(piece, *direction, occupied, only_occ);
  75. }
  76. }
  77. if diagonal {
  78. for direction in diagonals.iter() {
  79. result |= generate_direction(piece, *direction, occupied, only_occ);
  80. }
  81. }
  82. return result;
  83. }
  84. fn generate_direction(piece: Bitboard, direction: fn(Bitboard) -> Bitboard, occupied: Bitboard, only_occ: bool) -> Bitboard {
  85. let mut result: Bitboard = 0;
  86. let mut b = piece;
  87. loop {
  88. b = direction(b);
  89. if only_occ && direction(b) == 0 {
  90. break;
  91. }
  92. result |= b;
  93. if b & occupied != 0 || b == 0 {
  94. break;
  95. }
  96. }
  97. return result;
  98. }
  99. fn extract(mut mask: Bitboard, index: u32) -> Bitboard {
  100. let required_bits = mask.count_ones();
  101. let mut result: Bitboard = 0;
  102. for bit in 0..required_bits {
  103. let idx = mask.trailing_zeros();
  104. if (1 << bit) & index != 0 {
  105. result |= 1 << idx;
  106. }
  107. mask = mask & !(1 << idx);
  108. }
  109. return result;
  110. }
  111. pub fn low_one_random() -> u64 {
  112. let mut rng = rand::thread_rng();
  113. rng.next_u64() & rng.next_u64() & rng.next_u64()
  114. }
  115. fn create_magic_slider(s: Square, diagonal: bool) -> Option<(u64, u64, Vec<Bitboard>)> {
  116. let bitboard = from_square(s);
  117. let patt = generate_sliding_destinations(0, bitboard, !diagonal, diagonal, true);
  118. if !diagonal {
  119. println!("{}", print_board(bitboard));
  120. println!("{}\n\n", print_board(patt));
  121. //panic!("asas");
  122. }
  123. let required_bits = patt.count_ones();
  124. let mut correct_results: [Bitboard; 4096] = [!0_u64; 4096];
  125. for i in 0..4096_usize {
  126. let b = extract(patt, i as _);
  127. correct_results[i] = generate_sliding_destinations(b, bitboard, !diagonal, diagonal, false);
  128. }
  129. for _ in 0..10000000 {
  130. let mut table: [Bitboard; 4096] = [0; 4096];
  131. let magic = low_one_random();
  132. let mut failed = false;
  133. if magic.wrapping_mul(patt).wrapping_shr(48).count_ones() < 6 {
  134. continue;
  135. }
  136. for i in 0..(1 << required_bits) {
  137. let b = extract(patt, i as _);
  138. let correct_result =
  139. if correct_results[i] != !0_u64 {
  140. correct_results[i]
  141. }
  142. else {
  143. correct_results[i] = generate_sliding_destinations(b, bitboard, !diagonal, diagonal, false);
  144. correct_results[i]
  145. };
  146. let index = magic.wrapping_mul(b).wrapping_shr(64 - required_bits) as usize;
  147. if index >= 4096 {
  148. println!("{}", print_board(patt));
  149. panic!("asas");
  150. }
  151. if table[index] == 0 {
  152. table[index] = correct_result;
  153. }
  154. else if table[index] != correct_result {
  155. failed = true;
  156. break;
  157. }
  158. //println!("{}", print_board(b));
  159. }
  160. if !failed {
  161. return Some((patt, magic, table.to_vec()));
  162. }
  163. }
  164. println!("OH NOO\n{}", print_board(patt));
  165. return None;
  166. }
  167. fn create_tables(file: &mut File) {
  168. writeln!(file, "use crate::bitboard::*;").unwrap();
  169. create(file, false, "ROOK");
  170. create(file, true, "BISHOP");
  171. }
  172. fn create(file: &mut File, diagonal: bool, prefix: &str) {
  173. let mut masks: Vec<u64> = Vec::new();
  174. let mut magics: Vec<u64> = Vec::new();
  175. let mut tables: Vec<Vec<u64>> = Vec::new();
  176. // bishops:
  177. for square in 0..64 {
  178. let res = create_magic_slider(square, diagonal);
  179. if let Some((mask, magic, table)) = res {
  180. masks.push(mask);
  181. magics.push(magic);
  182. tables.push(table);
  183. }
  184. else {
  185. panic!("NO");
  186. }
  187. }
  188. write!(file, "pub const {}_MASKS_AND_MAGICS: [(Bitboard, Bitboard); 64] = [", prefix).unwrap();
  189. for square in 0..64 {
  190. write!(file, "({}, {}), ", masks[square], magics[square]).unwrap();
  191. }
  192. writeln!(file, "];").unwrap();
  193. write!(file, "pub const {}_BITS: [u8; 64] = [", prefix).unwrap();
  194. for square in 0..64 {
  195. write!(file, "{}, ", masks[square].count_ones()).unwrap();
  196. }
  197. writeln!(file, "];").unwrap();
  198. let max_tablesize = 1_usize << masks.iter().map(|x| x.count_ones()).max().unwrap_or(12);
  199. write!(file, "pub const {}_TABLES: [[Bitboard; {}]; 64] = [", prefix, max_tablesize).unwrap();
  200. for square in 0..64 {
  201. write!(file, "[").unwrap();
  202. //for result in &tables[square] {
  203. for i in 0..max_tablesize {
  204. write!(file, "{}, ", tables[square][i]).unwrap();
  205. }
  206. writeln!(file, "], ").unwrap();
  207. }
  208. writeln!(file, "];").unwrap();
  209. //panic!("asas");
  210. }