use crate::{ agent::Agent, complexagent::ComplexAgent, game_inner::GameInner, logic::{ChildrenEvalMethod, FutureMoveConfig}, repr::{Board, Piece, Winner}, }; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use skillratings::{ elo::{elo, EloConfig, EloRating}, Outcomes, Rating, }; pub fn run() { const FMV_BASE: FutureMoveConfig = FutureMoveConfig { max_depth: 20, min_arena_depth: 14, top_k_children: 2, up_to_minus: 10, max_arena_size: usize::MAX, do_not_prune: true, print: false, children_eval_method: ChildrenEvalMethod::Max, }; let vec: Vec<(String, Box Box>)> = (1..=6) .flat_map(|d| { [ ChildrenEvalMethod::Average, // ChildrenEvalMethod::Max, // ChildrenEvalMethod::Min, ] .into_iter() .map(move |m| -> (String, Box Box>) { ( format!("ComplexAgentD{}{:?}", d, m), Box::new(move |piece| { Box::new(ComplexAgent::new( piece, FutureMoveConfig { max_depth: d, children_eval_method: m, ..FMV_BASE }, )) }), ) }) }) .collect(); let mut arena = PlayerArena::new(vec); arena.prop_arena(300); println!("{}", arena); } pub struct PlayerArena { /// Name, Creator Function, Elo players: Vec<(String, Box Box>, EloRating)>, } impl std::fmt::Display for PlayerArena { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut players_i: Vec = (0..self.players.len()).collect(); players_i.sort_by_key(|&i| -(self.players[i].2.rating() * 100.0) as i64); for i in players_i { writeln!( f, "({:.2}): {}", self.players[i].2.rating(), self.players[i].0 )?; } Ok(()) } } impl PlayerArena { pub fn new(players: Vec<(String, Box Box>)>) -> Self { Self { players: players .into_iter() .zip([EloRating::new()].into_iter().cycle()) .map(|((a, b), c)| (a, b, c)) .collect(), } } fn play(&mut self, pairs: &[(usize, usize)]) { pairs .iter() .map(|&(i, j)| { ( (i, j), Self::create_agents(&self.players[i].1, &self.players[j].1), ) }) .collect::>() // after the agents are created, we can multithread the games being played .into_par_iter() .map(|((i, j), (p1, p2))| (i, j, Self::play_two_inner(p1, p2))) .collect::>() // collect and process the outcomes of all the games .into_iter() .for_each(|(i, j, o)| self.process_outcome(i, j, &o)); } fn prop_arena(&mut self, n: usize) { self.play( &(0..self.players.len()) .flat_map(|i| { (0..self.players.len()) .map(move |j| (i, j)) .filter(|(i, j)| i != j) .collect::>() }) .collect::>() .repeat(n), ); } fn process_outcome(&mut self, player1: usize, player2: usize, outcome: &Outcomes) { let (np1, np2) = elo( &self.players[player1].2, &self.players[player2].2, outcome, &EloConfig::new(), ); self.players[player1].2 = np1; self.players[player2].2 = np2; } fn create_agents( player_1_fn: &dyn Fn(Piece) -> Box, player_2_fn: &dyn Fn(Piece) -> Box, ) -> (Box, Box) { (player_1_fn(Piece::Black), player_2_fn(Piece::White)) } fn play_two_inner(player_1: Box, player_2: Box) -> Outcomes { let result = GameInner::new( player_1, player_2, false, Board::random(rand::random_range(3..8)), ) .loop_until_result(); match result { Winner::Player(piece) => match piece { Piece::Black => Outcomes::WIN, Piece::White => Outcomes::LOSS, }, Winner::Tie => Outcomes::DRAW, Winner::None => panic!("somehow met None"), } } }