From 0534143d6b2cb8cdc15ae0b6a764211ba3811ba7 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Fri, 26 Apr 2024 09:05:38 -0400 Subject: [PATCH] Finish implementing GameTree.Clone and PartialEq --- sgf/src/game.rs | 80 +++++++++++++++++++++++++++++++----------------- sgf/src/lib.rs | 3 +- sgf/src/types.rs | 1 + 3 files changed, 55 insertions(+), 29 deletions(-) diff --git a/sgf/src/game.rs b/sgf/src/game.rs index 181956d..9f748da 100644 --- a/sgf/src/game.rs +++ b/sgf/src/game.rs @@ -5,7 +5,10 @@ use crate::{ use serde::{Deserialize, Serialize}; use slab_tree::{NodeId, NodeMut, NodeRef, Tree}; use std::{ - collections::{HashMap, HashSet, VecDeque}, fmt::Debug, ops::Deref, time::Duration + collections::{HashMap, HashSet, VecDeque}, + fmt::Debug, + ops::Deref, + time::Duration, }; use uuid::Uuid; @@ -134,7 +137,7 @@ impl GameRecord { /// children. pub fn mainline(&self) -> Option> { println!("number of trees: {}", self.trees.len()); - if self.trees.len() > 0 { + if !self.trees.is_empty(){ Some(MainlineIter { next: self.trees[0].root(), tree: &self.trees[0], @@ -233,7 +236,10 @@ impl TryFrom for GameRecord { .map_err(GameError::InvalidGameNode)?; */ - s.trees = tree.root.next.into_iter() + s.trees = tree + .root + .next + .into_iter() .map(recursive_tree_to_slab_tree) .collect::, GameError>>()?; @@ -272,10 +278,12 @@ fn recursive_tree_to_slab_tree(node: parser::Node) -> Result { queue: VecDeque>, } +/* impl<'a> Default for TreeIter<'a> { fn default() -> Self { TreeIter { @@ -283,6 +291,7 @@ impl<'a> Default for TreeIter<'a> { } } } +*/ impl<'a> Iterator for TreeIter<'a> { type Item = &'a GameNode; @@ -298,8 +307,7 @@ impl<'a> Iterator for TreeIter<'a> { } } -#[derive(PartialEq)] -struct GameTree(Tree); +pub struct GameTree(Tree); impl Clone for GameTree { fn clone(&self) -> Self { @@ -319,6 +327,19 @@ impl Clone for GameTree { mapping.insert(source_root_node.node_id(), dest_root_id); for source_node in source_root_node.traverse_level_order() { + match source_node.parent() { + None => {} + Some(parent) => { + let source_node_parent_id = parent.node_id(); + let target_node_parent_id = mapping.get(&source_node_parent_id).expect("node should have been added to the source to dest mapping when being cloned"); + + let mut parent = dest.get_mut(*target_node_parent_id).expect( + "destination parent node to exist before reaching potential children", + ); + let dest_id = parent.append(source_node.data().clone()).node_id(); + mapping.insert(source_node.node_id(), dest_id); + } + } } Self(dest) @@ -341,6 +362,30 @@ impl Deref for GameTree { } } +impl PartialEq for GameTree { + fn eq(&self, other: &Self) -> bool { + // Get pre-order iterators over both trees, zip them, and ensure that the data contents are + // the same between them + let left_root = self.root(); + let right_root = other.root(); + + match (left_root, right_root) { + (Some(left_root), Some(right_root)) => { + for (left_node, right_node) in std::iter::zip( + left_root.traverse_pre_order(), + right_root.traverse_pre_order(), + ) { + if left_node.data() != right_node.data() { + return false; + } + } + } + (None, None) => return true, + _ => return false, + } + true + } +} pub struct MainlineIter<'a> { next: Option>, @@ -382,33 +427,12 @@ impl TryFrom for GameNode { type Error = GameNodeError; fn try_from(n: parser::Node) -> Result { - // I originally wrote this recursively. However, on an ordinary game of a couple hundred - // moves, that meant that I was recursing 500 functions, and that exceeded the stack limit. - // So, instead, I need to unroll everything to non-recursive form. - // - // So, I can treat each branch of the tree as a single line. Iterate over that line. I can - // only use the MoveNode::try_from and SetupNode::try_from if those functions don't - // recurse. Instead, I'm going to process just that node, then return to here and process - // the children. let move_node = MoveNode::try_from(n.clone()); let setup_node = SetupNode::try_from(n.clone()); - // I'm much too tired when writing this. I'm still recursing, but I did cut the number of - // recursions in half. This helps, but it still doesn't guarantee that I'm going to be able - // to parse all possible games. So, still, treat each branch of the game as a single line. - // Iterate over that line, don't recurse. Create bookmarks at each branch point, and then - // come back to each one. - /* - let children = n - .next - .iter() - .map(GameNode::try_from) - .collect::, Self::Error>>()?; - */ - match (move_node, setup_node) { - (Ok(mut node), _) => Ok(Self::MoveNode(node)), - (Err(_), Ok(mut node)) => Ok(Self::SetupNode(node)), + (Ok(node), _) => Ok(Self::MoveNode(node)), + (Err(_), Ok(node)) => Ok(Self::SetupNode(node)), (Err(move_err), Err(setup_err)) => { Err(Self::Error::UnsupportedGameNode(move_err, setup_err, n)) } diff --git a/sgf/src/lib.rs b/sgf/src/lib.rs index 1685bb3..d06b8fc 100644 --- a/sgf/src/lib.rs +++ b/sgf/src/lib.rs @@ -22,6 +22,7 @@ pub enum Error { InvalidSgf(VerboseNomError), } +#[allow(dead_code)] #[derive(Debug)] pub struct VerboseNomError(nom::error::VerboseError); @@ -73,7 +74,7 @@ pub fn parse_sgf(input: &str) -> Result> let (_, games) = parse_collection::>(input)?; let games = games .into_iter() - .map(|game| GameRecord::try_from(game)) + .map(GameRecord::try_from) .collect::>>(); Ok(games) diff --git a/sgf/src/types.rs b/sgf/src/types.rs index 3cf3d13..723164d 100644 --- a/sgf/src/types.rs +++ b/sgf/src/types.rs @@ -56,6 +56,7 @@ pub enum Error { InvalidSgf(VerboseNomError), } +#[allow(dead_code)] #[derive(Debug)] pub struct VerboseNomError(nom::error::VerboseError);