diff --git a/src/complexagent.rs b/src/complexagent.rs index 2759aa4..4899cc2 100644 --- a/src/complexagent.rs +++ b/src/complexagent.rs @@ -32,11 +32,9 @@ impl Agent for ComplexAgent { 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) { - panic!("update_root_coord failed"); - } - }) + self.future_moves + .best_move() + .expect("FutureMoves has no move?") } fn name(&self) -> &'static str { diff --git a/src/logic/future_moves.rs b/src/logic/future_moves.rs index e1ad42c..773f591 100644 --- a/src/logic/future_moves.rs +++ b/src/logic/future_moves.rs @@ -216,7 +216,7 @@ impl FutureMoves { } /// Return the best move which is a child of `self.current_root` - pub fn best_move(&self) -> Option<(Coord, Coord)> { + pub fn best_move(&self) -> Option> { self.current_root .and_then(|x| { self.arena[x] @@ -230,25 +230,32 @@ impl FutureMoves { "selected move color should be the same as the color of the agent" ); }) - .and_then(|&x| self.arena[x].coord) + .map(|&x| self.arena[x].coord) } /// Updates `FutureMoves` based on the current state of the board /// The board is supposed to be after the opposing move - pub fn update_from_board(&mut self, board: &Board) { + /// Returns whether or not the arena was regenerated (bool) + pub fn update_from_board(&mut self, board: &Board) -> bool { let curr_board = self .arena .iter() .enumerate() - .find(|(_, m)| &m.board == board && (m.parent == self.current_root)) - .map(|(idx, _)| idx) - .filter(|_| self.current_root.is_some()); + .filter(|(idx, _)| { + self.current_root + .map(|x| self.arena[x].children.contains(idx)) + .unwrap_or(false) + }) + .find(|(_, m)| &m.board == board) + .map(|(idx, _)| idx); if let Some(curr_board_idx) = curr_board { self.set_root_idx_raw(curr_board_idx); + return false; } else { dbg!("regenerating arena from board"); self.set_root_from_board(*board); + return true; } } @@ -264,26 +271,6 @@ impl FutureMoves { self.set_root_idx_raw(0); } - /// Update the root based on the coordinate of the move - /// Returns a boolean, `true` if the operation was successful, false if not - #[must_use = "You must check if the root was properly set"] - pub fn update_root_coord(&mut self, i: Coord, j: Coord) -> bool { - // check to make sure current_root is some so we dont - // have to do that in the iterator - if self.current_root.is_none() { - return false; - } - - self.arena - .iter() - .enumerate() - .find(|(_, node)| node.parent == self.current_root && node.coord == Some((i, j))) - .map(|x| x.0) - // do raw set so we can prune it on the next move (in `update`) - .inspect(|&root| self.update_root_idx_raw(root)) - .is_some() - } - /// Update current root without modifying or pruning the Arena fn update_root_idx_raw(&mut self, idx: usize) { self.current_root = Some(idx); @@ -461,8 +448,8 @@ mod tests { const FUTURE_MOVES_CONFIG: FutureMoveConfig = FutureMoveConfig { max_depth: 1, - min_arena_depth_sub: 2, - top_k_children: 2, + min_arena_depth_sub: 0, + top_k_children: 1, up_to_minus: 0, max_arena_size: 100, }; @@ -662,17 +649,32 @@ mod tests { (Some((4, 2)), Piece::White), ]; - for (coords, color) in moves { + for (i, (coords, color)) in moves.into_iter().enumerate() { if color == futm.agent_color { // my turn - futm.update_from_board(&board); + + // seperate variable because we want it to always be executed + let update_result = futm.update_from_board(&board); + + // make sure that the arena should only be + // regenerated on the first move + assert!(i <= 0 || update_result, "board regenerated on move #{}", i); + let best_move = futm.best_move(); + assert!( + best_move.is_some(), + "best_move (#{}) resulted in ABSOLUTE None: {:?}", + i, + best_move + ); + if coords.is_none() { - assert_eq!(best_move, None); + assert_eq!(best_move, Some(None)); } else { - assert_ne!(best_move, None); + assert_ne!(best_move, Some(None)); } } + if let Some((i, j)) = coords { board.place(i, j, color).unwrap(); }