pounce 2.0.2

A mediocre (but trying its best) uci chess engine
Documentation
pub mod magic;
pub mod utils;

mod bishop;
mod king;
mod knight;
mod magic_gen;
mod pawn;
mod queen;
mod rook;
mod tables;
mod types;

pub use tables::init_tables;
pub use types::MoveGen;

use crate::chess::Position;

#[inline]
pub fn perft(pos: &mut Position, depth: u8) -> usize {
    let mut total = 0;
    let mut mg = MoveGen::new(pos);

    if depth == 0 {
        return 1;
    }

    if depth == 1 {
        return mg.len();
    }

    for m in &mut mg {
        pos.make_move(m);
        total += perft(pos, depth - 1);
        pos.unmake_move(m)
    }
    total
}

#[cfg(test)]
fn masked_perft(pos: &mut Position, depth: u8) -> usize {
    use crate::chess::bitboard::Bitboard;

    if depth == 0 {
        return 1;
    }

    let mut total = 0;
    let mask = pos.occupancy;

    let mut mg = MoveGen::new(pos);
    mg.set_mask(mask);

    for m in &mut mg {
        pos.make_move(m);
        total += masked_perft(pos, depth - 1);
        pos.unmake_move(m)
    }

    mg.set_mask(Bitboard::FULL);
    for m in &mut mg {
        pos.make_move(m);
        total += masked_perft(pos, depth - 1);
        pos.unmake_move(m)
    }

    total
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::chess::position::fen::{Fen, STARTPOS};

    const KIWIPETE_FEN: &str =
        "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1";
    const POSITTION_3_FEN: &str = "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1";
    const POSITION_4_FEN: &str = "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1";
    const POSITION_5_FEN: &str = "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8";
    const POSITION_6_FEN: &str =
        "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10";

    #[test]
    fn perft_normal() {
        init_tables();
        let Fen(position) = Fen::parse(STARTPOS).unwrap();
        assert_eq!(perft(&mut position.clone(), 2), 400);
        assert_eq!(perft(&mut position.clone(), 3), 8902);
        assert_eq!(perft(&mut position.clone(), 4), 197_281);
        assert_eq!(perft(&mut position.clone(), 5), 4_865_609);
        assert_eq!(perft(&mut position.clone(), 6), 119_060_324);
    }

    #[test]
    fn masked_perft_normal() {
        init_tables();
        let Fen(position) = Fen::parse(STARTPOS).unwrap();
        assert_eq!(masked_perft(&mut position.clone(), 2), 400);
        assert_eq!(masked_perft(&mut position.clone(), 3), 8902);
        assert_eq!(masked_perft(&mut position.clone(), 4), 197_281);
        assert_eq!(masked_perft(&mut position.clone(), 5), 4_865_609);
    }

    #[test]
    fn perft_kiwipete() {
        init_tables();
        let Fen(position) = Fen::parse(KIWIPETE_FEN).unwrap();
        assert_eq!(perft(&mut position.clone(), 1), 48);
        assert_eq!(perft(&mut position.clone(), 2), 2_039);
        assert_eq!(perft(&mut position.clone(), 3), 97_862);
        assert_eq!(perft(&mut position.clone(), 4), 4_085_603);
        assert_eq!(perft(&mut position.clone(), 5), 193_690_690);
    }

    #[test]
    fn perft_pos_3() {
        init_tables();
        let Fen(position) = Fen::parse(POSITTION_3_FEN).unwrap();
        assert_eq!(perft(&mut position.clone(), 1), 14);
        assert_eq!(perft(&mut position.clone(), 2), 191);
        assert_eq!(perft(&mut position.clone(), 3), 2_812);
        assert_eq!(perft(&mut position.clone(), 4), 43_238);
        assert_eq!(perft(&mut position.clone(), 5), 674_624);
        assert_eq!(perft(&mut position.clone(), 6), 11_030_083);
        assert_eq!(perft(&mut position.clone(), 7), 178_633_661);
    }

    #[test]
    fn perft_pos_4() {
        init_tables();
        let Fen(position) = Fen::parse(POSITION_4_FEN).unwrap();
        assert_eq!(perft(&mut position.clone(), 1), 6);
        assert_eq!(perft(&mut position.clone(), 2), 264);
        assert_eq!(perft(&mut position.clone(), 3), 9_467);
        assert_eq!(perft(&mut position.clone(), 4), 422_333);
        assert_eq!(perft(&mut position.clone(), 5), 15_833_292);
    }

    #[test]
    fn perft_pos_5() {
        init_tables();
        let Fen(position) = Fen::parse(POSITION_5_FEN).unwrap();
        assert_eq!(perft(&mut position.clone(), 1), 44);
        assert_eq!(perft(&mut position.clone(), 2), 1_486);
        assert_eq!(perft(&mut position.clone(), 3), 62_379);
        assert_eq!(perft(&mut position.clone(), 4), 2_103_487);
        assert_eq!(perft(&mut position.clone(), 5), 89_941_194);
    }

    #[test]
    fn masked_perft_pos_5() {
        init_tables();
        let Fen(position) = Fen::parse(POSITION_5_FEN).unwrap();
        assert_eq!(masked_perft(&mut position.clone(), 1), 44);
        assert_eq!(masked_perft(&mut position.clone(), 2), 1_486);
        assert_eq!(masked_perft(&mut position.clone(), 3), 62_379);
        assert_eq!(masked_perft(&mut position.clone(), 4), 2_103_487);
    }

    #[test]
    fn perft_pos_6() {
        init_tables();
        let Fen(position) = Fen::parse(POSITION_6_FEN).unwrap();
        assert_eq!(perft(&mut position.clone(), 1), 46);
        assert_eq!(perft(&mut position.clone(), 2), 2_079);
        assert_eq!(perft(&mut position.clone(), 3), 89_890);
        assert_eq!(perft(&mut position.clone(), 4), 3_894_594);
        assert_eq!(perft(&mut position.clone(), 5), 164_075_551);
    }
}