From ff8733751257514fa3df93b305c6292e96e8b6b1 Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Wed, 26 Feb 2025 11:10:57 -0500 Subject: [PATCH] create FutureMoveConfig --- benches/future_children.rs | 10 ++++-- src/complexagent.rs | 11 ++++-- src/logic/future_moves.rs | 68 +++++++++++++++++++++++--------------- src/logic/mod.rs | 2 +- src/main.rs | 4 +-- 5 files changed, 60 insertions(+), 35 deletions(-) diff --git a/benches/future_children.rs b/benches/future_children.rs index 9cf0f66..2d51883 100644 --- a/benches/future_children.rs +++ b/benches/future_children.rs @@ -1,12 +1,18 @@ use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use othello::{ - logic::FutureMoves, + logic::{FutureMoveConfig, FutureMoves}, repr::{Board, Piece}, }; use std::time::Duration; fn extend_layers_test(depth: usize) { - let mut fut = FutureMoves::new(Piece::Black, depth); + let config = FutureMoveConfig { + max_depth: depth, + start_pruning_at_minus: 4, + top_k_children: 2, + up_to_mod: 4, + }; + let mut fut = FutureMoves::new(Piece::Black, config); fut.set_root_from_board(Board::new().starting_pos()); fut.extend_layers(); } diff --git a/src/complexagent.rs b/src/complexagent.rs index e3687a8..8b123ab 100644 --- a/src/complexagent.rs +++ b/src/complexagent.rs @@ -1,6 +1,6 @@ use crate::{ agent::Agent, - logic::FutureMoves, + logic::{FutureMoveConfig, FutureMoves}, repr::{Board, Piece}, }; @@ -12,10 +12,15 @@ pub struct ComplexAgent { #[allow(dead_code)] impl ComplexAgent { pub const fn new(color: Piece) -> Self { - const MAX_DEPTH: usize = 9; + const CONFIG: FutureMoveConfig = FutureMoveConfig { + max_depth: 7, + start_pruning_at_minus: 4, + top_k_children: 2, + up_to_mod: 4, + }; Self { color, - future_moves: FutureMoves::new(color, MAX_DEPTH), + future_moves: FutureMoves::new(color, CONFIG), } } } diff --git a/src/logic/future_moves.rs b/src/logic/future_moves.rs index c3690de..a3a8f75 100644 --- a/src/logic/future_moves.rs +++ b/src/logic/future_moves.rs @@ -15,21 +15,37 @@ pub struct FutureMoves { /// Current generated depth of the Arena current_depth: usize, - /// Target depth of children to generate - max_depth: usize, - /// Color w.r.t agent_color: Piece, + + config: FutureMoveConfig, +} + +#[derive(Default)] +pub struct FutureMoveConfig { + /// Max depth of that we should try and traverse + pub max_depth: usize, + + /// start pruning at X depth before self.max_depth is reached + /// used for pruning during tree generation before the tree is fully grown + pub start_pruning_at_minus: usize, + + /// when pruning, keep the top_k # of children + pub top_k_children: usize, + + // the lower the value, the more conservative the pruning is, what level to stop pruning at? + // a lower value allows more possible paths + pub up_to_mod: usize, } impl FutureMoves { - pub const fn new(agent_color: Piece, max_depth: usize) -> Self { + pub const fn new(agent_color: Piece, config: FutureMoveConfig) -> Self { Self { arena: Vec::new(), current_root: None, current_depth: 0, - max_depth, agent_color, + config, } } @@ -41,7 +57,7 @@ impl FutureMoves { /// Generate children for all children of `nodes` /// only `pub` for the sake of benchmarking pub fn extend_layers(&mut self) { - for i in (self.current_depth + 1)..=self.max_depth { + for i in (self.current_depth + 1)..=self.config.max_depth { (0..self.arena.len()) // we want to select all nodes that don't have children, or are lazy (need to maybe be regenerated) .filter(|&idx| { @@ -54,7 +70,7 @@ impl FutureMoves { .progress_with_style( ProgressStyle::with_template(&format!( "Generating children (depth: {}/{}): ({{pos}}/{{len}}) {{per_sec}}", - i, self.max_depth + i, self.config.max_depth )) .unwrap(), ) @@ -66,9 +82,9 @@ impl FutureMoves { self.current_depth += 1; } assert_eq!( - self.current_depth, self.max_depth, + self.current_depth, self.config.max_depth, "iteration and extention did not extend current_depth ({}) to the max_depth ({})", - self.current_depth, self.max_depth + self.current_depth, self.config.max_depth ); } @@ -323,23 +339,18 @@ impl FutureMoves { let by_depth = self.by_depth(0..self.arena.len()); - const TOP_K_CHIL: usize = 2; - - // the lower the value, the more conservative, what level to stop pruning at? - // a lower value allows more possible paths - let up_to = self.current_depth - 2; - - // start pruning at X depth before self.max_depth is reached - // used for pruning during tree generation before the tree is fully grown - const START_PRUNING_AT_MINUS: usize = 3; - - if self.max_depth.saturating_sub(START_PRUNING_AT_MINUS) > self.current_depth { + if self + .config + .max_depth + .saturating_sub(self.config.start_pruning_at_minus) + > self.current_depth + { return; } for (depth, indexes) in by_depth { // TODO! maybe update by_depth every iteration or something? - if depth > up_to { + if depth > self.current_depth.saturating_sub(self.config.up_to_mod) { return; } @@ -355,8 +366,8 @@ impl FutureMoves { } m.is_trimmed = true; m.sort_children(&mut self.arena); - if m.children.len() > TOP_K_CHIL { - let drained = m.children.drain(TOP_K_CHIL..); + if m.children.len() > self.config.top_k_children { + let drained = m.children.drain(self.config.top_k_children..); for idx in drained { self.arena[idx].parent = None; } @@ -441,7 +452,8 @@ mod tests { #[test] fn prune_tree_test() { - let mut futm = FutureMoves::new(Piece::Black, 0); + let mut futm = FutureMoves::new(Piece::Black, Default::default()); + futm.arena.push(Move { i: 0, j: 0, @@ -510,7 +522,9 @@ mod tests { #[test] fn expand_layer_test() { - let mut futm = FutureMoves::new(Piece::Black, 1); + let mut futm = FutureMoves::new(Piece::Black, Default::default()); + futm.config.max_depth = 1; + futm.arena.push(Move::new( 0, 0, @@ -542,7 +556,7 @@ mod tests { #[test] fn depth_of_test() { - let mut futm = FutureMoves::new(Piece::Black, 0); + let mut futm = FutureMoves::new(Piece::Black, Default::default()); futm.arena.push(Move { i: 0, @@ -606,7 +620,7 @@ mod tests { #[test] fn by_depth_test() { - let mut futm = FutureMoves::new(Piece::Black, 0); + let mut futm = FutureMoves::new(Piece::Black, Default::default()); futm.arena.push(Move { i: 0, diff --git a/src/logic/mod.rs b/src/logic/mod.rs index aef055a..e27556a 100644 --- a/src/logic/mod.rs +++ b/src/logic/mod.rs @@ -1,4 +1,4 @@ mod board_value; mod future_moves; mod r#move; -pub use future_moves::FutureMoves; +pub use future_moves::{FutureMoveConfig, FutureMoves}; diff --git a/src/main.rs b/src/main.rs index 82924e5..e6672a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,8 +10,8 @@ pub mod repr; fn main() { let player1 = complexagent::ComplexAgent::new(Piece::Black); // let player2 = complexagent::ComplexAgent::new(Piece::White); - let player2 = agent::ManualAgent::new(Piece::White); - // let player2 = agent::RandomAgent::new(Piece::White); + // let player2 = agent::ManualAgent::new(Piece::White); + let player2 = agent::RandomAgent::new(Piece::White); let mut game = Game::new(Box::new(player1), Box::new(player2)); game.game_loop(); }