Skip to main content

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}