improve parent selection

This commit is contained in:
Simon Gardling 2025-02-26 22:11:27 -05:00
parent bbeb1b8b37
commit 4ec9f3cf21
Signed by: titaniumtown
GPG Key ID: 9AB28AC10ECE533D
4 changed files with 38 additions and 24 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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::<Vec<usize>>()
@ -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<impl Iterator<Item = usize>> {
/// 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<Item = usize> {
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);

View File

@ -22,6 +22,9 @@ pub struct Move {
/// Indices of this Move's Children
pub children: Vec<usize>,
/// Has this [`Move`] already attempted to create children?
pub tried_children: bool,
/// Value of this move (including children)
pub value: Option<i128>,
@ -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