fully fix future_moves

This commit is contained in:
Simon Gardling 2025-03-07 22:21:45 -05:00
parent efd762e5d2
commit 52e7ed7386
Signed by: titaniumtown
GPG Key ID: 9AB28AC10ECE533D
3 changed files with 31 additions and 82 deletions

View File

@ -16,7 +16,7 @@ fn extend_layers_no_pruning(depth: usize, arena_size: usize) -> usize {
children_eval_method: ChildrenEvalMethod::Max,
};
let mut fut = FutureMoves::new(Piece::Black, config);
fut.set_root_from_board(Board::new().starting_pos());
fut.update_from_board(&Board::new().starting_pos());
fut.extend_layers();
fut.arena_len()
}

View File

@ -22,6 +22,7 @@ impl ComplexAgent {
impl Agent for ComplexAgent {
fn next_move(&mut self, board: &Board) -> Option<CoordPair> {
self.future_moves.update_from_board(board);
self.future_moves.generate();
self.future_moves
.best_move()

View File

@ -366,54 +366,41 @@ impl FutureMoves {
// match the agent_color usually root or great-grand child
.filter(|&idx| self.depth_of(idx) % 2 == 0)
.find(|&idx| {
self.get_board_from_idx(idx).as_ref() == Some(board)
&& self.arena[idx].color == !self.agent_color
self.arena[idx].color == !self.agent_color
&& self.get_board_from_idx(idx).as_ref() == Some(board)
});
if let Some(curr_board_idx) = curr_board {
self.set_root_idx_raw(curr_board_idx);
self.root_from_child_idx_board(curr_board_idx, *board);
false
} else {
if self.config.print && !self.arena.is_empty() {
println!("regenerating arena from board");
}
self.set_root_from_board(*board);
self.rebuild_from_board(*board);
true
}
}
/// Clear the arena and create and set a root which contains a Board
pub fn set_root_from_board(&mut self, board: Board) {
pub fn generate(&mut self) {
self.extend_layers();
self.compute_values(0..self.arena.len());
}
fn rebuild_from_board(&mut self, board: Board) {
self.arena.clear();
self.arena
.push(Move::new(None, board, !self.agent_color, self.agent_color));
// because we have to regenerate root from a [`Board`]
// we need to reset the current_depth (fixes `skip_move_recovery`)
self.current_root = Some(0);
self.current_depth = 0;
self.set_root_idx_raw(0);
self.board = board;
}
/// Update current root without modifying or pruning the Arena
fn update_root_idx_raw(&mut self, idx: usize) {
self.current_root = Some(idx);
fn root_from_child_idx_board(&mut self, idx: usize, board: Board) {
self.current_depth -= self.depth_of(idx);
}
/// Update current root index while pruning and extending the tree (also recalculate values)
fn set_root_idx_raw(&mut self, idx: usize) {
self.update_root_idx_raw(idx);
self.current_root = Some(idx);
self.board = board;
self.refocus_tree();
self.extend_layers();
if self.config.print {
println!("# of moves stored: {}", self.arena_len());
}
self.compute_values(0..self.arena.len());
// check arena's consistancy
debug_assert_eq!(self.check_arena().join("\n"), "");
}
pub fn set_parent_child(&mut self, parent: usize, child: usize) {
@ -574,26 +561,14 @@ mod tests {
max_arena_size: 100,
do_prune: false,
print: false,
children_eval_method: ChildrenEvalMethod::Max,
children_eval_method: ChildrenEvalMethod::Average,
};
#[test]
fn prune_tree_test() {
let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG);
futm.arena.push(Move {
coord: None,
winner: Winner::None,
parent: None,
children: Vec::new(),
value: None,
self_value: 0,
color: Piece::Black,
is_trimmed: false,
tried_children: false,
});
futm.update_root_idx_raw(0);
futm.update_from_board(&Board::new());
// child 1
futm.arena
@ -636,20 +611,17 @@ mod tests {
let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG);
futm.config.max_depth = 1;
futm.arena.push(Move::new(
None,
Board::new().starting_pos(),
Piece::Black,
Piece::Black,
));
futm.update_root_idx_raw(0);
futm.update_from_board(&Board::new().starting_pos());
futm.extend_layers();
assert_eq!(futm.arena_len(), 5);
// move to a child
futm.update_root_idx_raw(1);
futm.root_from_child_idx_board(
1,
futm.get_board_from_idx(1)
.expect("unable to get board from child"),
);
futm.refocus_tree();
assert_eq!(futm.arena_len(), 1);
@ -667,19 +639,7 @@ mod tests {
fn depth_of_test() {
let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG);
futm.arena.push(Move {
coord: None,
winner: Winner::None,
parent: None,
children: vec![],
value: None,
self_value: 0,
color: Piece::Black,
is_trimmed: false,
tried_children: false,
});
futm.update_root_idx_raw(0);
futm.update_from_board(&Board::new());
// child 1
futm.arena
@ -707,19 +667,7 @@ mod tests {
fn by_depth_test() {
let mut futm = FutureMoves::new(Piece::Black, FUTURE_MOVES_CONFIG);
futm.arena.push(Move {
coord: None,
winner: Winner::None,
parent: None,
children: vec![1],
value: None,
self_value: 0,
color: Piece::Black,
is_trimmed: false,
tried_children: false,
});
futm.update_root_idx_raw(0);
futm.update_from_board(&Board::new());
// child 1
futm.arena
@ -775,6 +723,7 @@ mod tests {
// seperate variable because we want it to always be executed
let update_result = futm.update_from_board(&board);
futm.generate();
// make sure that the arena should only be
// regenerated on the first move
@ -808,9 +757,7 @@ mod tests {
let mut futm = FutureMoves::new(Piece::White, FUTURE_MOVES_CONFIG);
let mut b = Board::new().starting_pos();
futm.arena
.push(Move::new(None, b, Piece::Black, Piece::White));
futm.update_root_idx_raw(0);
futm.update_from_board(&Board::new().starting_pos());
b.place((4, 2).into(), Piece::White).unwrap();
@ -877,7 +824,8 @@ mod tests {
let mut futm = FutureMoves::new(Piece::White, FUTURE_MOVES_CONFIG);
futm.update_from_board(&board);
futm.extend_layers();
futm.generate();
let best_move = futm.best_move();
if let Some(best_move) = best_move {