diff --git a/benches/future_children.rs b/benches/future_children.rs index 02e3bf1..c79d8b6 100644 --- a/benches/future_children.rs +++ b/benches/future_children.rs @@ -8,9 +8,9 @@ use std::time::Duration; fn extend_layers_test(depth: usize) { let config = FutureMoveConfig { max_depth: depth, - start_pruning_at_minus: 4, + min_arena_depth_sub: 4, top_k_children: 2, - up_to_mod: 4, + up_to_minus: 4, max_arena_size: 10_000_000, }; let mut fut = FutureMoves::new(Piece::Black, config); diff --git a/src/complexagent.rs b/src/complexagent.rs index 633239d..11b470f 100644 --- a/src/complexagent.rs +++ b/src/complexagent.rs @@ -14,10 +14,10 @@ impl ComplexAgent { pub const fn new(color: Piece) -> Self { const CONFIG: FutureMoveConfig = FutureMoveConfig { max_depth: 10, - start_pruning_at_minus: 4, + min_arena_depth_sub: 3, top_k_children: 2, - up_to_mod: 4, - max_arena_size: 100_000_000, + up_to_minus: 4, + max_arena_size: 10_000_000, }; Self { color, diff --git a/src/logic/future_moves.rs b/src/logic/future_moves.rs index eb361b5..cb963cd 100644 --- a/src/logic/future_moves.rs +++ b/src/logic/future_moves.rs @@ -26,16 +26,17 @@ 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, + /// subtract this value from FutureMove.max_depth + /// and that would be the min depth an arena should fill for + /// pruning to happen + pub min_arena_depth_sub: 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, + pub up_to_minus: usize, /// Max size of the arena, will not generate more if /// the arena is of that size or bigger @@ -71,7 +72,7 @@ impl FutureMoves { // we want to select all nodes that don't have children, or are lazy (need to maybe be regenerated) .filter(|&idx| { let got = &self.arena[idx]; - got.is_trimmed || got.children.is_empty() + !got.is_trimmed && got.winner == Winner::None && !got.tried_children }) .filter(|&idx| self.is_connected_to_root(idx)) .collect::>() @@ -84,7 +85,8 @@ impl FutureMoves { .unwrap(), ) .for_each(|node_idx| { - self.generate_children(node_idx); + self.generate_children(node_idx).last(); + self.arena[node_idx].tried_children = true; }); self.prune_bad_children(); @@ -109,14 +111,11 @@ impl FutureMoves { } /// Creates children for a parent (`parent`), returns an iterator it's children's indexes - fn generate_children(&mut self, parent_idx: usize) -> Option> { + /// Completely unchecked, the caller should be the one who tests to make sure child generation + /// hasn't already been tried on a parent + fn generate_children(&mut self, parent_idx: usize) -> impl Iterator { let parent = &self.arena[parent_idx]; - // early-exit if a winner for the parent already exists - if parent.winner != Winner::None { - return None; - } - let new_color = !parent.color; // use [`Board::all_positions`] here instead of [`Board::possible_moves`] @@ -140,7 +139,7 @@ impl FutureMoves { self.set_parent_child(parent_idx, child_idx); } - Some(new_indices) + new_indices } /// Given an index from `self.arena`, what depth is it at? 0-indexed @@ -346,7 +345,7 @@ impl FutureMoves { if self .config .max_depth - .saturating_sub(self.config.start_pruning_at_minus) + .saturating_sub(self.config.min_arena_depth_sub) > self.current_depth { return; @@ -354,7 +353,7 @@ impl FutureMoves { for (depth, indexes) in by_depth { // TODO! maybe update by_depth every iteration or something? - if depth > self.current_depth.saturating_sub(self.config.up_to_mod) { + if depth > self.current_depth.saturating_sub(self.config.up_to_minus) { return; } @@ -454,9 +453,17 @@ impl FutureMoves { mod tests { use super::*; + const FUTURE_MOVES_CONFIG: FutureMoveConfig = FutureMoveConfig { + max_depth: 1, + min_arena_depth_sub: 2, + top_k_children: 2, + up_to_minus: 0, + max_arena_size: 100, + }; + #[test] fn prune_tree_test() { - let mut futm = FutureMoves::new(Piece::Black, Default::default()); + let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG); futm.arena.push(Move { i: 0, @@ -469,6 +476,7 @@ mod tests { self_value: 0, color: Piece::Black, is_trimmed: false, + tried_children: false, }); futm.update_root_idx_raw(0); @@ -508,7 +516,7 @@ mod tests { #[test] fn expand_layer_test() { - let mut futm = FutureMoves::new(Piece::Black, Default::default()); + let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG); futm.config.max_depth = 1; futm.arena.push(Move::new( @@ -541,7 +549,7 @@ mod tests { #[test] fn depth_of_test() { - let mut futm = FutureMoves::new(Piece::Black, Default::default()); + let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG); futm.arena.push(Move { i: 0, @@ -554,6 +562,7 @@ mod tests { self_value: 0, color: Piece::Black, is_trimmed: false, + tried_children: false, }); futm.update_root_idx_raw(0); @@ -587,7 +596,7 @@ mod tests { #[test] fn by_depth_test() { - let mut futm = FutureMoves::new(Piece::Black, Default::default()); + let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG); futm.arena.push(Move { i: 0, @@ -600,6 +609,7 @@ mod tests { self_value: 0, color: Piece::Black, is_trimmed: false, + tried_children: false, }); futm.update_root_idx_raw(0); diff --git a/src/logic/move.rs b/src/logic/move.rs index 5fff678..2f82ec0 100644 --- a/src/logic/move.rs +++ b/src/logic/move.rs @@ -22,6 +22,9 @@ pub struct Move { /// Indices of this Move's Children pub children: Vec, + /// Has this [`Move`] already attempted to create children? + pub tried_children: bool, + /// Value of this move (including children) pub value: Option, @@ -52,6 +55,7 @@ impl Move { color, is_trimmed: false, self_value: 0, + tried_children: false, }; m.self_value = m.compute_self_value(agent_color); m