bitstackchess/rules/promotion.rs
1//! PromotionLogic handles turning a pawn on its final rank into a chosen piece (Q, R, B, N).
2//! It removes the pawn’s old PID, updates captured_bits, and places the new piece PID.
3
4use crate::board::{PieceMapping, CapturedBits, Occupied};
5
6/// A stateless struct containing only static helper methods.
7pub struct PromotionLogic;
8
9impl PromotionLogic {
10 /// Promote a pawn `pawn_pid` on `dest` (rank 0 or 7) to `new_kind` (0=queen,1=bishop,2=knight,3=rook).
11 /// Uses fixed PIDs:
12 /// • White: 14=queen, 12=bishop, 10=knight, 8=rook
13 /// • Black: 30=queen, 28=bishop, 26=knight, 24=rook
14 /// Updates `mapping`, `occupied`, and `captured_bits`. Returns the new PID.
15 pub fn promote_pawn(
16 mapping: &mut PieceMapping,
17 occupied: &mut Occupied,
18 captured_bits: &mut CapturedBits,
19 pawn_pid: u8,
20 color: u8,
21 dest: u8,
22 new_kind: u8, // 0=queen,1=bishop,2=knight,3=rook
23 ) -> u8 {
24 // 1) Remove pawn from board:
25 mapping.remove_piece(pawn_pid);
26 *occupied &= !(1u64 << (dest as u64));
27 *captured_bits |= 1u32 << (pawn_pid as u32);
28
29 // 2) Compute new PID based on color and new_kind:
30 let new_pid = match (color, new_kind) {
31 (0, 0) => 14, // White queen
32 (0, 1) => 12, // White bishop
33 (0, 2) => 10, // White knight
34 (0, 3) => 8, // White rook
35 (1, 0) => 30, // Black queen
36 (1, 1) => 28, // Black bishop
37 (1, 2) => 26, // Black knight
38 (1, 3) => 24, // Black rook
39 _ => panic!("Invalid color ({}) or kind ({})", color, new_kind),
40 };
41
42 // 3) Place new piece on dest:
43 mapping.place_piece(new_pid, dest);
44 *occupied |= 1u64 << (dest as u64);
45
46 new_pid
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use crate::board::encode_square;
54
55 #[test]
56 fn promotion_removes_pawn_and_places_queen() {
57 let mut mapping = PieceMapping::new_empty();
58 let mut occupied: u64 = 0;
59 let mut captured_bits: u32 = 0;
60
61 // Pick White pawn PID=4 (pawn originally on e2), move it to e7=52
62 let pawn_pid = 4;
63 mapping.place_piece(pawn_pid, encode_square(6, 4)); // e7
64 occupied |= 1u64 << 52;
65
66 // Promote white pawn to queen on e8=60
67 let new_pid = PromotionLogic::promote_pawn(
68 &mut mapping,
69 &mut occupied,
70 &mut captured_bits,
71 pawn_pid,
72 0, // color = White
73 60, // destination e8
74 0, // new_kind = 0 (queen)
75 );
76 assert_eq!(new_pid, 14); // White queen PID=14
77 assert_eq!(mapping.piece_square[pawn_pid as usize], None);
78 assert_eq!(mapping.piece_square[new_pid as usize], Some(60));
79 assert_eq!((occupied >> 60) & 1u64, 1u64);
80 assert_eq!(
81 captured_bits & (1u32 << (pawn_pid as u32)),
82 1u32 << (pawn_pid as u32)
83 );
84 }
85}