diff --git a/Cargo.lock b/Cargo.lock index 5657680..1b5b4f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "block-buffer" version = "0.10.4" @@ -126,6 +132,21 @@ dependencies = [ "typenum", ] +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", + "rayon", +] + [[package]] name = "digest" version = "0.10.7" @@ -152,6 +173,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -190,6 +217,16 @@ version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.22" @@ -217,6 +254,19 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + [[package]] name = "pest" version = "2.7.14" @@ -300,6 +350,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.11.1" @@ -329,6 +388,12 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "sha2" version = "0.10.8" @@ -346,10 +411,17 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "swordfish" version = "0.0.0" dependencies = [ + "dashmap", "rayon", "regex", "vampirc-uci", diff --git a/Cargo.toml b/Cargo.toml index 3d31cc0..2158906 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" edition = "2021" [dependencies] +dashmap = { version = "6.1.0", features = ["rayon"] } rayon = "1.10.0" regex = "1.10.6" vampirc-uci = "0.11" diff --git a/src/gamemanager/legal_moves.rs b/src/gamemanager/legal_moves.rs index c1f3e35..a7ac53b 100644 --- a/src/gamemanager/legal_moves.rs +++ b/src/gamemanager/legal_moves.rs @@ -4,7 +4,6 @@ use crate::{ bitboard::*, gamemanager::*, types::{CastlingRights, Color, MoveType, PieceType, Square}, - MOVETABLE, }; pub mod perft; @@ -14,7 +13,10 @@ impl GameManager { /// This results in a list of possible GameManagers that could result from /// the possible moves, which are also returned. Each can be evaluated for /// strengths and weaknesses. - pub fn legal_moves(&self) -> Vec<(PieceType, Square, Square, MoveType, GameManager)> { + pub fn legal_moves( + &self, + tbl: &NoArc, + ) -> Vec<(PieceType, Square, Square, MoveType, GameManager)> { /* ************************************************************************************* */ /* WARNING: THIS FUNCTION WILL ERROR SILENTLY IF ANY COLOR-DEPENDENT LOGIC IS USED HERE. */ /* ALL LOGIC IN THIS FUNCTION MUST BE COLOR-AGNOSTIC. */ @@ -27,69 +29,15 @@ impl GameManager { let mut legal_moves: Vec<(PieceType, Square, Square, MoveType, GameManager)> = vec![]; - // Based on color, union all the friendly and enemy pieces, and determine - // which squares the enemy is attacking. We'll need that info for checking - // whether the king is in danger. - let (friendly_pieces, enemy_pieces, currently_attacked) = match color { - Color::Black => { - let friendly_pieces = self.bitboard.pawns_black - | self.bitboard.rooks_black - | self.bitboard.knights_black - | self.bitboard.bishops_black - | self.bitboard.queens_black - | self.bitboard.king_black; - let enemy_pieces = self.bitboard.pawns_white - | self.bitboard.rooks_white - | self.bitboard.knights_white - | self.bitboard.bishops_white - | self.bitboard.queens_white - | self.bitboard.king_white; - - let enemy_attacked = self.attacked_by(Color::White); - - (friendly_pieces, enemy_pieces, enemy_attacked) - } - Color::White => { - let friendly_pieces = self.bitboard.pawns_white - | self.bitboard.rooks_white - | self.bitboard.knights_white - | self.bitboard.bishops_white - | self.bitboard.queens_white - | self.bitboard.king_white; - let enemy_pieces = self.bitboard.pawns_black - | self.bitboard.rooks_black - | self.bitboard.knights_black - | self.bitboard.bishops_black - | self.bitboard.queens_black - | self.bitboard.king_black; - - let enemy_attacked = self.attacked_by(Color::Black); - - (friendly_pieces, enemy_pieces, enemy_attacked) - } - }; - - // Based on color, extract the friendly and enemy kings. - let (friendly_king, enemy_king) = match color { - Color::Black => (self.bitboard.king_black, self.bitboard.king_white), - Color::White => (self.bitboard.king_white, self.bitboard.king_black), - }; - - // Based on color, extract the friendly and enemy rooks. - let (friendly_rooks, enemy_rooks) = match color { - Color::Black => (self.bitboard.rooks_black, self.bitboard.rooks_white), - Color::White => (self.bitboard.rooks_white, self.bitboard.rooks_black), - }; - // First get all the pseudolegal moves. let pslm = pseudolegal_moves::pseudolegal_moves( color, self.bitboard, - &MOVETABLE, self.castling_rights, &self.en_passant_target, self.halfmoves, self.fullmoves, + &tbl, ); // ASSERT: We will never have Super moves in the pseudolegal moves vector. @@ -137,10 +85,13 @@ impl GameManager { } // TODO: Test mask and king intersection. - let enemy_attacked = modified_gm.attacked_by(match color { - Color::Black => Color::White, - Color::White => Color::Black, - }); + let enemy_attacked = modified_gm.attacked_by( + &tbl, + match color { + Color::Black => Color::White, + Color::White => Color::Black, + }, + ); match color { Color::Black => { @@ -191,7 +142,6 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, ..*self }, MoveType::Capture => { @@ -209,7 +159,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -239,7 +189,7 @@ impl GameManager { }, castling_rights: new_castling_rights, en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::Capture => { @@ -257,7 +207,7 @@ impl GameManager { }, castling_rights: new_castling_rights, en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -276,7 +226,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::QueenCastle => GameManager { @@ -288,7 +238,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::Capture => { @@ -305,7 +255,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -316,7 +266,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, _ => unreachable!("Kings will never make another type of move."), @@ -329,7 +279,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::Capture => { @@ -347,7 +297,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -363,7 +313,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::RPromotion => GameManager { @@ -374,7 +324,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::NPromotion => GameManager { @@ -385,7 +335,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::QPromotion => GameManager { @@ -396,7 +346,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, // On a promotion capture to X delete all enemy pieces @@ -416,7 +366,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -435,7 +385,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -454,7 +404,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -473,7 +423,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -503,7 +453,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -532,7 +482,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: String::from(target_coord), - movetable: &MOVETABLE, + ..*self } } @@ -543,7 +493,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::Capture => { @@ -560,7 +510,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -577,7 +527,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::Capture => { @@ -594,7 +544,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -636,7 +586,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::Capture => { @@ -654,7 +604,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -684,7 +634,7 @@ impl GameManager { }, castling_rights: new_castling_rights, en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::Capture => { @@ -702,7 +652,7 @@ impl GameManager { }, castling_rights: new_castling_rights, en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -721,7 +671,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::QueenCastle => GameManager { @@ -733,7 +683,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::Capture => { @@ -750,7 +700,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -761,7 +711,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, _ => unreachable!("Kings will never make another type of move."), @@ -774,7 +724,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::Capture => { @@ -792,7 +742,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -808,7 +758,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::RPromotion => GameManager { @@ -819,7 +769,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::NPromotion => GameManager { @@ -830,7 +780,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::QPromotion => GameManager { @@ -841,7 +791,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, // On a promotion capture to X delete all enemy pieces @@ -861,7 +811,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -880,7 +830,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -899,7 +849,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -918,7 +868,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -948,7 +898,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -977,7 +927,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: String::from(target_coord), - movetable: &MOVETABLE, + ..*self } } @@ -988,7 +938,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::Capture => { @@ -1005,7 +955,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -1022,7 +972,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self }, MoveType::Capture => { @@ -1039,7 +989,7 @@ impl GameManager { }, castling_rights: self.castling_rights.clone(), en_passant_target: self.en_passant_target.clone(), - movetable: &MOVETABLE, + ..*self } } @@ -1058,7 +1008,7 @@ mod tests { #[test] fn test_en_passant() { let gm = GameManager::black_match_block( - &GameManager::from_fen_string("6k1/5p2/4p3/2p1P3/1pP2P2/1P6/8/6K1 b - c3 0 1"), + &GameManager::from_fen_str("6k1/5p2/4p3/2p1P3/1pP2P2/1P6/8/6K1 b - c3 0 1"), crate::types::PieceType::Pawn, crate::types::MoveType::EPCapture, crate::types::Square::B4, diff --git a/src/gamemanager/legal_moves/perft.rs b/src/gamemanager/legal_moves/perft.rs index d2e08b3..fe3f871 100644 --- a/src/gamemanager/legal_moves/perft.rs +++ b/src/gamemanager/legal_moves/perft.rs @@ -1,23 +1,13 @@ -use crate::types::Move; - -use super::GameManager; +use super::{GameManager, MoveTable, NoArc}; use rayon::prelude::*; -pub fn perft(depth: u16, maxdepth: u16, mv: Move, gm: GameManager) { - if depth > maxdepth { - return; - } - let mvlst = gm.legal_moves(); - let count = mvlst.iter().count(); +pub fn perft(depth: u16, maxdepth: u16, gm: GameManager, tbl: &NoArc) -> u64 { if depth == maxdepth { - //let s = format!("{}{}: ", mv.1.to_str(), mv.2.to_str()).to_ascii_lowercase(); - //println!("{}", s); - //eprintln!("MOVE AT DEPTH {depth}"); - //println!("{s}{}", mvlst.iter().count()); + 1 + } else { + gm.legal_moves(tbl) + .into_par_iter() + .map(|mv| perft(depth + 1, maxdepth, mv.4, tbl)) + .sum::() } - mvlst - .into_par_iter() - .for_each(|(pc, from, to, mvtp, modgm)| { - perft(depth + 1, maxdepth, (pc, from, to, mvtp.clone()), modgm) - }); } diff --git a/src/gamemanager/mod.rs b/src/gamemanager/mod.rs index f225248..61e7521 100644 --- a/src/gamemanager/mod.rs +++ b/src/gamemanager/mod.rs @@ -1,11 +1,7 @@ -#![allow(dead_code, unused_variables, unused_mut)] -use std::sync::LazyLock; - use crate::{ bitboard, - movetable::MoveTable, + movetable::{noarc::NoArc, MoveTable}, types::{CastlingRecord, Color}, - MOVETABLE, }; use bitboard::BitBoard; use pseudolegal_moves::pseudolegal_moves; @@ -33,7 +29,6 @@ pub struct GameManager { * fullmove number - number of completed turns (increment when black moves) */ pub bitboard: BitBoard, - pub movetable: &'static LazyLock, pub white_to_move: bool, pub castling_rights: CastlingRecord, pub en_passant_target: String, @@ -42,11 +37,10 @@ pub struct GameManager { } impl Default for GameManager { - /// Constructs a new `GameManager`, set to Chess's starting position + /// Constructs a new `GameManager` set to startpos. fn default() -> Self { GameManager { bitboard: BitBoard::default(), - movetable: &MOVETABLE, white_to_move: true, castling_rights: CastlingRecord::default(), en_passant_target: String::new(), @@ -60,13 +54,12 @@ impl GameManager { /// A utility method for generating a new `GameManager` from a FEN string\ /// * `fen` - a `&str` representing a game's state in FEN /// * `returns` - a `GameManager` as generated from the FEN - pub fn from_fen_string(fen: &str) -> Self { + pub fn from_fen_str(fen: &str) -> Self { if Self::is_valid_fen(fen) { let tokens: Vec = fen.split_whitespace().map(str::to_string).collect(); GameManager { //board space validation implemented at higher level (is_valid_fen()) bitboard: BitBoard::from_fen_string(&tokens[0]), - movetable: &MOVETABLE, white_to_move: tokens[1] == "w", castling_rights: CastlingRecord::try_from(tokens[2].as_str()) .expect("We expect FEN strings to be well-formed."), @@ -151,15 +144,15 @@ impl GameManager { } /// Returns a bitmask of all the pieces attacked by the given color on this GameManager's state. - pub fn attacked_by(&self, color: Color) -> u64 { + pub fn attacked_by(&self, tbl: &NoArc, color: Color) -> u64 { let moves = pseudolegal_moves( color, self.bitboard, - &MOVETABLE, self.castling_rights, &self.en_passant_target, self.halfmoves, self.fullmoves, + tbl, ); moves @@ -172,7 +165,11 @@ impl GameManager { #[cfg(test)] mod test { use super::GameManager; - use crate::{gamemanager::pseudolegal_moves::*, types::Color}; + use crate::{ + gamemanager::pseudolegal_moves::*, + movetable::{noarc::NoArc, MoveTable}, + types::Color, + }; #[test] fn check_psl_moves_1() { @@ -180,11 +177,11 @@ mod test { let moves = pseudolegal_moves( Color::Black, game_manager.bitboard, - &game_manager.movetable, game_manager.castling_rights, &game_manager.en_passant_target, game_manager.halfmoves, game_manager.fullmoves, + &NoArc::new(MoveTable::default()), ); assert_eq!( @@ -199,11 +196,11 @@ mod test { let moves = pseudolegal_moves( Color::White, game_manager.bitboard, - &game_manager.movetable, game_manager.castling_rights, &game_manager.en_passant_target, game_manager.halfmoves, game_manager.fullmoves, + &NoArc::new(MoveTable::default()), ); assert_eq!( diff --git a/src/gamemanager/pseudolegal_moves/bishops.rs b/src/gamemanager/pseudolegal_moves/bishops.rs index d614306..ac38478 100644 --- a/src/gamemanager/pseudolegal_moves/bishops.rs +++ b/src/gamemanager/pseudolegal_moves/bishops.rs @@ -1,4 +1,7 @@ -use crate::{movetable::MoveTable, types::*}; +use crate::{ + movetable::{noarc::NoArc, MoveTable}, + types::*, +}; /// Returns all pseudolegal moves the knights can make from their positions. /// ## Inputs @@ -41,10 +44,10 @@ use crate::{movetable::MoveTable, types::*}; /// ``` pub fn pseudolegal_bishop_moves( color: Color, - movetable: &MoveTable, bishop_locations: Vec, friendly_pieces: u64, enemy_pieces: u64, + movetable: &NoArc, ) -> Vec<(PieceType, Square, Square, MoveType)> { let mut bishop_pseudo_legal_moves = Vec::new(); @@ -88,17 +91,21 @@ pub fn pseudolegal_bishop_moves( #[cfg(test)] mod test { - use crate::{gamemanager::pseudolegal_moves::bishops, movetable::MoveTable, types::*}; + use crate::{ + gamemanager::pseudolegal_moves::bishops, + movetable::{noarc::NoArc, MoveTable}, + types::*, + }; use std::collections::HashSet; #[test] fn check_bishop_pslm() { let pslnm = bishops::pseudolegal_bishop_moves( Color::Black, - &MoveTable::default(), vec![0x20000000_00000000], 0xFFAF5000_00000000, 0xFFFF, + &NoArc::new(MoveTable::default()), ); let moves: HashSet = HashSet::from_iter( vec![ diff --git a/src/gamemanager/pseudolegal_moves/kings.rs b/src/gamemanager/pseudolegal_moves/kings.rs index da96346..31fb191 100644 --- a/src/gamemanager/pseudolegal_moves/kings.rs +++ b/src/gamemanager/pseudolegal_moves/kings.rs @@ -1,4 +1,7 @@ -use crate::{movetable::MoveTable, types::*}; +use crate::{ + movetable::{noarc::NoArc, MoveTable}, + types::*, +}; /// Returns all pseudolegal moves the kings can make from their positions. /// ## Inputs @@ -43,12 +46,12 @@ use crate::{movetable::MoveTable, types::*}; /// ``` pub fn pseudolegal_king_moves( color: Color, - movetable: &MoveTable, king_locations: Vec, friendly_pieces: u64, friendly_rooks: u64, enemy_pieces: u64, castling_rights: CastlingRecord, + movetable: &NoArc, ) -> Vec { let mut king_pseudo_legal_moves = Vec::new(); @@ -190,7 +193,11 @@ pub fn pseudolegal_king_moves( #[cfg(test)] mod tests { - use crate::{gamemanager::pseudolegal_moves::kings, movetable::MoveTable, types::*}; + use crate::{ + gamemanager::pseudolegal_moves::kings, + movetable::{noarc::NoArc, MoveTable}, + types::*, + }; use std::collections::HashSet; use Square::*; @@ -198,7 +205,6 @@ mod tests { fn check_king_pslm() { let pslnm = kings::pseudolegal_king_moves( Color::Black, - &MoveTable::default(), vec![B5.to_u64()], 0, 0, @@ -207,6 +213,7 @@ mod tests { black: CastlingRights::Neither, white: CastlingRights::Neither, }, + &NoArc::new(MoveTable::default()), ); let moves: HashSet = HashSet::from_iter( vec![ @@ -230,7 +237,6 @@ mod tests { fn check_black_king_pslm_castling() { let pslnm = kings::pseudolegal_king_moves( Color::Black, - &MoveTable::default(), vec![E8.to_u64()], 0, Square::A8.to_u64() | Square::H8.to_u64(), @@ -239,6 +245,7 @@ mod tests { black: CastlingRights::Both, white: CastlingRights::Neither, }, + &NoArc::new(MoveTable::default()), ); let moves: HashSet = HashSet::from_iter( vec![ @@ -262,7 +269,6 @@ mod tests { fn check_white_king_pslm_castling() { let pslnm = kings::pseudolegal_king_moves( Color::White, - &MoveTable::default(), vec![E1.to_u64()], 0, Square::A1.to_u64() | Square::H1.to_u64(), @@ -271,6 +277,7 @@ mod tests { black: CastlingRights::Neither, white: CastlingRights::Both, }, + &NoArc::new(MoveTable::default()), ); let moves: HashSet = HashSet::from_iter( vec![ diff --git a/src/gamemanager/pseudolegal_moves/knights.rs b/src/gamemanager/pseudolegal_moves/knights.rs index 02e8f76..f96dd30 100644 --- a/src/gamemanager/pseudolegal_moves/knights.rs +++ b/src/gamemanager/pseudolegal_moves/knights.rs @@ -1,4 +1,7 @@ -use crate::{movetable::MoveTable, types::*}; +use crate::{ + movetable::{noarc::NoArc, MoveTable}, + types::*, +}; /// Returns all pseudolegal moves the knights can make from their positions. /// ## Inputs @@ -29,10 +32,10 @@ use crate::{movetable::MoveTable, types::*}; /// ``` pub fn pseudolegal_knight_moves( color: Color, - movetable: &MoveTable, knight_locations: Vec, friendly_pieces: u64, enemy_pieces: u64, + movetable: &NoArc, ) -> Vec { let mut knight_pseudo_legal_moves = Vec::new(); @@ -73,6 +76,7 @@ pub fn pseudolegal_knight_moves( #[cfg(test)] mod tests { use crate::gamemanager::pseudolegal_moves::knights; + use crate::movetable::noarc::NoArc; use crate::{movetable::MoveTable, types::*}; use std::collections::HashSet; @@ -80,10 +84,10 @@ mod tests { fn check_knight_pslm() { let pslnm = knights::pseudolegal_knight_moves( Color::Black, - &MoveTable::default(), vec![0x40000000_00000000], 0xFFFF0000_00000000, 0xFFFF, + &NoArc::new(MoveTable::default()), ); let moves: HashSet = HashSet::from_iter( vec![0x00008000_00000000, 0x00002000_00000000] diff --git a/src/gamemanager/pseudolegal_moves/mod.rs b/src/gamemanager/pseudolegal_moves/mod.rs index 955725d..1119ed4 100644 --- a/src/gamemanager/pseudolegal_moves/mod.rs +++ b/src/gamemanager/pseudolegal_moves/mod.rs @@ -13,7 +13,7 @@ pub mod rooks; use crate::{ bitboard::BitBoard, gamemanager::GameManager, - movetable::MoveTable, + movetable::{noarc::NoArc, MoveTable}, types::{CastlingRecord, Color, Move}, }; @@ -23,11 +23,11 @@ use crate::{ pub fn pseudolegal_moves( color: Color, bitboard: BitBoard, - movetable: &MoveTable, castling_rights: CastlingRecord, en_passant_target: &str, halfmoves: u32, fullmoves: u32, + movetable: &NoArc, ) -> Vec { let mut pseudolegal_moves: Vec = Vec::new(); @@ -65,58 +65,58 @@ pub fn pseudolegal_moves( let mut pawn_pseudo_legal_moves = pawns::pseudolegal_pawn_moves( color, - movetable, pawns, friendly_pieces, enemy_pieces, en_passant_target, + &movetable, ); pseudolegal_moves.append(&mut pawn_pseudo_legal_moves); let mut knight_pseudo_legal_moves = knights::pseudolegal_knight_moves( color, - movetable, knights, friendly_pieces, enemy_pieces, + &movetable, ); pseudolegal_moves.append(&mut knight_pseudo_legal_moves); let mut bishop_pseudo_legal_moves = bishops::pseudolegal_bishop_moves( color, - movetable, bishops, friendly_pieces, enemy_pieces, + &movetable, ); pseudolegal_moves.append(&mut bishop_pseudo_legal_moves); let mut rook_pseudo_legal_moves = rooks::pseudolegal_rook_moves( color, - movetable, rooks, friendly_pieces, enemy_pieces, + &movetable, ); pseudolegal_moves.append(&mut rook_pseudo_legal_moves); let mut queen_pseudo_legal_moves = queens::pseudolegal_queen_moves( color, - movetable, queens, friendly_pieces, enemy_pieces, + &movetable, ); pseudolegal_moves.append(&mut queen_pseudo_legal_moves); let mut king_pseudo_legal_moves = kings::pseudolegal_king_moves( color, - movetable, kings, friendly_pieces, bitboard.rooks_black, enemy_pieces, castling_rights, + &movetable, ); pseudolegal_moves.append(&mut king_pseudo_legal_moves); } @@ -145,58 +145,58 @@ pub fn pseudolegal_moves( let mut pawn_pseudo_legal_moves = pawns::pseudolegal_pawn_moves( color, - movetable, pawns, friendly_pieces, enemy_pieces, en_passant_target, + &movetable, ); pseudolegal_moves.append(&mut pawn_pseudo_legal_moves); let mut knight_pseudo_legal_moves = knights::pseudolegal_knight_moves( color, - movetable, knights, friendly_pieces, enemy_pieces, + &movetable, ); pseudolegal_moves.append(&mut knight_pseudo_legal_moves); let mut bishop_pseudo_legal_moves = bishops::pseudolegal_bishop_moves( color, - movetable, bishops, friendly_pieces, enemy_pieces, + &movetable, ); pseudolegal_moves.append(&mut bishop_pseudo_legal_moves); let mut rook_pseudo_legal_moves = rooks::pseudolegal_rook_moves( color, - movetable, rooks, friendly_pieces, enemy_pieces, + &movetable, ); pseudolegal_moves.append(&mut rook_pseudo_legal_moves); let mut queen_pseudo_legal_moves = queens::pseudolegal_queen_moves( color, - movetable, queens, friendly_pieces, enemy_pieces, + &movetable, ); pseudolegal_moves.append(&mut queen_pseudo_legal_moves); let mut king_pseudo_legal_moves = kings::pseudolegal_king_moves( color, - movetable, kings, friendly_pieces, bitboard.rooks_white, enemy_pieces, castling_rights, + &movetable, ); pseudolegal_moves.append(&mut king_pseudo_legal_moves); } diff --git a/src/gamemanager/pseudolegal_moves/pawns.rs b/src/gamemanager/pseudolegal_moves/pawns.rs index f2bcdf7..814c286 100644 --- a/src/gamemanager/pseudolegal_moves/pawns.rs +++ b/src/gamemanager/pseudolegal_moves/pawns.rs @@ -1,4 +1,7 @@ -use crate::{movetable::MoveTable, types::*}; +use crate::{ + movetable::{noarc::NoArc, MoveTable}, + types::*, +}; /// A method returning a list of pseudo-legal pawn moves playable according to /// the information encoded in this instance of GameManager @@ -11,11 +14,11 @@ use crate::{movetable::MoveTable, types::*}; /// the target `Square`, and the `MoveType`) pub fn pseudolegal_pawn_moves( color: Color, - movetable: &MoveTable, pawn_locations: Vec, friendly_pieces: u64, enemy_pieces: u64, en_passant_target: &str, + movetable: &NoArc, ) -> Vec { let mut pawn_pseudo_legal_moves = Vec::new(); diff --git a/src/gamemanager/pseudolegal_moves/queens.rs b/src/gamemanager/pseudolegal_moves/queens.rs index 3a44f67..9026501 100644 --- a/src/gamemanager/pseudolegal_moves/queens.rs +++ b/src/gamemanager/pseudolegal_moves/queens.rs @@ -1,11 +1,14 @@ -use crate::{movetable::MoveTable, types::*}; +use crate::{ + movetable::{noarc::NoArc, MoveTable}, + types::*, +}; pub fn pseudolegal_queen_moves( color: Color, - movetable: &MoveTable, queen_locations: Vec, friendly_pieces: u64, enemy_pieces: u64, + movetable: &NoArc, ) -> Vec { let mut queen_pseudo_legal_moves = Vec::new(); diff --git a/src/gamemanager/pseudolegal_moves/rooks.rs b/src/gamemanager/pseudolegal_moves/rooks.rs index e02f377..15ba3c2 100644 --- a/src/gamemanager/pseudolegal_moves/rooks.rs +++ b/src/gamemanager/pseudolegal_moves/rooks.rs @@ -1,4 +1,7 @@ -use crate::{movetable::MoveTable, types::*}; +use crate::{ + movetable::{noarc::NoArc, MoveTable}, + types::*, +}; /// Returns all pseudolegal moves the rooks can make from their positions. /// ## Inputs @@ -13,10 +16,10 @@ use crate::{movetable::MoveTable, types::*}; /// which expands to `(PieceType, Square, Square, MoveType)`. pub fn pseudolegal_rook_moves( color: Color, - movetable: &MoveTable, rook_locations: Vec, friendly_pieces: u64, enemy_pieces: u64, + movetable: &NoArc, ) -> Vec { let mut rook_pseudo_legal_moves = Vec::new(); @@ -87,6 +90,7 @@ pub fn pseudolegal_rook_moves( #[cfg(test)] mod tests { use crate::gamemanager::pseudolegal_moves::rooks; + use crate::movetable::noarc::NoArc; use crate::{movetable::MoveTable, types::*}; use std::collections::HashSet; @@ -96,10 +100,10 @@ mod tests { let pslm = rooks::pseudolegal_rook_moves( Color::Black, - &MoveTable::default(), vec![B5.to_u64()], 0, 0, + &NoArc::new(MoveTable::default()), ); let moves: HashSet = HashSet::from_iter( vec![ diff --git a/src/main.rs b/src/main.rs index c315fdd..a263703 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,7 @@ #![allow(dead_code)] -use std::sync::LazyLock; -use gamemanager::GameManager; -use movetable::MoveTable; +use gamemanager::{legal_moves::perft::perft, GameManager}; +use movetable::{noarc, MoveTable}; mod bitboard; mod gamemanager; @@ -10,27 +9,11 @@ mod movetable; mod types; mod ucimanager; -pub static MOVETABLE: LazyLock = std::sync::LazyLock::new(MoveTable::default); - fn main() { - let gm = - GameManager::from_fen_string("rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8"); - let mvlst = gm.legal_moves(); - for mv in &mvlst { - let s = format!("{}{}: ", mv.1.to_str(), mv.2.to_str()).to_ascii_lowercase(); - println!("{}{}", s, mv.4.legal_moves().iter().count()); - // println!( - // "{}: 1", - // format!( - // "{s}{}", - // mv.4.legal_moves() - // .iter() - // .map(|newmv| format!("{}{}", newmv.1.to_str(), newmv.2.to_str())) - // .fold(String::new(), |acc, s| acc.to_owned() + " " + &s) - // .to_ascii_lowercase() - // ) - // ); - } + let tbl = noarc::NoArc::new(MoveTable::default()); + + let gm = GameManager::default(); + println!("Searched {} nodes.", perft(0, 6, gm, &tbl)); } #[cfg(test)] @@ -66,7 +49,7 @@ mod test { ]; for fen in tests { - let game = GameManager::from_fen_string(fen); + let game = GameManager::from_fen_str(fen); let generated_fen = game.to_fen_string(); assert_eq!(fen, generated_fen); diff --git a/src/movetable.rs b/src/movetable/mod.rs similarity index 99% rename from src/movetable.rs rename to src/movetable/mod.rs index bb51e50..744f296 100644 --- a/src/movetable.rs +++ b/src/movetable/mod.rs @@ -1,5 +1,7 @@ use crate::types::{Color, PieceType}; -use std::collections::HashMap; +use dashmap::DashMap; + +pub mod noarc; /// A HashMap of [`(Color, PieceType, u64)`] indexing [`Vec>`] where /// the index integer is a position on the board (must be a power of two) and @@ -7,13 +9,13 @@ use std::collections::HashMap; /// can move in is a separate list. This facilitates move legality checking, /// because sliding pieces simply start at the head of the list and work out. pub struct MoveTable { - table: HashMap<(Color, PieceType, u64), Vec>>, + table: DashMap<(Color, PieceType, u64), Vec>>, } impl Default for MoveTable { /// Generates a `MoveTable` containing the possible moves for each piece type at each square fn default() -> Self { - let mut table: HashMap<(Color, PieceType, u64), Vec>> = HashMap::new(); + let table: DashMap<(Color, PieceType, u64), Vec>> = DashMap::new(); let mut shift = 0x8000000000000000; // Piece in the top left corner. for y in 0..8_usize { diff --git a/src/movetable/noarc.rs b/src/movetable/noarc.rs new file mode 100644 index 0000000..ee7d88d --- /dev/null +++ b/src/movetable/noarc.rs @@ -0,0 +1,24 @@ +use std::ops::Deref; + +#[derive(Copy, Clone)] +pub struct NoArc { + ptr: *mut T, +} + +impl NoArc { + pub fn new(val: T) -> Self { + Self { + ptr: Box::leak(Box::new(val)), + } + } +} + +unsafe impl Sync for NoArc {} +unsafe impl Send for NoArc {} + +impl Deref for NoArc { + type Target = T; + fn deref(&self) -> &Self::Target { + unsafe { self.ptr.as_ref().unwrap() } + } +}