From 1fef25ebc6b4fa1f72cb64b906ad4071fe33f8e8 Mon Sep 17 00:00:00 2001 From: Bruno Dutra Date: Sun, 13 Oct 2024 19:57:10 +0200 Subject: [PATCH] restrict Copy trait to the smallest types --- benches/search.rs | 10 +++++----- lib/chess/board.rs | 2 +- lib/chess/position.rs | 18 +++++++++--------- lib/nnue.rs | 2 +- lib/nnue/evaluator.rs | 18 +++++++++--------- lib/nnue/hidden.rs | 26 +++++++++++++------------- lib/nnue/material.rs | 6 +++--- lib/nnue/positional.rs | 8 ++++---- lib/nnue/transformer.rs | 2 +- lib/search/driver.rs | 4 ++-- lib/search/engine.rs | 35 +++++++++++++++++------------------ lib/search/killers.rs | 4 ++-- lib/search/limits.rs | 2 +- lib/search/options.rs | 2 +- lib/uci.rs | 30 +++++++++++++++--------------- tests/perft.rs | 18 +++++++++--------- 16 files changed, 93 insertions(+), 94 deletions(-) diff --git a/benches/search.rs b/benches/search.rs index fcc7f400..bc57f47c 100644 --- a/benches/search.rs +++ b/benches/search.rs @@ -13,7 +13,7 @@ use std::{str::FromStr, thread::available_parallelism}; static POSITION: Evaluator = Evaluator::from_str("6br/1KNp1n1r/2p2p2/P1ppRP2/1kP3pP/3PBB2/PN1P4/8 w - - 0 1").unwrap(); -fn bench(reps: u64, options: Options, limits: Limits) -> Duration { +fn bench(reps: u64, options: &Options, limits: &Limits) -> Duration { let mut time = Duration::ZERO; for _ in 0..reps { @@ -39,22 +39,22 @@ fn crit(c: &mut Criterion) { ..Options::default() })); - for &o in &options { + for o in &options { let depth = Depth::new(12); c.benchmark_group("ttd") .sampling_mode(SamplingMode::Flat) .bench_function(o.threads.to_string(), |b| { - b.iter_custom(|i| bench(i, o, depth.into())) + b.iter_custom(|i| bench(i, o, &depth.into())) }); } - for &o in &options { + for o in &options { let nodes = 300_000; c.benchmark_group("nps") .sampling_mode(SamplingMode::Flat) .throughput(Throughput::Elements(nodes)) .bench_function(o.threads.to_string(), |b| { - b.iter_custom(|i| bench(i, o, nodes.into())) + b.iter_custom(|i| bench(i, o, &nodes.into())) }); } } diff --git a/lib/chess/board.rs b/lib/chess/board.rs index f8c6f2ab..ab7d1324 100644 --- a/lib/chess/board.rs +++ b/lib/chess/board.rs @@ -5,7 +5,7 @@ use std::fmt::{self, Write}; use std::{ops::Index, str::FromStr}; /// The chess board. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[cfg_attr(test, derive(test_strategy::Arbitrary))] #[debug("Board({self})")] pub struct Board { diff --git a/lib/chess/position.rs b/lib/chess/position.rs index 4bed01ea..4832ddb6 100644 --- a/lib/chess/position.rs +++ b/lib/chess/position.rs @@ -159,7 +159,7 @@ impl Moves { /// The current position on the board board. /// /// This type guarantees that it only holds valid positions. -#[derive(Debug, Copy, Clone, Eq)] +#[derive(Debug, Clone, Eq)] #[debug("Position({self})")] pub struct Position { board: Board, @@ -175,11 +175,11 @@ impl Default for Position { let board = Board::default(); Self { - board, zobrist: board.zobrist(), checkers: Default::default(), pinned: Default::default(), history: Default::default(), + board, } } } @@ -320,7 +320,7 @@ impl Position { match NonZeroU32::new(self.zobrist().cast()) { None => 0, hash => { - let history = self.history[self.turn() as usize]; + let history = &self.history[self.turn() as usize]; history.iter().filter(|h| **h == hash).count() } } @@ -664,11 +664,11 @@ impl FromStr for Position { } Ok(Position { - board, checkers, pinned, zobrist: board.zobrist(), history: Default::default(), + board, }) } } @@ -779,7 +779,7 @@ mod tests { #[filter(#pos.moves().any(|ms| ms.is_capture()))] mut pos: Position, #[map(|s: Selector| s.select(#pos.moves().filter(MoveSet::is_capture).flatten()))] m: Move, ) { - let prev = pos; + let prev = pos.clone(); pos.play(m); assert!(pos.material(pos.turn()).len() < prev.material(pos.turn()).len()); } @@ -790,7 +790,7 @@ mod tests { #[map(|s: Selector| s.select(#pos.moves().filter(MoveSet::is_promotion).flatten()))] m: Move, ) { - let prev = pos; + let prev = pos.clone(); pos.play(m); let pawn = Piece::new(Role::Pawn, prev.turn()); assert!(pos.board.by_piece(pawn).len() < prev.board.by_piece(pawn).len()); @@ -819,7 +819,7 @@ mod tests { #[filter(#pos.outcome().is_none())] mut pos: Position, #[map(|s: Selector| s.select(#pos.moves().flatten()))] m: Move, ) { - let prev = pos; + let prev = pos.clone(); pos.play(m); assert_ne!(pos, prev); @@ -880,14 +880,14 @@ mod tests { #[proptest] fn pass_updates_position(#[filter(!#pos.is_check())] mut pos: Position) { - let prev = pos; + let prev = pos.clone(); pos.pass(); assert_ne!(pos, prev); } #[proptest] fn pass_reverts_itself(#[filter(!#pos.is_check() )] mut pos: Position) { - let prev = pos; + let prev = pos.clone(); pos.pass(); pos.pass(); assert_eq!(Vec::from_iter(pos.iter()), Vec::from_iter(prev.iter())); diff --git a/lib/nnue.rs b/lib/nnue.rs index 0e666709..7825f75c 100644 --- a/lib/nnue.rs +++ b/lib/nnue.rs @@ -26,7 +26,7 @@ pub use value::*; /// An [Efficiently Updatable Neural Network][NNUE]. /// /// [NNUE]: https://www.chessprogramming.org/NNUE -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] struct Nnue { ft: Transformer, psqt: Transformer, diff --git a/lib/nnue/evaluator.rs b/lib/nnue/evaluator.rs index 301bb959..5745bf9d 100644 --- a/lib/nnue/evaluator.rs +++ b/lib/nnue/evaluator.rs @@ -12,14 +12,14 @@ use proptest::prelude::*; #[derive(Debug, Display, Clone, Eq, PartialEq, Hash, Deref)] #[debug("Evaluator({self})")] #[display("{pos}")] -pub struct Evaluator { +pub struct Evaluator { #[deref] pos: Position, acc: T, } #[cfg(test)] -impl Arbitrary for Evaluator { +impl Arbitrary for Evaluator { type Parameters = (); type Strategy = BoxedStrategy; @@ -34,7 +34,7 @@ impl Default for Evaluator { } } -impl Evaluator { +impl Evaluator { /// Constructs the evaluator from a [`Position`]. pub fn new(pos: Position) -> Self { let mut acc = T::default(); @@ -146,16 +146,16 @@ impl Evaluator { /// The [`Position`]'s material evaluator. pub fn material(&self) -> Evaluator { Evaluator { - pos: self.pos, - acc: self.acc.0, + pos: self.pos.clone(), + acc: self.acc.0.clone(), } } /// The [`Position`]'s positional evaluator. pub fn positional(&self) -> Evaluator { Evaluator { - pos: self.pos, - acc: self.acc.1, + pos: self.pos.clone(), + acc: self.acc.1.clone(), } } } @@ -194,7 +194,7 @@ mod tests { #[filter(#e.outcome().is_none())] mut e: Evaluator, #[map(|sq: Selector| sq.select(#e.moves().flatten()))] m: Move, ) { - let mut pos = e.pos; + let mut pos = e.pos.clone(); e.play(m); pos.play(m); assert_eq!(e, Evaluator::new(pos)); @@ -202,7 +202,7 @@ mod tests { #[proptest] fn pass_updates_evaluator(#[filter(!#e.is_check())] mut e: Evaluator) { - let mut pos = e.pos; + let mut pos = e.pos.clone(); e.pass(); pos.pass(); assert_eq!(e, Evaluator::new(pos)); diff --git a/lib/nnue/hidden.rs b/lib/nnue/hidden.rs index 6169e629..925f8066 100644 --- a/lib/nnue/hidden.rs +++ b/lib/nnue/hidden.rs @@ -2,7 +2,7 @@ use crate::util::AlignTo64; use derive_more::{Constructor, Shl}; /// The hidden layer. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Constructor)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, Constructor)] #[cfg_attr(test, derive(test_strategy::Arbitrary))] pub struct Hidden { #[cfg_attr(test, map(|b: i8| i32::from(b)))] @@ -14,7 +14,7 @@ impl Hidden { #[doc(hidden)] #[inline(always)] #[cfg(target_feature = "avx2")] - pub unsafe fn avx2(&self, input: [&[i16; N]; 2]) -> i32 { + pub unsafe fn avx2(&self, us: &[i16; N], them: &[i16; N]) -> i32 { const { assert!(N % 128 == 0) }; use std::{arch::x86_64::*, mem::transmute}; @@ -43,7 +43,7 @@ impl Hidden { let mut y = _mm256_setr_epi32(self.bias, 0, 0, 0, 0, 0, 0, 0); - for (w, i) in self.weight.iter().zip(input) { + for (w, i) in self.weight.iter().zip([us, them]) { debug_assert_eq!(w.as_ptr() as usize % 32, 0); debug_assert_eq!(i.as_ptr() as usize % 32, 0); @@ -72,7 +72,7 @@ impl Hidden { #[doc(hidden)] #[inline(always)] #[cfg(target_feature = "ssse3")] - pub unsafe fn sse(&self, input: [&[i16; N]; 2]) -> i32 { + pub unsafe fn sse(&self, us: &[i16; N], them: &[i16; N]) -> i32 { const { assert!(N % 64 == 0) }; use std::{arch::x86_64::*, mem::transmute}; @@ -100,7 +100,7 @@ impl Hidden { let mut y = _mm_setr_epi32(self.bias, 0, 0, 0); - for (w, i) in self.weight.iter().zip(input) { + for (w, i) in self.weight.iter().zip([us, them]) { debug_assert_eq!(w.as_ptr() as usize % 16, 0); debug_assert_eq!(i.as_ptr() as usize % 16, 0); @@ -125,9 +125,9 @@ impl Hidden { #[doc(hidden)] #[inline(always)] - pub fn scalar(&self, input: [&[i16; N]; 2]) -> i32 { + pub fn scalar(&self, us: &[i16; N], them: &[i16; N]) -> i32 { let mut y = self.bias; - for (w, i) in self.weight.iter().zip(input) { + for (w, i) in self.weight.iter().zip([us, them]) { for (&a, &x) in Iterator::zip(w.iter(), i.iter()) { y += a as i32 * (((x as i32).clamp(0, 255).shl(3i32).pow(2) + 16384) >> 15); } @@ -140,21 +140,21 @@ impl Hidden { impl Hidden { /// Transforms the accumulator. #[inline(always)] - pub fn forward(&self, input: [&[i16; N]; 2]) -> i32 { + pub fn forward(&self, us: &[i16; N], them: &[i16; N]) -> i32 { #[cfg(target_feature = "avx2")] unsafe { - self.avx2(input) + self.avx2(us, them) } #[cfg(not(target_feature = "avx2"))] #[cfg(target_feature = "ssse3")] unsafe { - self.sse(input) + self.sse(us, them) } #[cfg(not(target_feature = "avx2"))] #[cfg(not(target_feature = "ssse3"))] - self.scalar(input) + self.scalar(us, them) } } @@ -166,12 +166,12 @@ mod tests { #[cfg(target_feature = "avx2")] #[proptest] fn uses_avx(o: Hidden<128>, i: AlignTo64<[[i16; 128]; 2]>) { - assert_eq!(unsafe { o.avx2([&i[0], &i[1]]) }, o.scalar([&i[0], &i[1]])); + assert_eq!(unsafe { o.avx2(&i[0], &i[1]) }, o.scalar(&i[0], &i[1])); } #[cfg(target_feature = "ssse3")] #[proptest] fn uses_sse(o: Hidden<128>, i: AlignTo64<[[i16; 128]; 2]>) { - assert_eq!(unsafe { o.sse([&i[0], &i[1]]) }, o.scalar([&i[0], &i[1]])); + assert_eq!(unsafe { o.sse(&i[0], &i[1]) }, o.scalar(&i[0], &i[1])); } } diff --git a/lib/nnue/material.rs b/lib/nnue/material.rs index 037c2285..f2c6c8c8 100644 --- a/lib/nnue/material.rs +++ b/lib/nnue/material.rs @@ -4,7 +4,7 @@ use crate::util::{AlignTo64, Assume}; use derive_more::Debug; /// An accumulator for the psqt transformer. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[cfg_attr(test, derive(test_strategy::Arbitrary))] #[debug("Positional")] pub struct Material( @@ -64,7 +64,7 @@ mod tests { #[proptest] fn remove_reverses_add(a: Material, c: Color, f: Feature) { - let mut b = a; + let mut b = a.clone(); b.add(c, f); b.remove(c, f); assert_eq!(a, b); @@ -72,7 +72,7 @@ mod tests { #[proptest] fn replace_reverses_itself(a: Material, c: Color, x: Feature, y: Feature) { - let mut b = a; + let mut b = a.clone(); b.replace(c, x, y); b.replace(c, y, x); assert_eq!(a, b); diff --git a/lib/nnue/positional.rs b/lib/nnue/positional.rs index 60f5c1a7..869ff9fa 100644 --- a/lib/nnue/positional.rs +++ b/lib/nnue/positional.rs @@ -4,7 +4,7 @@ use crate::util::AlignTo64; use derive_more::Debug; /// An accumulator for the feature transformer. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[cfg_attr(test, derive(test_strategy::Arbitrary))] #[debug("Positional")] pub struct Positional( @@ -44,7 +44,7 @@ impl Accumulator for Positional { #[inline(always)] fn evaluate(&self, turn: Color, phase: usize) -> i32 { - Nnue::hidden(phase).forward([&self.0[turn as usize], &self.0[turn.flip() as usize]]) / 40 + Nnue::hidden(phase).forward(&self.0[turn as usize], &self.0[turn.flip() as usize]) / 40 } } @@ -57,7 +57,7 @@ mod tests { #[proptest] fn remove_reverses_add(a: Positional, c: Color, f: Feature) { - let mut b = a; + let mut b = a.clone(); b.add(c, f); b.remove(c, f); assert_eq!(a, b); @@ -65,7 +65,7 @@ mod tests { #[proptest] fn replace_reverses_itself(a: Positional, c: Color, x: Feature, y: Feature) { - let mut b = a; + let mut b = a.clone(); b.replace(c, x, y); b.replace(c, y, x); assert_eq!(a, b); diff --git a/lib/nnue/transformer.rs b/lib/nnue/transformer.rs index c4587685..48ccef00 100644 --- a/lib/nnue/transformer.rs +++ b/lib/nnue/transformer.rs @@ -10,7 +10,7 @@ use proptest::{prelude::*, sample::Index}; use std::ops::Range; /// A feature transformer. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Constructor)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, Constructor)] pub struct Transformer { pub(super) bias: AlignTo64<[T; N]>, pub(super) weight: AlignTo64<[[T; N]; Feature::LEN]>, diff --git a/lib/search/driver.rs b/lib/search/driver.rs index 3cf23a83..6914e527 100644 --- a/lib/search/driver.rs +++ b/lib/search/driver.rs @@ -5,7 +5,7 @@ use rayon::{prelude::*, ThreadPool, ThreadPoolBuilder}; use std::sync::atomic::{AtomicU64, Ordering}; /// Whether the search should be [`Interrupted`] or exited early. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From)] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From)] pub enum ControlFlow { Interrupt(Interrupted), Break, @@ -68,7 +68,7 @@ impl Driver { } } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deref)] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deref)] #[cfg_attr(test, derive(test_strategy::Arbitrary))] struct IndexedPv(#[deref] Pv, u32); diff --git a/lib/search/engine.rs b/lib/search/engine.rs index 3b00dfac..c51cb852 100644 --- a/lib/search/engine.rs +++ b/lib/search/engine.rs @@ -32,11 +32,11 @@ impl Engine { /// Initializes the engine with the default [`Options`]. pub fn new() -> Self { - Self::with_options(Options::default()) + Self::with_options(&Options::default()) } /// Initializes the engine with the given [`Options`]. - pub fn with_options(options: Options) -> Self { + pub fn with_options(options: &Options) -> Self { Engine { driver: Driver::new(options.threads), tt: TranspositionTable::new(options.hash), @@ -289,7 +289,7 @@ impl Engine { pos: &Evaluator, limit: Depth, nodes: u64, - time: Range, + time: &Range, interrupter: &Trigger, ) -> Pv { let ctrl = Control::Limited(Counter::new(nodes), Timer::new(time.end), interrupter); @@ -349,23 +349,22 @@ impl Engine { pv } - fn time_to_search(&self, pos: &Evaluator, limits: Limits) -> Range { + fn time_to_search(&self, pos: &Evaluator, limits: &Limits) -> Range { let (clock, inc) = match limits { Limits::Clock(c, i) => (c, i), _ => return limits.time()..limits.time(), }; - let time_left = clock.saturating_sub(inc); + let time_left = clock.saturating_sub(*inc); let moves_left = 280 / pos.fullmoves().get().min(40); let time_per_move = inc.saturating_add(time_left / moves_left); time_per_move / 2..time_per_move } /// Searches for the [principal variation][`Pv`]. - pub fn search(&mut self, pos: &Evaluator, limits: Limits, interrupter: &Trigger) -> Pv { + pub fn search(&mut self, pos: &Evaluator, limits: &Limits, interrupter: &Trigger) -> Pv { let time = self.time_to_search(pos, limits); - let (depth, nodes) = (limits.depth(), limits.nodes()); - self.aw(pos, depth, nodes, time, interrupter) + self.aw(pos, limits.depth(), limits.nodes(), &time, interrupter) } } @@ -415,7 +414,7 @@ mod tests { #[proptest] fn hash_is_an_upper_limit_for_table_size(o: Options) { - let e = Engine::with_options(o); + let e = Engine::with_options(&o); prop_assume!(e.tt.capacity() > 1); assert!(e.tt.size() <= o.hash); } @@ -604,8 +603,8 @@ mod tests { d: Depth, #[filter(#p >= 0)] p: Ply, ) { - let x = Engine::with_options(x); - let y = Engine::with_options(y); + let x = Engine::with_options(&x); + let y = Engine::with_options(&y); let ctrl = Control::Unlimited; @@ -622,7 +621,7 @@ mod tests { #[filter(#d > 1)] d: Depth, ) { assert_eq!( - e.search(&pos, Limits::Depth(d), &Trigger::armed()).score(), + e.search(&pos, &Limits::Depth(d), &Trigger::armed()).score(), e.fw(&pos, d, Ply::new(0), &Control::Unlimited)?.score() ); } @@ -630,8 +629,8 @@ mod tests { #[proptest] fn search_is_stable(mut e: Engine, pos: Evaluator, d: Depth) { assert_eq!( - e.search(&pos, Limits::Depth(d), &Trigger::armed()).score(), - e.search(&pos, Limits::Depth(d), &Trigger::armed()).score() + e.search(&pos, &Limits::Depth(d), &Trigger::armed()).score(), + e.search(&pos, &Limits::Depth(d), &Trigger::armed()).score() ); } @@ -644,7 +643,7 @@ mod tests { let timer = Instant::now(); let trigger = Trigger::armed(); let limits = Limits::Time(Duration::from_millis(ms.into())); - e.search(&pos, limits, &trigger); + e.search(&pos, &limits, &trigger); assert!(timer.elapsed() < Duration::from_secs(1)); } @@ -654,7 +653,7 @@ mod tests { #[filter(#pos.outcome().is_none())] pos: Evaluator, ) { let limits = Duration::ZERO.into(); - assert_ne!(e.search(&pos, limits, &Trigger::armed()).best(), None); + assert_ne!(e.search(&pos, &limits, &Trigger::armed()).best(), None); } #[proptest] @@ -663,7 +662,7 @@ mod tests { #[filter(#pos.outcome().is_none())] pos: Evaluator, ) { let limits = Depth::lower().into(); - assert_ne!(e.search(&pos, limits, &Trigger::armed()).best(), None); + assert_ne!(e.search(&pos, &limits, &Trigger::armed()).best(), None); } #[proptest] @@ -672,6 +671,6 @@ mod tests { #[filter(#pos.outcome().is_none())] pos: Evaluator, ) { let limits = Limits::None; - assert_ne!(e.search(&pos, limits, &Trigger::disarmed()).best(), None); + assert_ne!(e.search(&pos, &limits, &Trigger::disarmed()).best(), None); } } diff --git a/lib/search/killers.rs b/lib/search/killers.rs index f0b624ac..a26f806e 100644 --- a/lib/search/killers.rs +++ b/lib/search/killers.rs @@ -4,7 +4,7 @@ use crate::{search::Ply, util::Integer}; /// A set of [killer moves] indexed by [`Ply`] and side to move. /// /// [killer moves]: https://www.chessprogramming.org/Killer_Move -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[cfg_attr(test, derive(test_strategy::Arbitrary))] pub struct Killers([[[Option; 2]; 2]; P]); @@ -85,7 +85,7 @@ mod tests { c: Color, m: Move, ) { - let prev = ks; + let prev = ks.clone(); ks.insert(p, c, m); assert_eq!(ks, prev); } diff --git a/lib/search/limits.rs b/lib/search/limits.rs index 7b133cad..a20012a4 100644 --- a/lib/search/limits.rs +++ b/lib/search/limits.rs @@ -3,7 +3,7 @@ use derive_more::From; use std::time::Duration; /// Configuration for search limits. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, From)] +#[derive(Debug, Default, Clone, Eq, PartialEq, From)] pub enum Limits { /// Unlimited search. #[default] diff --git a/lib/search/options.rs b/lib/search/options.rs index a845891e..2192713d 100644 --- a/lib/search/options.rs +++ b/lib/search/options.rs @@ -120,7 +120,7 @@ impl FromStr for ThreadCount { } /// Configuration for adversarial search algorithms. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Default, Clone, Eq, PartialEq)] #[cfg_attr(test, derive(test_strategy::Arbitrary))] pub struct Options { /// The size of the transposition table in bytes. diff --git a/lib/uci.rs b/lib/uci.rs index fea4e48a..07fba8e1 100644 --- a/lib/uci.rs +++ b/lib/uci.rs @@ -107,7 +107,7 @@ impl + Unpin, O: Sink + Unpin> Uci { self.moves.push(UciMove::from(m)); } - async fn go(&mut self, limits: Limits) -> Result<(), O::Error> { + async fn go(&mut self, limits: &Limits) -> Result<(), O::Error> { let interrupter = Trigger::armed(); let mut search = @@ -141,7 +141,7 @@ impl + Unpin, O: Sink + Unpin> Uci { Ok(()) } - async fn bench(&mut self, limits: Limits) -> Result<(), O::Error> { + async fn bench(&mut self, limits: &Limits) -> Result<(), O::Error> { let interrupter = Trigger::armed(); let timer = Instant::now(); self.engine.search(&self.position, limits, &interrupter); @@ -151,7 +151,7 @@ impl + Unpin, O: Sink + Unpin> Uci { Limits::Depth(d) => format!("info time {millis} depth {}", d.get()), Limits::Nodes(nodes) => format!( "info time {millis} nodes {nodes} nps {}", - nodes as u128 * 1000 / millis + *nodes as u128 * 1000 / millis ), _ => return Ok(()), }; @@ -218,7 +218,7 @@ impl + Unpin, O: Sink + Unpin> Uci { (Ok(t), Ok(i)) => { let t = Duration::from_millis(t); let i = Duration::from_millis(i); - self.go(Limits::Clock(t, i)).await?; + self.go(&Limits::Clock(t, i)).await?; } } @@ -227,7 +227,7 @@ impl + Unpin, O: Sink + Unpin> Uci { ["go", "depth", depth] => { match depth.parse::() { - Ok(d) => self.go(Limits::Depth(d.saturate())).await?, + Ok(d) => self.go(&Limits::Depth(d.saturate())).await?, Err(e) => eprintln!("{e}"), } @@ -236,7 +236,7 @@ impl + Unpin, O: Sink + Unpin> Uci { ["go", "nodes", nodes] => { match nodes.parse::() { - Ok(n) => self.go(n.into()).await?, + Ok(n) => self.go(&n.into()).await?, Err(e) => eprintln!("{e}"), } @@ -245,7 +245,7 @@ impl + Unpin, O: Sink + Unpin> Uci { ["go", "movetime", time] => { match time.parse() { - Ok(ms) => self.go(Duration::from_millis(ms).into()).await?, + Ok(ms) => self.go(&Duration::from_millis(ms).into()).await?, Err(e) => eprintln!("{e}"), } @@ -253,13 +253,13 @@ impl + Unpin, O: Sink + Unpin> Uci { } ["go"] | ["go", "infinite"] => { - self.go(Limits::None).await?; + self.go(&Limits::None).await?; Ok(true) } ["bench", "depth", depth] => { match depth.parse::() { - Ok(d) => self.bench(Limits::Depth(d.saturate())).await?, + Ok(d) => self.bench(&Limits::Depth(d.saturate())).await?, Err(e) => eprintln!("{e}"), } @@ -268,7 +268,7 @@ impl + Unpin, O: Sink + Unpin> Uci { ["bench", "nodes", nodes] => { match nodes.parse::() { - Ok(n) => self.bench(n.into()).await?, + Ok(n) => self.bench(&n.into()).await?, Err(e) => eprintln!("{e}"), } @@ -314,7 +314,7 @@ impl + Unpin, O: Sink + Unpin> Uci { } ["ucinewgame"] => { - self.engine = Engine::with_options(self.options); + self.engine = Engine::with_options(&self.options); self.position = Evaluator::default(); self.moves.clear(); Ok(true) @@ -332,7 +332,7 @@ impl + Unpin, O: Sink + Unpin> Uci { Ok(h) => { if h != self.options.hash { self.options.hash = h; - self.engine = Engine::with_options(self.options); + self.engine = Engine::with_options(&self.options); } } } @@ -347,7 +347,7 @@ impl + Unpin, O: Sink + Unpin> Uci { Ok(t) => { if t != self.options.threads { self.options.threads = t; - self.engine = Engine::with_options(self.options); + self.engine = Engine::with_options(&self.options); } } }; @@ -639,7 +639,7 @@ mod tests { #[any(StaticStream::new([format!("setoption name Hash value {}", #_s)]))] mut uci: MockUci, #[filter(#_s.trim().parse::().is_err())] _s: String, ) { - let o = uci.options; + let o = uci.options.clone(); assert_eq!(block_on(uci.run()), Ok(())); assert_eq!(uci.options, o); assert!(uci.output.is_empty()); @@ -662,7 +662,7 @@ mod tests { mut uci: MockUci, #[filter(#_s.trim().parse::().is_err())] _s: String, ) { - let o = uci.options; + let o = uci.options.clone(); assert_eq!(block_on(uci.run()), Ok(())); assert_eq!(uci.options, o); assert!(uci.output.is_empty()); diff --git a/tests/perft.rs b/tests/perft.rs index 56a473ad..78b5d208 100644 --- a/tests/perft.rs +++ b/tests/perft.rs @@ -2,7 +2,7 @@ use lib::chess::Position; use rayon::prelude::*; use test_strategy::proptest; -fn perft(pos: Position, depth: u8) -> usize { +fn perft(pos: &Position, depth: u8) -> usize { match depth { 0 => 1, 1 => pos.moves().flatten().count(), @@ -11,9 +11,9 @@ fn perft(pos: Position, depth: u8) -> usize { .flatten() .par_bridge() .map(|m| { - let mut next = pos; + let mut next = pos.clone(); next.play(m); - perft(next, d - 1) + perft(&next, d - 1) }) .sum(), } @@ -23,25 +23,25 @@ fn perft(pos: Position, depth: u8) -> usize { #[proptest(cases = 1)] fn perft_expands_expected_number_of_nodes() { // https://www.chessprogramming.org/Perft_Results#Initial_Position - assert_eq!(perft(Position::default(), 5), 4865609); + assert_eq!(perft(&Position::default(), 5), 4865609); // https://www.chessprogramming.org/Perft_Results#Position_2 let pos = "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1".parse()?; - assert_eq!(perft(pos, 5), 193690690); + assert_eq!(perft(&pos, 5), 193690690); // https://www.chessprogramming.org/Perft_Results#Position_3 let pos = "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1".parse()?; - assert_eq!(perft(pos, 5), 674624); + assert_eq!(perft(&pos, 5), 674624); // https://www.chessprogramming.org/Perft_Results#Position_4 let pos = "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1".parse()?; - assert_eq!(perft(pos, 5), 15833292); + assert_eq!(perft(&pos, 5), 15833292); // https://www.chessprogramming.org/Perft_Results#Position_5 let pos = "rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8".parse()?; - assert_eq!(perft(pos, 5), 89941194); + assert_eq!(perft(&pos, 5), 89941194); // https://www.chessprogramming.org/Perft_Results#Position_6 let pos = "r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10".parse()?; - assert_eq!(perft(pos, 5), 164075551); + assert_eq!(perft(&pos, 5), 164075551); }