movegen.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. use bitboard::Bitboard;
  2. use bitboard::Square;
  3. use bitboard::*;
  4. use game::Game;
  5. use log::info;
  6. pub type Side = bool;
  7. pub const WHITE: Side = false;
  8. pub const BLACK: Side = true;
  9. pub type PieceType = u8;
  10. pub const NO_PIECE: PieceType = 255;
  11. pub const PAWN: PieceType = 0;
  12. pub const KNIGHT: PieceType = 1;
  13. pub const BISHOP: PieceType = 2;
  14. pub const ROOK: PieceType = 3;
  15. pub const QUEEN: PieceType = 4;
  16. pub const KING: PieceType = 5;
  17. #[derive(Copy, Clone, Debug, PartialEq, Eq)]
  18. pub struct SimpleMove {
  19. pub from: Square,
  20. pub to: Square,
  21. }
  22. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  23. pub enum Move {
  24. Default { mov: SimpleMove, piece_type: PieceType },
  25. Castling { side: Side, left: bool },
  26. EnPassant { mov: SimpleMove, beaten: Square },
  27. Promotion { mov: SimpleMove, promote_to: PieceType },
  28. }
  29. impl Default for Move {
  30. fn default() -> Move {
  31. Move::Default{ mov: SimpleMove { from: 0, to: 0 }, piece_type: NO_PIECE }
  32. }
  33. }
  34. impl Move {
  35. pub fn parse_square(sq: &str) -> Option<Square> {
  36. let col = sq.chars().nth(0)?;
  37. let row = sq.chars().nth(1)?;
  38. Some((row as u8 - '1' as u8) * 8 + 7 - (col as u8 - 'a' as u8))
  39. }
  40. pub fn square_to_string(sq: Square) -> String {
  41. let col = 7 - (sq % 8);
  42. let row = sq / 8;
  43. let colchar = (('a' as u8) + col) as char;
  44. let rowchar = (('1' as u8) + row) as char;
  45. let chars = [colchar, rowchar];
  46. //println!("{} {}", col, row);
  47. chars.iter().collect()
  48. }
  49. pub fn to_string(&self) -> String {
  50. match self {
  51. Move::Default{ mov, piece_type } => {
  52. Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
  53. },
  54. Move::Castling{ side, left } => {
  55. match (side, left) {
  56. (&WHITE, false) => {
  57. Self::square_to_string(3) + &Self::square_to_string(1)
  58. },
  59. (&WHITE, true) => {
  60. Self::square_to_string(3) + &Self::square_to_string(5)
  61. },
  62. (&BLACK, false) => {
  63. Self::square_to_string(56 + 3) + &Self::square_to_string(56 + 1)
  64. },
  65. (&BLACK, true) => {
  66. Self::square_to_string(56 + 3) + &Self::square_to_string(56 + 5)
  67. }
  68. }
  69. },
  70. Move::EnPassant{ mov, beaten } => {
  71. Self::square_to_string(mov.from) + &Self::square_to_string(mov.to)
  72. },
  73. Move::Promotion{ mov, promote_to } => {
  74. Self::square_to_string(mov.from) + &Self::square_to_string(mov.to) +
  75. if *promote_to == QUEEN { "Q" }
  76. else if *promote_to == ROOK { "R" }
  77. else if *promote_to == KNIGHT { "N" }
  78. else if *promote_to == BISHOP { "B" }
  79. else { "" }
  80. },
  81. }
  82. }
  83. }
  84. /**
  85. * @brief Iterator to serialize bitboard bit for bit
  86. *
  87. * Extracts every bit out of the bitboard and returns each one as a separate bitboard.
  88. */
  89. pub struct BitboardIterator { pub board: Bitboard }
  90. impl Iterator for BitboardIterator {
  91. type Item = Bitboard;
  92. fn next(&mut self) -> Option<Bitboard> {
  93. if self.board != 0 {
  94. let lsb = self.board & (self.board.wrapping_neg());
  95. self.board ^= lsb;
  96. //Some(lsb.trailing_zeros())
  97. Some(lsb)
  98. } else {
  99. None
  100. }
  101. }
  102. }
  103. impl SimpleMove {
  104. pub fn apply_to(self, bitboard: Bitboard) -> Bitboard {
  105. (bitboard & !from_square(self.from)) | from_square(self.to)
  106. }
  107. }
  108. pub fn generate_moves(game: &Game, side: Side) -> Vec<Move> {
  109. let mut moves: Vec<Move> = Vec::with_capacity(128);
  110. generate_pawn_pushes(game, side, &mut moves);
  111. generate_pawn_doublepushes(game, side, &mut moves);
  112. generate_pawn_captures(game, side, &mut moves);
  113. generate_promotions(game, side, &mut moves);
  114. generate_en_passant(game, side, &mut moves);
  115. generate_knight_moves(game, side, &mut moves, false);
  116. generate_bishop_moves(game, side, &mut moves, false);
  117. generate_rook_moves(game, side, &mut moves, false);
  118. generate_queen_moves(game, side, &mut moves, false);
  119. generate_king_moves(game, side, &mut moves, false);
  120. generate_castling_moves(game, side, &mut moves);
  121. return moves;
  122. }
  123. /**
  124. * generates moves that could possibly attack a king,
  125. * this function is used to check if the king is in check
  126. */
  127. pub fn generate_possattacking_moves(game: &Game, side: Side) -> Vec<Move> {
  128. let mut moves: Vec<Move> = Vec::with_capacity(32);
  129. generate_pawn_captures(game, side, &mut moves);
  130. generate_promotions(game, side, &mut moves);
  131. generate_knight_moves(game, side, &mut moves, true);
  132. generate_bishop_moves(game, side, &mut moves, true);
  133. generate_rook_moves(game, side, &mut moves, true);
  134. generate_queen_moves(game, side, &mut moves, true);
  135. generate_king_moves(game, side, &mut moves, true);
  136. return moves;
  137. }
  138. pub fn generate_legal_moves(game: &Game, side: Side) -> Vec<Move> {
  139. let moves = generate_moves(game, side);
  140. moves.into_iter().filter(|mov| {
  141. let tryout = super::search::apply_move(game, *mov);
  142. !is_check(&tryout, side)
  143. }).collect::<Vec<Move>>()
  144. }
  145. pub fn generate_attacking_moves(game: &Game, side: Side) -> Vec<Move> {
  146. let mut moves: Vec<Move> = Vec::with_capacity(32);
  147. generate_pawn_captures(game, side, &mut moves);
  148. generate_knight_moves(game, side, &mut moves, true);
  149. generate_bishop_moves(game, side, &mut moves, true);
  150. generate_rook_moves(game, side, &mut moves, true);
  151. generate_queen_moves(game, side, &mut moves, true);
  152. generate_king_moves(game, side, &mut moves, true);
  153. return moves;
  154. }
  155. pub fn sort_moves(game: &Game, move_list: &mut Vec<Move>) {
  156. let all_pieces = game.get_all_side(WHITE) | game.get_all_side(BLACK);
  157. move_list.sort_by_key(|mov| {
  158. match mov {
  159. Move::Default { mov, piece_type } => if (from_square(mov.to) & all_pieces) != 0 { -10 } else { 0 },
  160. Move::Castling { side: _, left: _ } => 0,
  161. Move::Promotion { mov, promote_to } => -15,
  162. Move::EnPassant { mov: _, beaten: _ } => -10,
  163. }
  164. });
  165. }
  166. /*
  167. pub fn generate_pawn_moves(game: &Game, side: Side) -> Bitboard {
  168. let pushed = generate_pawn_pushes(game, side);
  169. let iter = BitboardIterator { board: pushed };
  170. for p in iter {
  171. println!("{}", p.trailing_zeros());
  172. }
  173. return 0;
  174. }*/
  175. fn generate_pawn_pushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  176. let pawns = game.pawns(side);
  177. let others = game.get_all_side(!side);
  178. let pieces = game.get_all_side(side);
  179. let moved_pawns =
  180. match side {
  181. WHITE => north_one(pawns),
  182. BLACK => south_one(pawns)
  183. } & !(ROW_1 | ROW_8) & !(others | pieces);
  184. let iter = BitboardIterator { board: moved_pawns & !others };
  185. for p in iter {
  186. let origin = match side {
  187. WHITE => south_one(p),
  188. BLACK => north_one(p)
  189. };
  190. move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN });
  191. }
  192. }
  193. fn generate_pawn_doublepushes(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  194. let pawns = game.pawns(side) & match side { WHITE => ROW_2, BLACK => ROW_7 };
  195. let others = game.get_all_side(!side);
  196. let pieces = game.get_all_side(side);
  197. let all_pieces = others | pieces;
  198. let moved_pawns =
  199. match side {
  200. WHITE => north_one(north_one(pawns) & !all_pieces),
  201. BLACK => south_one(south_one(pawns) & !all_pieces)
  202. } & !all_pieces;
  203. let iter = BitboardIterator { board: moved_pawns & !others };
  204. for p in iter {
  205. let origin = match side {
  206. WHITE => south_one(south_one(p)),
  207. BLACK => north_one(north_one(p))
  208. };
  209. move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN });
  210. }
  211. }
  212. fn generate_pawn_captures(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  213. let pawns = game.pawns(side);
  214. let others = game.get_all_side(!side);
  215. let promotion_mask = ROW_1 | ROW_8;
  216. let pawn_iterator = BitboardIterator { board: pawns };
  217. for pawn in pawn_iterator {
  218. let left_cap = match side {
  219. WHITE => northeast_one(pawn),
  220. BLACK => southeast_one(pawn)
  221. };
  222. let right_cap = match side {
  223. WHITE => northwest_one(pawn),
  224. BLACK => southwest_one(pawn)
  225. };
  226. for cap in [left_cap, right_cap].iter() {
  227. if cap & others != 0 {
  228. let simple_move = SimpleMove { from: square(pawn), to: square(*cap) };
  229. if cap & promotion_mask != 0 {
  230. move_list.push(Move::Promotion { mov: simple_move, promote_to: QUEEN });
  231. move_list.push(Move::Promotion { mov: simple_move, promote_to: ROOK });
  232. move_list.push(Move::Promotion { mov: simple_move, promote_to: BISHOP });
  233. move_list.push(Move::Promotion { mov: simple_move, promote_to: KNIGHT });
  234. } else {
  235. move_list.push(Move::Default { mov: simple_move, piece_type: PAWN });
  236. }
  237. }
  238. }
  239. }
  240. }
  241. fn generate_promotions(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  242. let pawns = game.pawns(side);
  243. let others = game.get_all_side(!side);
  244. let pieces = game.get_all_side(side);
  245. let moved_pawns =
  246. match side {
  247. WHITE => north_one(pawns),
  248. BLACK => south_one(pawns)
  249. } & (ROW_1 | ROW_8) & !(others | pieces);
  250. let iter = BitboardIterator { board: moved_pawns };
  251. for p in iter {
  252. let origin = match side {
  253. WHITE => south_one(p),
  254. BLACK => north_one(p)
  255. };
  256. let movement = SimpleMove { from: square(origin), to: square(p) };
  257. //move_list.push(Move::Default { mov: SimpleMove { from: square(origin), to: square(p) }, piece_type: PAWN });
  258. move_list.push(Move::Promotion { mov: movement, promote_to: QUEEN });
  259. move_list.push(Move::Promotion { mov: movement, promote_to: ROOK });
  260. move_list.push(Move::Promotion { mov: movement, promote_to: BISHOP });
  261. move_list.push(Move::Promotion { mov: movement, promote_to: KNIGHT });
  262. }
  263. }
  264. fn generate_en_passant(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  265. if let Some(ep) = game.en_passant {
  266. let pawncolumn = A_FILE >> ep;
  267. let pawnrow: Bitboard = match side {
  268. WHITE => ROW_5,
  269. BLACK => ROW_4
  270. };
  271. let beaten_pawn = pawncolumn & pawnrow;
  272. if beaten_pawn & game.get_piece(PAWN, !side) == 0 {
  273. return;
  274. }
  275. let pawn_left = (beaten_pawn << 1) & pawnrow;
  276. let pawn_right = (beaten_pawn >> 1) & pawnrow;
  277. let attacking_pawns = game.get_piece(PAWN, side);
  278. let target_square = pawncolumn & match side {
  279. WHITE => ROW_6,
  280. BLACK => ROW_3
  281. };
  282. if pawn_left & attacking_pawns != 0 {
  283. let mov = Move::EnPassant{ mov: SimpleMove{ from: square(pawn_left), to: square(target_square) }, beaten: square(beaten_pawn) };
  284. move_list.push(mov);
  285. }
  286. if pawn_right & attacking_pawns != 0 {
  287. let mov = Move::EnPassant{ mov: SimpleMove{ from: square(pawn_right), to: square(target_square) }, beaten: square(beaten_pawn) };
  288. move_list.push(mov);
  289. }
  290. }
  291. }
  292. fn generate_knight_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  293. let friends = game.get_all_side(side);
  294. let others = game.get_all_side(!side);
  295. let knights = game.knights(side);
  296. let knight_iter = BitboardIterator{ board: knights };
  297. for k in knight_iter {
  298. let target_mask = if captures_only {
  299. !friends & others
  300. } else {
  301. !friends
  302. };
  303. let targets = BitboardIterator { board: get_knight_targets(square(k)) & target_mask };
  304. for target in targets {
  305. let simple_move = SimpleMove { from: square(k), to: square(target) };
  306. move_list.push(Move::Default{ mov: simple_move, piece_type: KNIGHT });
  307. }
  308. }
  309. }
  310. pub fn get_knight_targets(square: Square) -> Bitboard {
  311. /// @brief array containing the possible targets for a knight on each square.
  312. /// entry at index i is a bitboard with all bits set where a knight on square i can jump
  313. const TARGETS: [Bitboard; 64] = [132096, 329728, 659712, 1319424, 2638848, 5277696, 10489856,
  314. 4202496, 33816580, 84410376, 168886289, 337772578, 675545156, 1351090312, 2685403152,
  315. 1075839008, 8657044482, 21609056261, 43234889994, 86469779988, 172939559976, 345879119952,
  316. 687463207072, 275414786112, 2216203387392, 5531918402816, 11068131838464, 22136263676928,
  317. 44272527353856, 88545054707712, 175990581010432, 70506185244672, 567348067172352,
  318. 1416171111120896, 2833441750646784, 5666883501293568, 11333767002587136, 22667534005174272,
  319. 45053588738670592, 18049583422636032, 145241105196122112, 362539804446949376,
  320. 725361088165576704, 1450722176331153408, 2901444352662306816, 5802888705324613632,
  321. 11533718717099671552, 4620693356194824192, 288234782788157440, 576469569871282176,
  322. 1224997833292120064, 2449995666584240128, 4899991333168480256, 9799982666336960512,
  323. 1152939783987658752, 2305878468463689728, 1128098930098176, 2257297371824128, 4796069720358912,
  324. 9592139440717824, 19184278881435648, 38368557762871296, 4679521487814656, 9077567998918656];
  325. TARGETS[square as usize]
  326. }
  327. fn generate_bishop_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  328. let friends = game.get_all_side(side);
  329. let others = game.get_all_side(!side);
  330. generate_sliding_moves(friends, others, game.bishops(side), BISHOP, false, true, move_list, captures_only);
  331. }
  332. fn generate_rook_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  333. let friends = game.get_all_side(side);
  334. let others = game.get_all_side(!side);
  335. generate_sliding_moves(friends, others, game.rooks(side), ROOK, true, false, move_list, captures_only);
  336. }
  337. fn generate_queen_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  338. let friends = game.get_all_side(side);
  339. let others = game.get_all_side(!side);
  340. generate_sliding_moves(friends, others, game.queens(side), QUEEN, true, true, move_list, captures_only);
  341. }
  342. fn generate_sliding_moves(friends: Bitboard, others: Bitboard, pieces: Bitboard, piece_type: PieceType,
  343. straight: bool, diagonal: bool, move_list: &mut Vec<Move>, captures_only: bool) {
  344. let pieces_iter = BitboardIterator { board: pieces };
  345. let mask = if captures_only { others } else { !(0 as Bitboard) };
  346. for piece in pieces_iter {
  347. let destinations = generate_sliding_destinations(friends, others, piece, straight, diagonal);
  348. let dest_iter = BitboardIterator { board: destinations & mask };
  349. for dest in dest_iter {
  350. let smove = SimpleMove{ from: square(piece), to: square(dest) };
  351. move_list.push(Move::Default { mov: smove, piece_type: piece_type});
  352. }
  353. }
  354. }
  355. fn generate_sliding_destinations(friends: Bitboard, others: Bitboard,
  356. piece: Bitboard, straight: bool,
  357. diagonal: bool) -> Bitboard {
  358. let occupied = friends | others;
  359. let straights = [north_one, south_one, east_one, west_one];
  360. let diagonals = [northeast_one, southeast_one, northwest_one, southwest_one];
  361. let mut result: Bitboard = 0;
  362. if straight {
  363. for direction in straights.iter() {
  364. result |= generate_direction(piece, *direction, occupied);
  365. }
  366. }
  367. if diagonal {
  368. for direction in diagonals.iter() {
  369. result |= generate_direction(piece, *direction, occupied);
  370. }
  371. }
  372. return result & !friends;
  373. }
  374. fn generate_direction(piece: Bitboard, direction: fn(Bitboard) -> Bitboard, occupied: Bitboard) -> Bitboard {
  375. let mut result: Bitboard = 0;
  376. let mut b = piece;
  377. loop {
  378. b = direction(b);
  379. result |= b;
  380. if b & (occupied) != 0 || b == 0 {
  381. break;
  382. }
  383. }
  384. return result;
  385. }
  386. fn generate_king_moves(game: &Game, side: Side, move_list: &mut Vec<Move>, captures_only: bool) {
  387. let friends = game.get_all_side(side);
  388. let others = game.get_all_side(!side);
  389. let king = game.kings(side);
  390. //assert_eq!(king.count_ones(), 1); // assume only one king per player
  391. if king.count_ones() != 1 { return; }
  392. let mask =
  393. if captures_only {
  394. !friends & others
  395. }
  396. else {
  397. !friends
  398. };
  399. let area = (north_one(king)
  400. | south_one(king)
  401. | east_one(king)
  402. | west_one(king)
  403. | northeast_one(king)
  404. | northwest_one(king)
  405. | southwest_one(king)
  406. | southeast_one(king))
  407. & mask;
  408. let area_iter = BitboardIterator { board: area };
  409. for destination in area_iter {
  410. let simple_move = SimpleMove{ from: square(king), to: square(destination) };
  411. move_list.push(Move::Default { mov: simple_move, piece_type: KING });
  412. }
  413. }
  414. fn generate_castling_moves(game: &Game, side: Side, move_list: &mut Vec<Move>) {
  415. let c1 = Move::Castling{ side: side, left: false };
  416. let c2 = Move::Castling{ side: side, left: true };
  417. let legal_castlings: &[bool] = match side {
  418. WHITE => &game.castling_rights[0..2],
  419. BLACK => &game.castling_rights[2..4],
  420. };
  421. let all_pieces = game.get_all_side(WHITE) | game.get_all_side(BLACK);
  422. // kingside castling
  423. if legal_castlings[0] {
  424. //info!("possible castling? {} {} {}", game.get_piece(KING, side), game.get_piece(ROOK, side), ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)));
  425. if ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)) != 0 &&
  426. ((game.get_piece(KING, side) >> 1) | (game.get_piece(KING, side) >> 2)) & all_pieces == 0 {
  427. let mut tg1 = game.clone();
  428. *tg1.get_piece_mut(KING, side) = game.get_piece(KING, side) >> 1;
  429. if !is_check(game, side) && !is_check(&tg1, side) {
  430. move_list.push(c1);
  431. }
  432. }
  433. }
  434. // queenside
  435. if legal_castlings[1] {
  436. //info!("possible castling? {} {} {}", game.get_piece(KING, side), game.get_piece(ROOK, side), ((game.get_piece(KING, side) >> 3) & game.get_piece(ROOK, side)));
  437. if ((game.get_piece(KING, side) << 4) & game.get_piece(ROOK, side)) != 0 &&
  438. ((game.get_piece(KING, side) << 1) | (game.get_piece(KING, side) << 2) | (game.get_piece(KING, side) << 3)) & all_pieces == 0 {
  439. let mut tg1 = game.clone();
  440. let mut tg2 = game.clone();
  441. *tg1.get_piece_mut(KING, side) = game.get_piece(KING, side) << 1;
  442. *tg2.get_piece_mut(KING, side) = game.get_piece(KING, side) << 2;
  443. if !is_check(game, side) && !is_check(&tg1, side) && !is_check(&tg2, side) {
  444. move_list.push(c2);
  445. }
  446. }
  447. }
  448. }
  449. /**
  450. * checks if side's king is in check
  451. */
  452. pub fn is_check(game: &Game, side: Side) -> bool {
  453. let king_square = square(game.get_piece(KING, side));
  454. let possible_attacks = generate_possattacking_moves(game, !side);
  455. for mov in possible_attacks {
  456. if let Move::Default{ mov, piece_type: _ } = mov {
  457. if mov.to == king_square {
  458. return true;
  459. }
  460. }
  461. else if let Move::Promotion{ mov, promote_to: _ } = mov {
  462. if mov.to == king_square {
  463. return true;
  464. }
  465. }
  466. }
  467. false
  468. }
  469. /*
  470. #[cfg(test)]
  471. mod tests {
  472. use search::Game;
  473. use movegen::*;
  474. #[test]
  475. fn pawn_pushes() {
  476. let mut game: Game = Game::default();
  477. let pawn_moves = generate_pawn_moves(&game, WHITE);
  478. assert_eq!(pawn_moves, ());
  479. }
  480. }
  481. */