Finish implementing GameTree.Clone and PartialEq
This commit is contained in:
parent
0c886b3bff
commit
f899fdb691
|
@ -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<impl Iterator<Item = &'_ GameNode>> {
|
||||
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<parser::Tree> 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::<Result<Vec<GameTree>, GameError>>()?;
|
||||
|
||||
|
@ -272,10 +278,12 @@ fn recursive_tree_to_slab_tree(node: parser::Node) -> Result<GameTree, GameError
|
|||
Ok(GameTree(slab))
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TreeIter<'a> {
|
||||
queue: VecDeque<NodeRef<'a, &'a GameNode>>,
|
||||
}
|
||||
|
||||
/*
|
||||
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<GameNode>);
|
||||
pub struct GameTree(Tree<GameNode>);
|
||||
|
||||
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<NodeRef<'a, GameNode>>,
|
||||
|
@ -382,33 +427,12 @@ impl TryFrom<parser::Node> for GameNode {
|
|||
type Error = GameNodeError;
|
||||
|
||||
fn try_from(n: parser::Node) -> Result<Self, Self::Error> {
|
||||
// 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::<Result<Vec<Self>, 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))
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ pub enum Error {
|
|||
InvalidSgf(VerboseNomError),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct VerboseNomError(nom::error::VerboseError<String>);
|
||||
|
||||
|
@ -73,7 +74,7 @@ pub fn parse_sgf(input: &str) -> Result<Vec<Result<GameRecord, game::GameError>>
|
|||
let (_, games) = parse_collection::<nom::error::VerboseError<&str>>(input)?;
|
||||
let games = games
|
||||
.into_iter()
|
||||
.map(|game| GameRecord::try_from(game))
|
||||
.map(GameRecord::try_from)
|
||||
.collect::<Vec<Result<GameRecord, game::GameError>>>();
|
||||
|
||||
Ok(games)
|
||||
|
|
|
@ -56,6 +56,7 @@ pub enum Error {
|
|||
InvalidSgf(VerboseNomError),
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct VerboseNomError(nom::error::VerboseError<String>);
|
||||
|
||||
|
|
Loading…
Reference in New Issue