From 00248de3e9a2037b2080fa8a611b4df2d29e1670 Mon Sep 17 00:00:00 2001 From: Bananasmoothii <45853225+bananasmoothii@users.noreply.github.com> Date: Sat, 7 Oct 2023 15:28:57 +0200 Subject: [PATCH] improving memory usage a tiny bit --- src/main.rs | 2 +- src/min_max.rs | 62 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/main.rs b/src/main.rs index d5c0ee5..9ee32ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ mod min_max; mod scalar; fn main() { - let max_depth = 9; + let max_depth = 10; let bot_vs_bot = true; let p1 = NonZeroU8::new(1).unwrap(); diff --git a/src/min_max.rs b/src/min_max.rs index 4e1884e..ba626ad 100644 --- a/src/min_max.rs +++ b/src/min_max.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::sync::{Arc, Mutex}; use rayon::iter::*; @@ -98,7 +99,9 @@ impl GameNode { G::Score::MIN() })); - let check_children = self.fill_children(now_playing); + // WARNING: (maybe) destroying game here, for memory efficiency + + let check_children = self.fill_children_and_destroy_game(now_playing, real_plays); let maybe_explore_children = |child: &mut Self| { let child_score = child.explore_children_recur( @@ -154,26 +157,31 @@ impl GameNode { weight.unwrap() }; - // WARNING: (maybe) destroying game here, for memory efficiency - if self.depth() != real_plays { - self.game = None; - } - weight } - fn fill_children(&mut self, now_playing: ::Player) -> bool { + /// Returns true if childrens should be checked for win or draw, false if they were already checked + fn fill_children_and_destroy_game( + &mut self, + now_playing: ::Player, + real_plays: u32, + ) -> bool { let game = self.game.as_ref().expect("game was removed too early"); if self.children.is_empty() { - self.children = game - .possible_plays() - .iter() - .map(|&input_coord| { + // if we take the game from us, we don't have to clone it, but we can do this only once + let take_game = self.depth() != real_plays; + + let possible_plays = game.possible_plays(); + let possibilities = possible_plays.len(); + let mut map = HashMap::with_capacity(possibilities); + + if possibilities >= 2 || !take_game { + for i in 0..(possibilities - 1) { + let input_coord = possible_plays[i]; let mut game = game.clone(); game.play(now_playing, input_coord).unwrap(); // should not panic as input_coord is a possible play - - ( + map.insert( input_coord, GameNode::new( Some(game), @@ -181,9 +189,31 @@ impl GameNode { None, PlayersTurn(now_playing.other(), Some(input_coord)), ), - ) - }) - .collect(); // todo: a lot of memory is used here + ); + } + } + if possibilities >= 1 { + let input_coord = possible_plays[possibilities - 1]; + let mut game = if take_game { + // we don't want to destroy the game in the root node + // add the game itself while "destroying" it for us + self.game.take().unwrap() + } else { + game.clone() + }; + game.play(now_playing, input_coord).unwrap(); + map.insert( + input_coord, + GameNode::new( + Some(game), + self.depth() + 1, + None, + PlayersTurn(now_playing.other(), Some(input_coord)), + ), + ); + } + + self.children = map; true } else { self.regenerate_children_games();