diff --git a/benches/future_children.rs b/benches/future_children.rs index b01527a..b2e2ad6 100644 --- a/benches/future_children.rs +++ b/benches/future_children.rs @@ -12,6 +12,7 @@ fn extend_layers_no_pruning(depth: usize, arena_size: usize) -> usize { up_to_minus: 4, max_arena_size: arena_size, do_not_prune: true, + print: false, }; let mut fut = FutureMoves::new(Piece::Black, config); fut.set_root_from_board(Board::new().starting_pos()); diff --git a/src/elo.rs b/src/elo.rs index cc5f652..5349df8 100644 --- a/src/elo.rs +++ b/src/elo.rs @@ -11,38 +11,131 @@ use skillratings::{ }; 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: 5_000_000, + do_not_prune: false, + print: false, + }; + let mut arena = PlayerArena::new(vec![ ( "RandomAgent".into(), Box::new(|piece| Box::new(RandomAgent::new(piece))), + 1, ), ( - "ComplexAgentBasic".into(), + "ComplexAgent100K".into(), Box::new(|piece| { Box::new(ComplexAgent::new( piece, FutureMoveConfig { - max_depth: 20, - min_arena_depth: 14, - top_k_children: 2, - up_to_minus: 10, max_arena_size: 100_000, - do_not_prune: false, - print: false, + ..FMV_BASE }, )) }), + 1, + ), + ( + "ComplexAgent500K".into(), + Box::new(|piece| { + Box::new(ComplexAgent::new( + piece, + FutureMoveConfig { + max_arena_size: 500_000, + ..FMV_BASE + }, + )) + }), + 1, + ), + ( + "ComplexAgent1M".into(), + Box::new(|piece| { + Box::new(ComplexAgent::new( + piece, + FutureMoveConfig { + max_arena_size: 1_000_000, + ..FMV_BASE + }, + )) + }), + 1, + ), + // NO PRUNING : + ( + "ComplexAgent100K_NOPRUNE".into(), + Box::new(|piece| { + Box::new(ComplexAgent::new( + piece, + FutureMoveConfig { + max_arena_size: 100_000, + do_not_prune: true, + ..FMV_BASE + }, + )) + }), + 1, + ), + ( + "ComplexAgent500K_NOPRUNE".into(), + Box::new(|piece| { + Box::new(ComplexAgent::new( + piece, + FutureMoveConfig { + max_arena_size: 500_000, + do_not_prune: true, + ..FMV_BASE + }, + )) + }), + 1, + ), + ( + "ComplexAgent1M_NOPRUNE".into(), + Box::new(|piece| { + Box::new(ComplexAgent::new( + piece, + FutureMoveConfig { + max_arena_size: 1_000_000, + do_not_prune: true, + ..FMV_BASE + }, + )) + }), + 1, ), ]); - for _ in 0..10 { - arena.play_two(0, 1); + + // for _ in 0..100 { + // arena.prop_arena(); + // } + + for _ in 0..20 { + arena.play_all_against(0); } + // for _ in 0..2 { + // arena.play_two(1, 2); + // } + println!("{}", arena); } pub struct PlayerArena { - players: Vec<(String, Box Box>, EloRating)>, + /// Name, Creator, Elo, freq (mod) + players: Vec<( + String, + Box Box>, + EloRating, + usize, + )>, + + freq_map: Vec, } impl std::fmt::Display for PlayerArena { @@ -64,23 +157,68 @@ impl std::fmt::Display for PlayerArena { } impl PlayerArena { - pub fn new(players: Vec<(String, Box Box>)>) -> Self { + pub fn new(players: Vec<(String, Box Box>, usize)>) -> Self { + let len = players.len(); Self { players: players .into_iter() .zip([EloRating::new()].into_iter().cycle()) - .map(|((a, b), c)| (a, b, c)) + .map(|((a, b, d), c)| (a, b, c, d)) .collect(), + freq_map: [0].repeat(len).to_vec(), + } + } + + fn play_all_against(&mut self, i: usize) { + for j in 0..self.players.len() { + if i == j { + continue; + } + self.freq_map[i] += 1; + self.freq_map[j] += 1; + if self.freq_map[i] % self.players[i].3 != 0 { + continue; + } + + if self.freq_map[j] % self.players[j].3 != 0 { + continue; + } + + self.play_two(i, j); + } + } + + fn prop_arena(&mut self) { + for i in 0..self.players.len() { + self.play_all_against(i); } } fn play_two(&mut self, player1: usize, player2: usize) { - let result = GameInner::new( - self.players[player1].1(Piece::Black), - self.players[player2].1(Piece::White), - false, - ) - .loop_until_result(); + println!( + "{} vs {}...", + self.players[player1].0, self.players[player2].0 + ); + + let (np1, np2) = Self::play_two_inner( + &self.players[player1].1, + &self.players[player2].1, + &self.players[player1].2, + &self.players[player2].2, + ); + self.players[player1].2 = np1; + self.players[player2].2 = np2; + } + + fn play_two_inner( + player_1_fn: &Box Box>, + player_2_fn: &Box Box>, + player_1_elo: &EloRating, + player_2_elo: &EloRating, + ) -> (EloRating, EloRating) { + let result = GameInner::new(player_1_fn(Piece::Black), player_2_fn(Piece::White), false) + .loop_until_result(); + let outcome = match result { Winner::Player(piece) => match piece { Piece::Black => Outcomes::WIN, @@ -89,13 +227,7 @@ impl PlayerArena { Winner::Tie => Outcomes::DRAW, Winner::None => panic!("somehow met None"), }; - 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; + + elo(player_1_elo, player_2_elo, &outcome, &EloConfig::new()) } } diff --git a/src/game.rs b/src/game.rs index 44bd168..c3c2864 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,7 +1,6 @@ use crate::{ agent::Agent, game_inner::GameInner, - repr::{Board, Piece, Winner}, }; pub struct Game {