diff --git a/src/elo.rs b/src/elo.rs index f4e4531..18e45f5 100644 --- a/src/elo.rs +++ b/src/elo.rs @@ -6,6 +6,7 @@ use crate::{ repr::{Board, Piece, Winner}, }; use indicatif::{ParallelProgressIterator, ProgressStyle}; +use rand::seq::SliceRandom; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use skillratings::{ elo::{elo, EloConfig, EloRating}, @@ -24,30 +25,49 @@ pub fn run() { children_eval_method: ChildrenEvalMethod::Average, }; - let vec: Vec<(String, Box Box>)> = (5..=6) - .flat_map(move |d| { - // -> (String, Box Box>) - [true, false].map(move |p| -> (String, Box Box>) { - ( - format!("ComplexAgentD{}P{}", d, p), - Box::new(move |piece| { - Box::new(ComplexAgent::new( - piece, - FutureMoveConfig { - max_depth: d, - do_not_prune: p, - ..FMV_BASE - }, - )) - }), - ) + let configs = (1..=6) + .map(move |d| FutureMoveConfig { + max_depth: d, + ..FMV_BASE + }) + .flat_map(move |prev_c| { + // create children which enable, and disable pruning + [true, false].map(move |do_not_prune| FutureMoveConfig { + do_not_prune, + ..prev_c }) }) + .flat_map(move |prev_c| { + if prev_c.do_not_prune { + // do not bother making configs where do_not_prune is true + // as top_k_children does nothing when pruning is skipped + return vec![prev_c]; + } + + // different values of top_k_children + [1, 2, 3] + .map(move |top_k_children| FutureMoveConfig { + top_k_children, + ..prev_c + }) + .to_vec() + }); + + let vec: Vec<(String, Box Box>)> = configs + .into_iter() + .map( + move |config| -> (String, Box Box>) { + ( + format!("{}", config), + Box::new(move |piece| Box::new(ComplexAgent::new(piece, config))), + ) + }, + ) .collect(); let mut arena = PlayerArena::new(vec); - arena.prop_arena(10); + arena.prop_arena(1); println!("{}", arena); } @@ -87,7 +107,7 @@ impl PlayerArena { } fn play(&mut self, pairs: &[(usize, usize)]) { - pairs + let mut created_pairs = pairs .iter() .map(|&(i, j)| { ( @@ -95,13 +115,17 @@ impl PlayerArena { Self::create_agents(&self.players[i].1, &self.players[j].1), ) }) - .collect::>() - // after the agents are created, we can multithread the games being played + .collect::>(); + + // shuffle for consistency + created_pairs.shuffle(&mut rand::rng()); + + // after the agents are created, we can multithread the games being played + created_pairs .into_par_iter() .progress_with_style( ProgressStyle::with_template("[{elapsed_precise}] {pos:>7}/{len:7} ETA: {eta}") - .expect("invalid ProgressStyle") - .progress_chars("##-"), + .expect("invalid ProgressStyle"), ) .map(|((i, j), (p1, p2))| (i, j, Self::play_two_inner(p1, p2))) .collect::>() diff --git a/src/logic/future_moves.rs b/src/logic/future_moves.rs index 7bd896b..35c3f31 100644 --- a/src/logic/future_moves.rs +++ b/src/logic/future_moves.rs @@ -21,6 +21,7 @@ pub struct FutureMoves { config: FutureMoveConfig, } +#[derive(Copy, Clone)] pub struct FutureMoveConfig { /// Max depth of that we should try and traverse pub max_depth: usize, @@ -46,6 +47,24 @@ pub struct FutureMoveConfig { pub children_eval_method: ChildrenEvalMethod, } +impl std::fmt::Display for FutureMoveConfig { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "D{} ", self.max_depth)?; + write!(f, "MD{} ", self.min_arena_depth)?; + write!(f, "K{} ", self.top_k_children)?; + write!(f, "UM{} ", self.up_to_minus)?; + if self.max_arena_size == usize::MAX { + write!(f, "SMAX ")?; + } else { + write!(f, "S{} ", self.max_arena_size)?; + } + + write!(f, "P{} ", !self.do_not_prune)?; + write!(f, "C{:?}", self.children_eval_method)?; + Ok(()) + } +} + #[derive(Debug, Clone, Copy)] pub enum ChildrenEvalMethod { /// Best (by far) strat compared to Max or Min