diff --git a/benches/future_children.rs b/benches/future_children.rs index 9c76387..bed765b 100644 --- a/benches/future_children.rs +++ b/benches/future_children.rs @@ -1,6 +1,6 @@ use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; use othello::{ - logic::{ChildrenEvalMethod, FutureMoveConfig, FutureMoves}, + logic::{FutureMoveConfig, FutureMoves}, repr::{Board, Piece}, }; @@ -13,7 +13,7 @@ fn extend_layers_no_pruning(depth: usize) -> usize { max_arena_size: usize::MAX, do_prune: false, print: false, - children_eval_method: ChildrenEvalMethod::AverageDivDepth, + children_eval_method: Default::default(), }; let mut fut = FutureMoves::new(Piece::Black, config); fut.update_from_board(&Board::STARTING_POSITION); diff --git a/src/allocs.rs b/src/allocs.rs index 0d7105c..0f5e4f3 100644 --- a/src/allocs.rs +++ b/src/allocs.rs @@ -1,5 +1,5 @@ use crate::{ - logic::{ChildrenEvalMethod, FutureMoveConfig, FutureMoves}, + logic::{FutureMoveConfig, FutureMoves}, repr::{Board, Piece, Winner}, }; use allocative::FlameGraphBuilder; @@ -18,7 +18,7 @@ pub fn run() { max_arena_size: 100_000_000, do_prune: true, print: true, - children_eval_method: ChildrenEvalMethod::AverageDivDepth, + children_eval_method: Default::default(), }, ); diff --git a/src/elo.rs b/src/elo.rs index e8106bf..bb6cdbd 100644 --- a/src/elo.rs +++ b/src/elo.rs @@ -1,5 +1,5 @@ use crate::{ - agent::Agent, + agent::{Agent, RandomAgent}, complexagent::ComplexAgent, game_inner::GameInner, logic::{ChildrenEvalMethod, FutureMoveConfig}, @@ -18,7 +18,7 @@ type AgentMaker = Box Box>; #[allow(dead_code)] pub fn run() { - const FMV_BASE: FutureMoveConfig = FutureMoveConfig { + let fmv_base = FutureMoveConfig { max_depth: 20, min_arena_depth: 14, top_k_children: 2, @@ -26,26 +26,26 @@ pub fn run() { max_arena_size: usize::MAX, do_prune: false, print: false, - children_eval_method: ChildrenEvalMethod::AverageDivDepth, + children_eval_method: Default::default(), }; let configs = [6] .into_iter() .map(move |d| FutureMoveConfig { max_depth: d, - ..FMV_BASE + ..fmv_base }) .flat_map(move |prev_c| { // create children which enable, and disable pruning - [true, false].map(move |do_prune| FutureMoveConfig { do_prune, ..prev_c }) - }) - .filter(move |move_c| { - if move_c.do_prune { - move_c.max_depth >= 8 - } else { - move_c.max_depth < 8 - } + [false].map(move |do_prune| FutureMoveConfig { do_prune, ..prev_c }) }) + // .filter(move |move_c| { + // if move_c.do_prune { + // move_c.max_depth >= 8 + // } else { + // move_c.max_depth < 8 + // } + // }) // .flat_map(move |prev_c| { // [ // ChildrenEvalMethod::Average, @@ -64,12 +64,23 @@ pub fn run() { } // different values of top_k_children - [1, 2, 3] - .map(move |top_k_children| FutureMoveConfig { - top_k_children, - ..prev_c - }) - .to_vec() + [2].map(move |top_k_children| FutureMoveConfig { + top_k_children, + ..prev_c + }) + .to_vec() + }) + .flat_map(move |prev_c| { + [ + ChildrenEvalMethod::Average, + ChildrenEvalMethod::AverageDivDepth, + ChildrenEvalMethod::MinAvgDivDepth, + ChildrenEvalMethod::MinMax, + ] + .map(move |method| FutureMoveConfig { + children_eval_method: method, + ..prev_c + }) }) .flat_map(move |prev_c| { if !prev_c.do_prune { @@ -79,8 +90,7 @@ pub fn run() { // different values to be subtracted from max_depth // to become min_arena_depth - [1, 2, 3] - .into_iter() + [2].into_iter() .filter(|&x| x <= prev_c.max_depth) .map(move |ad_offset| FutureMoveConfig { min_arena_depth: prev_c.max_depth - ad_offset, @@ -95,8 +105,7 @@ pub fn run() { } // different values of up_to_minus - [prev_c.max_depth, 1, 2, 3] - .into_iter() + [3].into_iter() .filter(|&x| x <= prev_c.max_depth) .map(move |up_to_minus| FutureMoveConfig { up_to_minus, @@ -105,7 +114,7 @@ pub fn run() { .collect() }); - let vec: Vec<(String, AgentMaker)> = configs + let mut vec: Vec<(String, AgentMaker)> = configs .into_iter() .map(move |config| -> (String, AgentMaker) { ( @@ -114,6 +123,10 @@ pub fn run() { ) }) .collect(); + vec.push(( + "RandomAgent".to_string(), + Box::new(move |piece| Box::new(RandomAgent::new(piece))), + )); let mut arena = PlayerArena::new(vec); diff --git a/src/logic/future_moves.rs b/src/logic/future_moves.rs index 86db507..07aed66 100644 --- a/src/logic/future_moves.rs +++ b/src/logic/future_moves.rs @@ -79,10 +79,18 @@ impl std::fmt::Display for FutureMoveConfig { #[allow(dead_code)] pub enum ChildrenEvalMethod { Average, - /// AverageDivDepth gives the agent a sense of - /// time when it comes to how far away a potential win or gain - /// is. This performs much better in the Elo Arena than `Average` AverageDivDepth, + + MinAvgDivDepth, + + /// Best so far? + MinMax, +} + +impl Default for ChildrenEvalMethod { + fn default() -> Self { + Self::MinMax + } } impl FutureMoves { @@ -287,6 +295,31 @@ impl FutureMoves { .sum::() .checked_div(self.arena[idx].children.len() as i32) .and_then(|x| x.checked_div(depth as i32)), + ChildrenEvalMethod::MinAvgDivDepth => { + if self.arena[idx].color == self.agent_color { + // get best (for the adversary) enemy play + // this assumes the adversary is playing optimally + + children_values.into_iter().min() + } else { + children_values + .into_iter() + .sum::() + .checked_div(self.arena[idx].children.len() as i32) + .and_then(|x| x.checked_div(depth as i32)) + } + } + + ChildrenEvalMethod::MinMax => { + if self.arena[idx].color == self.agent_color { + // get best (for the adversary) enemy play + // this assumes the adversary is playing optimally + + children_values.into_iter().min() + } else { + children_values.into_iter().max() + } + } } .unwrap_or(0); @@ -571,22 +604,26 @@ impl FutureMoves { #[cfg(test)] mod tests { + use std::sync::LazyLock; + use super::*; - const FUTURE_MOVES_CONFIG: FutureMoveConfig = FutureMoveConfig { - max_depth: 3, // we want great-grand children for traversing moves - min_arena_depth: 0, - top_k_children: 1, - up_to_minus: 0, - max_arena_size: 100, - do_prune: false, - print: false, - children_eval_method: ChildrenEvalMethod::AverageDivDepth, - }; + static FUTURE_MOVES_CONFIG: LazyLock = LazyLock::new(|| { + FutureMoveConfig { + max_depth: 3, // we want great-grand children for traversing moves + min_arena_depth: 0, + top_k_children: 1, + up_to_minus: 0, + max_arena_size: 100, + do_prune: false, + print: false, + children_eval_method: Default::default(), + } + }); #[test] fn prune_tree_test() { - let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG); + let mut futm = FutureMoves::new(Piece::Black, *FUTURE_MOVES_CONFIG); futm.update_from_board(&Board::new()); @@ -628,7 +665,7 @@ mod tests { #[test] fn expand_layer_test() { - let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG); + let mut futm = FutureMoves::new(Piece::Black, *FUTURE_MOVES_CONFIG); futm.config.max_depth = 1; futm.update_from_board(&Board::STARTING_POSITION); @@ -653,7 +690,7 @@ mod tests { #[test] fn depth_of_test() { - let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG); + let mut futm = FutureMoves::new(Piece::Black, *FUTURE_MOVES_CONFIG); futm.update_from_board(&Board::new()); @@ -681,7 +718,7 @@ mod tests { #[test] fn by_depth_test() { - let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG); + let mut futm = FutureMoves::new(Piece::Black, *FUTURE_MOVES_CONFIG); futm.update_from_board(&Board::new()); @@ -707,7 +744,7 @@ mod tests { /// tests whether or not FutureMoves can recover from multiple skips and then manually regenerating the arena #[test] fn skip_move_recovery() { - let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG); + let mut futm = FutureMoves::new(Piece::Black, *FUTURE_MOVES_CONFIG); let mut board = Board::STARTING_POSITION; // replay of a test I did @@ -770,7 +807,7 @@ mod tests { #[test] fn derive_board() { - let mut futm = FutureMoves::new(Piece::White, FUTURE_MOVES_CONFIG); + let mut futm = FutureMoves::new(Piece::White, *FUTURE_MOVES_CONFIG); let mut b = Board::STARTING_POSITION; futm.update_from_board(&b); @@ -838,7 +875,7 @@ mod tests { } } - let mut futm = FutureMoves::new(Piece::White, FUTURE_MOVES_CONFIG); + let mut futm = FutureMoves::new(Piece::White, *FUTURE_MOVES_CONFIG); futm.update_from_board(&board); futm.generate(); diff --git a/src/main.rs b/src/main.rs index c5d1315..e924962 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,8 @@ pub mod repr; // TODO! make this agent configuration a config option via `clap-rs` // or maybe even like a TUI menu? fn main() { + // elo::run(); + // return; let player1 = complexagent::ComplexAgent::new( Piece::Black, FutureMoveConfig {