bitstackchess 0.1.1

A bitboard‐based chess game engine with 10 × u128 move history
Documentation
//! PromotionLogic handles turning a pawn on its final rank into a chosen piece (Q, R, B, N).
//! It removes the pawn’s old PID, updates captured_bits, and places the new piece PID.

use crate::board::{PieceMapping, CapturedBits, Occupied};

/// A stateless struct containing only static helper methods.
pub struct PromotionLogic;

impl PromotionLogic {
    /// Promote a pawn `pawn_pid` on `dest` (rank 0 or 7) to `new_kind` (0=queen,1=bishop,2=knight,3=rook).
    /// Uses fixed PIDs:
    ///   • White:  14=queen, 12=bishop, 10=knight,  8=rook  
    ///   • Black:  30=queen, 28=bishop, 26=knight, 24=rook  
    /// Updates `mapping`, `occupied`, and `captured_bits`. Returns the new PID.
    pub fn promote_pawn(
        mapping: &mut PieceMapping,
        occupied: &mut Occupied,
        captured_bits: &mut CapturedBits,
        pawn_pid: u8,
        color: u8,
        dest: u8,
        new_kind: u8, // 0=queen,1=bishop,2=knight,3=rook
    ) -> u8 {
        // 1) Remove pawn from board:
        mapping.remove_piece(pawn_pid);
        *occupied &= !(1u64 << (dest as u64));
        *captured_bits |= 1u32 << (pawn_pid as u32);

        // 2) Compute new PID based on color and new_kind:
        let new_pid = match (color, new_kind) {
            (0, 0) => 14, // White queen
            (0, 1) => 12, // White bishop
            (0, 2) => 10, // White knight
            (0, 3) => 8,  // White rook
            (1, 0) => 30, // Black queen
            (1, 1) => 28, // Black bishop
            (1, 2) => 26, // Black knight
            (1, 3) => 24, // Black rook
            _ => panic!("Invalid color ({}) or kind ({})", color, new_kind),
        };

        // 3) Place new piece on dest:
        mapping.place_piece(new_pid, dest);
        *occupied |= 1u64 << (dest as u64);

        new_pid
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::board::encode_square;

    #[test]
    fn promotion_removes_pawn_and_places_queen() {
        let mut mapping = PieceMapping::new_empty();
        let mut occupied: u64 = 0;
        let mut captured_bits: u32 = 0;

        // Pick White pawn PID=4 (pawn originally on e2), move it to e7=52
        let pawn_pid = 4;
        mapping.place_piece(pawn_pid, encode_square(6, 4)); // e7
        occupied |= 1u64 << 52;

        // Promote white pawn to queen on e8=60
        let new_pid = PromotionLogic::promote_pawn(
            &mut mapping,
            &mut occupied,
            &mut captured_bits,
            pawn_pid,
            0,    // color = White
            60,   // destination e8
            0,    // new_kind = 0 (queen)
        );
        assert_eq!(new_pid, 14); // White queen PID=14
        assert_eq!(mapping.piece_square[pawn_pid as usize], None);
        assert_eq!(mapping.piece_square[new_pid as usize], Some(60));
        assert_eq!((occupied >> 60) & 1u64, 1u64);
        assert_eq!(
            captured_bits & (1u32 << (pawn_pid as u32)),
            1u32 << (pawn_pid as u32)
        );
    }
}