replace lazy_children system
This commit is contained in:
parent
155a8d0548
commit
2d066a6a3c
@ -12,11 +12,10 @@ pub struct ComplexAgent {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl ComplexAgent {
|
impl ComplexAgent {
|
||||||
pub const fn new(color: Piece) -> Self {
|
pub const fn new(color: Piece) -> Self {
|
||||||
const MAX_DEPTH: usize = 10;
|
const MAX_DEPTH: usize = 9;
|
||||||
const NON_LAZY_DEPTH: usize = 3;
|
|
||||||
Self {
|
Self {
|
||||||
color,
|
color,
|
||||||
future_moves: FutureMoves::new(color, MAX_DEPTH, NON_LAZY_DEPTH),
|
future_moves: FutureMoves::new(color, MAX_DEPTH),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,22 +18,18 @@ pub struct FutureMoves {
|
|||||||
/// Target depth of children to generate
|
/// Target depth of children to generate
|
||||||
max_depth: usize,
|
max_depth: usize,
|
||||||
|
|
||||||
/// How many deep should the lazy children status expire?
|
|
||||||
lazy_expire: usize,
|
|
||||||
|
|
||||||
/// Color w.r.t
|
/// Color w.r.t
|
||||||
agent_color: Piece,
|
agent_color: Piece,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FutureMoves {
|
impl FutureMoves {
|
||||||
pub const fn new(agent_color: Piece, max_depth: usize, lazy_expire: usize) -> Self {
|
pub const fn new(agent_color: Piece, max_depth: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
arena: Vec::new(),
|
arena: Vec::new(),
|
||||||
current_root: None,
|
current_root: None,
|
||||||
current_depth: 0,
|
current_depth: 0,
|
||||||
max_depth,
|
max_depth,
|
||||||
agent_color,
|
agent_color,
|
||||||
lazy_expire,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,17 +41,15 @@ impl FutureMoves {
|
|||||||
/// Generate children for all children of `nodes`
|
/// Generate children for all children of `nodes`
|
||||||
/// only `pub` for the sake of benchmarking
|
/// only `pub` for the sake of benchmarking
|
||||||
pub fn extend_layers(&mut self) {
|
pub fn extend_layers(&mut self) {
|
||||||
let mut next_nodes: Vec<usize> = (0..self.arena.len())
|
for i in (self.current_depth + 1)..=self.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)
|
// we want to select all nodes that don't have children, or are lazy (need to maybe be regenerated)
|
||||||
.filter(|&idx| {
|
.filter(|&idx| {
|
||||||
let got = &self.arena[idx];
|
let got = &self.arena[idx];
|
||||||
got.is_lazy || got.children.is_empty()
|
got.is_lazy || got.children.is_empty()
|
||||||
})
|
})
|
||||||
.filter(|&idx| self.is_connected_to_root(idx)) // put here so this will not extend needlessly before prunes
|
.filter(|&idx| self.is_connected_to_root(idx))
|
||||||
.collect();
|
.collect::<Vec<usize>>()
|
||||||
|
|
||||||
for i in (self.current_depth + 1)..=self.max_depth {
|
|
||||||
next_nodes = next_nodes
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.progress_with_style(
|
.progress_with_style(
|
||||||
ProgressStyle::with_template(&format!(
|
ProgressStyle::with_template(&format!(
|
||||||
@ -64,19 +58,14 @@ impl FutureMoves {
|
|||||||
))
|
))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
)
|
)
|
||||||
.flat_map(|node_idx| {
|
.for_each(|node_idx| {
|
||||||
if (self.arena[node_idx].is_lazy && self.depth_of(node_idx) >= self.lazy_expire)
|
self.generate_children(node_idx);
|
||||||
|| !self.arena[node_idx].is_lazy
|
});
|
||||||
{
|
|
||||||
self.generate_children(node_idx, i >= self.lazy_expire)
|
self.prune_bad_children();
|
||||||
} else {
|
self.current_depth += 1;
|
||||||
None
|
|
||||||
}
|
}
|
||||||
})
|
assert_eq!(self.current_depth, self.max_depth);
|
||||||
.flatten()
|
|
||||||
.collect();
|
|
||||||
}
|
|
||||||
self.current_depth = self.max_depth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if a [`Move`] at index `idx` is connected to `self.current_root`
|
/// Determines if a [`Move`] at index `idx` is connected to `self.current_root`
|
||||||
@ -96,11 +85,7 @@ impl FutureMoves {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates children for a parent (`parent`), returns an iterator it's children's indexes
|
/// Creates children for a parent (`parent`), returns an iterator it's children's indexes
|
||||||
fn generate_children(
|
fn generate_children(&mut self, parent_idx: usize) -> Option<impl Iterator<Item = usize>> {
|
||||||
&mut self,
|
|
||||||
parent_idx: usize,
|
|
||||||
lazy_children: bool,
|
|
||||||
) -> Option<impl Iterator<Item = usize>> {
|
|
||||||
let parent = &self.arena[parent_idx];
|
let parent = &self.arena[parent_idx];
|
||||||
|
|
||||||
// early-exit if a winner for the parent already exists
|
// early-exit if a winner for the parent already exists
|
||||||
@ -131,9 +116,6 @@ impl FutureMoves {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// keep the TOP_K children of their magnitude
|
|
||||||
const TOP_K_CHILDREN: usize = 3;
|
|
||||||
|
|
||||||
let start_idx = self.arena.len();
|
let start_idx = self.arena.len();
|
||||||
self.arena.extend(new);
|
self.arena.extend(new);
|
||||||
|
|
||||||
@ -141,16 +123,6 @@ impl FutureMoves {
|
|||||||
|
|
||||||
self.arena[parent_idx].children.extend(new_indices.clone());
|
self.arena[parent_idx].children.extend(new_indices.clone());
|
||||||
|
|
||||||
if lazy_children && new_indices.clone().count() > TOP_K_CHILDREN {
|
|
||||||
let mut parent_copy = self.arena[parent_idx].clone();
|
|
||||||
parent_copy.sort_children(self.arena.as_mut_slice());
|
|
||||||
self.arena[parent_idx] = parent_copy;
|
|
||||||
|
|
||||||
for i in new_indices.clone().skip(TOP_K_CHILDREN) {
|
|
||||||
self.arena[i].is_lazy = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(new_indices)
|
Some(new_indices)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +270,7 @@ impl FutureMoves {
|
|||||||
fn set_root_idx_raw(&mut self, idx: usize) {
|
fn set_root_idx_raw(&mut self, idx: usize) {
|
||||||
self.update_root_idx_raw(idx);
|
self.update_root_idx_raw(idx);
|
||||||
|
|
||||||
// self.prune_bad_children();
|
self.prune_bad_children();
|
||||||
self.refocus_tree();
|
self.refocus_tree();
|
||||||
self.extend_layers();
|
self.extend_layers();
|
||||||
self.compute_values(0..self.arena.len());
|
self.compute_values(0..self.arena.len());
|
||||||
@ -343,23 +315,44 @@ impl FutureMoves {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn prune_bad_children(&mut self) {
|
fn prune_bad_children(&mut self) {
|
||||||
const BOTTOM_PERC: f32 = 20.0;
|
// values are needed in order to prune and see what's best
|
||||||
let Some(root) = self.current_root else {
|
self.compute_values(0..self.arena_len());
|
||||||
|
|
||||||
|
let by_depth =
|
||||||
|
self.by_depth((0..self.arena.len()).filter(|&i| self.is_connected_to_root(i)));
|
||||||
|
|
||||||
|
const TOP_K_CHIL: usize = 2;
|
||||||
|
|
||||||
|
// the lower the value, the more conservative
|
||||||
|
const UP_TO: usize = 4;
|
||||||
|
|
||||||
|
for (depth, indexes) in by_depth {
|
||||||
|
if depth > UP_TO {
|
||||||
return;
|
return;
|
||||||
};
|
|
||||||
|
|
||||||
let mut children = self.arena[root].children.clone();
|
|
||||||
|
|
||||||
children.sort_by_key(|&i| -self.arena[i].value.expect("child has no value"));
|
|
||||||
let start_len = ((children.len()) as f32 * (1.0 - BOTTOM_PERC)) as usize;
|
|
||||||
let drained = children.drain(start_len..);
|
|
||||||
println!("{}", drained.len());
|
|
||||||
|
|
||||||
for i in drained {
|
|
||||||
self.arena[i].parent = None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.arena[root].children = children;
|
// only prune moves of the agent
|
||||||
|
if indexes.first().map(|&i| self.arena[i].color) != Some(self.agent_color) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for idx in indexes {
|
||||||
|
let mut m = self.arena[idx].clone();
|
||||||
|
if m.is_lazy {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m.is_lazy = true;
|
||||||
|
m.sort_children(&mut self.arena);
|
||||||
|
if m.children.len() > TOP_K_CHIL {
|
||||||
|
let drained = m.children.drain(TOP_K_CHIL..);
|
||||||
|
for idx in drained {
|
||||||
|
self.arena[idx].parent = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.arena[idx] = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.refocus_tree();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rebuilds the Arena based on `self.current_root`, prunes unrelated nodes
|
/// Rebuilds the Arena based on `self.current_root`, prunes unrelated nodes
|
||||||
@ -434,7 +427,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn prune_tree_test() {
|
fn prune_tree_test() {
|
||||||
let mut futm = FutureMoves::new(Piece::Black, 0, 0);
|
let mut futm = FutureMoves::new(Piece::Black, 0);
|
||||||
futm.arena.push(Move {
|
futm.arena.push(Move {
|
||||||
i: 0,
|
i: 0,
|
||||||
j: 0,
|
j: 0,
|
||||||
@ -503,7 +496,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn expand_layer_test() {
|
fn expand_layer_test() {
|
||||||
let mut futm = FutureMoves::new(Piece::Black, 1, 1);
|
let mut futm = FutureMoves::new(Piece::Black, 1);
|
||||||
futm.arena.push(Move::new(
|
futm.arena.push(Move::new(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -535,7 +528,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn depth_of_test() {
|
fn depth_of_test() {
|
||||||
let mut futm = FutureMoves::new(Piece::Black, 0, 0);
|
let mut futm = FutureMoves::new(Piece::Black, 0);
|
||||||
|
|
||||||
futm.arena.push(Move {
|
futm.arena.push(Move {
|
||||||
i: 0,
|
i: 0,
|
||||||
@ -599,7 +592,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn by_depth_test() {
|
fn by_depth_test() {
|
||||||
let mut futm = FutureMoves::new(Piece::Black, 0, 0);
|
let mut futm = FutureMoves::new(Piece::Black, 0);
|
||||||
|
|
||||||
futm.arena.push(Move {
|
futm.arena.push(Move {
|
||||||
i: 0,
|
i: 0,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user