From 3b07a67d2e56686094e8886f7b637b5932400706 Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Thu, 20 Feb 2025 20:52:59 -0500 Subject: [PATCH] logical improvements and cleanup --- src/complexagent.rs | 6 +++--- src/logic/future_moves.rs | 43 +++++++++++++++------------------------ src/logic/move.rs | 30 ++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/src/complexagent.rs b/src/complexagent.rs index 0e0f48e..1169205 100644 --- a/src/complexagent.rs +++ b/src/complexagent.rs @@ -12,10 +12,10 @@ pub struct ComplexAgent { #[allow(dead_code)] impl ComplexAgent { pub const fn new(color: Piece) -> Self { - const MAX_DEPTH: usize = 12; + const MAX_DEPTH: usize = 10; Self { color, - future_moves: FutureMoves::new(color, MAX_DEPTH, 6), + future_moves: FutureMoves::new(color, MAX_DEPTH, 8), } } } @@ -24,7 +24,7 @@ impl Agent for ComplexAgent { fn next_move(&mut self, board: &Board) -> Option<(usize, usize)> { self.future_moves.update(board); - println!("# of moves stored: {}", self.future_moves.len()); + println!("# of moves stored: {}", self.future_moves.arena_len()); self.future_moves.best_move().inspect(|&(i, j)| { if !self.future_moves.update_root_coord(i, j) { diff --git a/src/logic/future_moves.rs b/src/logic/future_moves.rs index 15505ad..cbf192f 100644 --- a/src/logic/future_moves.rs +++ b/src/logic/future_moves.rs @@ -37,14 +37,10 @@ impl FutureMoves { } } - pub fn len(&self) -> usize { + pub fn arena_len(&self) -> usize { self.arena.len() } - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - /// Generate children for all children of `nodes` /// only `pub` for the sake of benchmarking pub fn extend_layers(&mut self) { @@ -118,26 +114,17 @@ impl FutureMoves { // because we use [`Board::what_if`] later and we want to reduce calls to [`Board::propegate_from_dry`] Board::all_positions() .flat_map(|(i, j)| parent.board.what_if(i, j, new_color).map(move |x| (i, j, x))) - .map(|(i, j, new_board)| Move { - i, - j, - board: new_board, - winner: new_board.game_winner(), - parent: Some(parent_idx), - children: Vec::new(), - value: 0, - color: new_color, - lazy_children, - }).collect(); + .map(|(i, j, new_board)| Move::new(i, j, new_board, new_color, lazy_children, self.agent_color, Some(parent_idx))).collect(); // negative, because we want the max value to be at the first index - new.sort_by_key(|x| -x.compute_self_value(self.agent_color)); + // abs because we want the most EXTREME possible outcome (win or lose for example) + new.sort_by_key(|x| -x.self_value.abs()); // keep the TOP_K children `self.agent_color`-color moves - const TOP_K_CHILDREN: usize = 1; + const TOP_K_CHILDREN: usize = 2; // we want to keep only the best move of the agent - if lazy_children && new_color == self.agent_color && new.len() > TOP_K_CHILDREN { + if lazy_children && new.len() > TOP_K_CHILDREN { new.drain(TOP_K_CHILDREN..); } @@ -156,6 +143,7 @@ impl FutureMoves { } else { self.arena.extend(new); } + let new_indices = start_idx..self.arena.len(); self.arena[parent_idx].children.extend(new_indices.clone()); @@ -191,15 +179,14 @@ impl FutureMoves { // TODO! impl dynamic sorting based on children's states, maybe it propegates // upwards using the `parent` field // SAFETY! the sort_by_key function should not modify anything - unsafe { (*(self as *mut Self)).arena.get_unchecked_mut(idx) } + unsafe { &mut (*(self as *mut Self)) }.arena[idx] .children // negative because we want the largest value in the first index - .sort_by_key(|&x| -self.arena[x].value); + // abs so we get the most extreme solutions + // but base on `.value` for recursive behavior + .sort_by_key(|&x| -self.arena[x].value.abs()); - let node = &self.arena[idx]; - let self_value = node.compute_self_value(self.agent_color) / (depth + 1) as i64; - - let children_value = node + let children_value = self.arena[idx] .children .iter() .rev() // rev then reverse so we get an index starting from the back @@ -207,10 +194,11 @@ impl FutureMoves { // since children are sorted by value, we should weight the first one more .map(|(i, &child)| self.arena[child].value * (i as i64 + 1)) .sum::() - .checked_div(node.children.len() as i64) + .checked_div((&self.arena[idx]).children.len() as i64) .unwrap_or(0); - self.arena[idx].value = self_value + children_value; + self.arena[idx].value = + self.arena[idx].self_value / (depth as i64 + 1) + children_value; } } } @@ -264,6 +252,7 @@ impl FutureMoves { value: 0, color: !self.agent_color, lazy_children: false, + self_value: 0, }); } diff --git a/src/logic/move.rs b/src/logic/move.rs index ce0a4f6..da3a737 100644 --- a/src/logic/move.rs +++ b/src/logic/move.rs @@ -24,9 +24,11 @@ pub struct Move { /// Indices of this Move's Children pub children: Vec, - /// Value of this move + /// Value of this move (including children) pub value: i64, + pub self_value: i64, + pub color: Piece, pub lazy_children: bool, @@ -37,6 +39,32 @@ lazy_static! { } impl Move { + pub fn new( + i: usize, + j: usize, + board: Board, + color: Piece, + lazy_children: bool, + agent_color: Piece, + parent: Option, + ) -> Self { + let mut m = Move { + i, + j, + board, + winner: board.game_winner(), + parent, + children: Vec::new(), + value: 0, + color, + lazy_children, + self_value: 0, + }; + m.self_value = m.compute_self_value(agent_color); + m.value = m.self_value; + m + } + pub const fn coords(&self) -> (usize, usize) { (self.i, self.j) }