From d7f5269e152a80593de2813977e1652cf692ef47 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Thu, 25 Apr 2024 11:04:59 -0400 Subject: [PATCH] Begin implementing traits for a game record --- sgf/src/game.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/sgf/src/game.rs b/sgf/src/game.rs index cca9488..181956d 100644 --- a/sgf/src/game.rs +++ b/sgf/src/game.rs @@ -5,8 +5,7 @@ use crate::{ use serde::{Deserialize, Serialize}; use slab_tree::{NodeId, NodeMut, NodeRef, Tree}; use std::{ - collections::{HashSet, VecDeque}, - time::Duration, + collections::{HashMap, HashSet, VecDeque}, fmt::Debug, ops::Deref, time::Duration }; use uuid::Uuid; @@ -56,6 +55,7 @@ pub struct Player { /// syntax issues, the result of the GameRecord is to have a fully-understood game. However, this /// doesn't (yet?) go quite to the level of apply the game type (i.e., this is Go, Chess, Yinsh, or /// whatever). +#[derive(Clone, Debug, PartialEq)] pub struct GameRecord { pub game_type: GameType, @@ -81,7 +81,7 @@ pub struct GameRecord { pub overtime: Option, pub transcriber: Option, - pub trees: Vec>, + pub trees: Vec, } impl GameRecord { @@ -235,13 +235,13 @@ impl TryFrom for GameRecord { s.trees = tree.root.next.into_iter() .map(recursive_tree_to_slab_tree) - .collect::>, GameError>>()?; + .collect::, GameError>>()?; Ok(s) } } -fn recursive_tree_to_slab_tree(node: parser::Node) -> Result, GameError> { +fn recursive_tree_to_slab_tree(node: parser::Node) -> Result { let mut slab = Tree::new(); let mut nodes: VecDeque<(NodeId, parser::Node)> = VecDeque::new(); @@ -269,7 +269,7 @@ fn recursive_tree_to_slab_tree(node: parser::Node) -> Result, Gam } } - Ok(slab) + Ok(GameTree(slab)) } pub struct TreeIter<'a> { @@ -298,6 +298,50 @@ impl<'a> Iterator for TreeIter<'a> { } } +#[derive(PartialEq)] +struct GameTree(Tree); + +impl Clone for GameTree { + fn clone(&self) -> Self { + match self.0.root() { + None => Self(Tree::new()), + Some(source_root_node) => { + let mut dest = Tree::new(); + let dest_root_id = dest.set_root(source_root_node.data().clone()); + + // In order to add a node to the new tree, I need to know the ID of the parent in + // the source tree and the ID of the parent in the destination tree. So I want a + // lookup table that maps source IDs to destination IDs. But is that sufficient? + // Perhaps I can just keep a mapping from a source noderef to a destination ID. + // I don't think I can keep more than one mutable destination node. + + let mut mapping: HashMap = HashMap::new(); + mapping.insert(source_root_node.node_id(), dest_root_id); + + for source_node in source_root_node.traverse_level_order() { + } + + Self(dest) + } + } + } +} + +impl Debug for GameTree { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + self.write_formatted(f) + } +} + +impl Deref for GameTree { + type Target = Tree; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + + pub struct MainlineIter<'a> { next: Option>, tree: &'a Tree, @@ -950,4 +994,14 @@ mod file_test { }); }); } + + #[test] + fn it_can_copy_a_game_record() { + with_file(std::path::Path::new("test_data/multi-tree.sgf"), |games| { + let dest = games.clone(); + + assert_eq!(games.len(), dest.len()); + assert_eq!(games[0], dest[0]); + }); + } }