Start propogating the slab_tree up to OTG
This commit is contained in:
parent
f899fdb691
commit
1ddc867f01
|
@ -2708,6 +2708,7 @@ dependencies = [
|
||||||
"serde 1.0.193",
|
"serde 1.0.193",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sgf",
|
"sgf",
|
||||||
|
"slab_tree",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"uuid 0.8.2",
|
"uuid 0.8.2",
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,6 +14,7 @@ sgf = { path = "../../sgf" }
|
||||||
grid = { version = "0.9" }
|
grid = { version = "0.9" }
|
||||||
serde_json = { version = "1" }
|
serde_json = { version = "1" }
|
||||||
serde = { version = "1", features = [ "derive" ] }
|
serde = { version = "1", features = [ "derive" ] }
|
||||||
|
slab_tree = { version = "0.3" }
|
||||||
thiserror = { version = "1" }
|
thiserror = { version = "1" }
|
||||||
uuid = { version = "0.8", features = ["v4", "serde"] }
|
uuid = { version = "0.8", features = ["v4", "serde"] }
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ impl From<HotseatPlayerRequest> for Player {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum CoreResponse {
|
pub enum CoreResponse {
|
||||||
Library(library::LibraryResponse),
|
Library(library::LibraryResponse),
|
||||||
Settings(settings::SettingsResponse),
|
Settings(settings::SettingsResponse),
|
||||||
|
|
|
@ -42,7 +42,8 @@ impl Database {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
match parse_sgf(&buffer) {
|
match parse_sgf(&buffer) {
|
||||||
Ok(sgfs) => {
|
Ok(sgfs) => {
|
||||||
let mut sgfs = sgfs.into_iter().flatten().collect::<Vec<sgf::GameRecord>>();
|
let mut sgfs =
|
||||||
|
sgfs.into_iter().flatten().collect::<Vec<sgf::GameRecord>>();
|
||||||
games.append(&mut sgfs);
|
games.append(&mut sgfs);
|
||||||
}
|
}
|
||||||
Err(err) => println!("Error parsing {:?}: {:?}", entry.path(), err),
|
Err(err) => println!("Error parsing {:?}: {:?}", entry.path(), err),
|
||||||
|
|
|
@ -29,5 +29,5 @@ pub mod library;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
|
||||||
mod types;
|
mod types;
|
||||||
pub use types::{BoardError, Color, Config, ConfigOption, LibraryPath, Player, Rank, Size, Tree};
|
pub use types::{BoardError, Color, Config, ConfigOption, LibraryPath, Player, Rank, Size};
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub enum LibraryRequest {
|
||||||
ListGames
|
ListGames
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum LibraryResponse {
|
pub enum LibraryResponse {
|
||||||
Games(Vec<GameRecord>)
|
Games(Vec<GameRecord>)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,9 @@ use crate::goban::{Coordinate, Goban};
|
||||||
use config::define_config;
|
use config::define_config;
|
||||||
use config_derive::ConfigOption;
|
use config_derive::ConfigOption;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sgf::GameNode;
|
use sgf::GameTree;
|
||||||
use std::{cell::RefCell, collections::VecDeque, fmt, path::PathBuf, time::Duration};
|
use std::{cell::RefCell, collections::VecDeque, fmt, path::PathBuf, time::Duration};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
define_config! {
|
define_config! {
|
||||||
LibraryPath(LibraryPath),
|
LibraryPath(LibraryPath),
|
||||||
|
@ -229,6 +228,7 @@ impl GameState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// To properly generate a tree, I need to know how deep to go. Then I can backtrace. Each node
|
// To properly generate a tree, I need to know how deep to go. Then I can backtrace. Each node
|
||||||
// needs to have a depth. Given a tree, the depth of the node is just the distance from the root.
|
// needs to have a depth. Given a tree, the depth of the node is just the distance from the root.
|
||||||
// This seems obvious, but I had to write it to discover how important that fact was.
|
// This seems obvious, but I had to write it to discover how important that fact was.
|
||||||
|
@ -238,18 +238,22 @@ impl GameState {
|
||||||
pub struct Tree<T> {
|
pub struct Tree<T> {
|
||||||
nodes: Vec<Node<T>>,
|
nodes: Vec<Node<T>>,
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct DepthTree(slab_tree::Tree<SizeNode>);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Node<T> {
|
pub struct SizeNode {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
node: T,
|
node_id: slab_tree::NodeId,
|
||||||
parent: Option<usize>,
|
parent: Option<usize>,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
width: RefCell<Option<usize>>,
|
width: RefCell<Option<usize>>,
|
||||||
children: Vec<usize>,
|
children: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Tree<T> {
|
impl DepthTree {
|
||||||
|
/*
|
||||||
fn new(root: T) -> Self {
|
fn new(root: T) -> Self {
|
||||||
Tree {
|
Tree {
|
||||||
nodes: vec![Node {
|
nodes: vec![Node {
|
||||||
|
@ -286,12 +290,16 @@ impl<T> Tree<T> {
|
||||||
parent.children.push(next_idx);
|
parent.children.push(next_idx);
|
||||||
next_idx
|
next_idx
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
pub fn max_depth(&self) -> usize {
|
pub fn max_depth(&self) -> usize {
|
||||||
|
unimplemented!()
|
||||||
|
/*
|
||||||
self.nodes.iter().fold(
|
self.nodes.iter().fold(
|
||||||
0,
|
0,
|
||||||
|max, node| if node.depth > max { node.depth } else { max },
|
|max, node| if node.depth > max { node.depth } else { max },
|
||||||
)
|
)
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since I know the width of a node, now I want to figure out its placement in the larger
|
// Since I know the width of a node, now I want to figure out its placement in the larger
|
||||||
|
@ -310,6 +318,8 @@ impl<T> Tree<T> {
|
||||||
//
|
//
|
||||||
// When drawing nodes, I don't know how to persist the level of indent.
|
// When drawing nodes, I don't know how to persist the level of indent.
|
||||||
pub fn position(&self, idx: usize) -> (usize, usize) {
|
pub fn position(&self, idx: usize) -> (usize, usize) {
|
||||||
|
unimplemented!()
|
||||||
|
/*
|
||||||
let node = &self.nodes[idx];
|
let node = &self.nodes[idx];
|
||||||
match node.parent {
|
match node.parent {
|
||||||
Some(parent_idx) => {
|
Some(parent_idx) => {
|
||||||
|
@ -326,8 +336,10 @@ impl<T> Tree<T> {
|
||||||
// Root nodes won't have a parent, so just put them in the first column
|
// Root nodes won't have a parent, so just put them in the first column
|
||||||
None => (0, 0),
|
None => (0, 0),
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// Given a node, do a postorder traversal to figure out the width of the node based on all of
|
// Given a node, do a postorder traversal to figure out the width of the node based on all of
|
||||||
// its children. This is equivalent to the widest of all of its children at all depths.
|
// its children. This is equivalent to the widest of all of its children at all depths.
|
||||||
//
|
//
|
||||||
|
@ -359,8 +371,16 @@ impl<T> Tree<T> {
|
||||||
queue.push_back(&self.nodes[0]);
|
queue.push_back(&self.nodes[0]);
|
||||||
BFSIter { tree: self, queue }
|
BFSIter { tree: self, queue }
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a GameTree> for DepthTree {
|
||||||
|
fn from(root: &'a GameTree) -> Self {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
impl<'a> From<&'a GameNode> for Tree<Uuid> {
|
impl<'a> From<&'a GameNode> for Tree<Uuid> {
|
||||||
fn from(root: &'a GameNode) -> Self {
|
fn from(root: &'a GameNode) -> Self {
|
||||||
fn add_subtree(tree: &mut Tree<Uuid>, parent_idx: usize, node: &GameNode) {
|
fn add_subtree(tree: &mut Tree<Uuid>, parent_idx: usize, node: &GameNode) {
|
||||||
|
@ -390,7 +410,9 @@ impl<'a> From<&'a GameNode> for Tree<Uuid> {
|
||||||
tree
|
tree
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
pub struct BFSIter<'a, T> {
|
pub struct BFSIter<'a, T> {
|
||||||
tree: &'a Tree<T>,
|
tree: &'a Tree<T>,
|
||||||
queue: VecDeque<&'a Node<T>>,
|
queue: VecDeque<&'a Node<T>>,
|
||||||
|
@ -410,12 +432,13 @@ impl<'a, T> Iterator for BFSIter<'a, T> {
|
||||||
retval
|
retval
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use cool_asserts::assert_matches;
|
// use sgf::{GameRecord, GameTree, GameType, Move, MoveNode};
|
||||||
use sgf::{Move, MoveNode};
|
use sgf::{GameNode, GameTree, Move, MoveNode};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn current_player_changes_after_move() {
|
fn current_player_changes_after_move() {
|
||||||
|
@ -474,69 +497,91 @@ mod test {
|
||||||
// B G H
|
// B G H
|
||||||
// C I
|
// C I
|
||||||
// D E F
|
// D E F
|
||||||
|
fn branching_tree() -> GameTree {
|
||||||
|
let mut game_tree = GameTree::default();
|
||||||
|
let node_a = game_tree.set_root(GameNode::MoveNode(MoveNode::new(
|
||||||
|
sgf::Color::Black,
|
||||||
|
Move::Move("dp".to_owned()),
|
||||||
|
)));
|
||||||
|
|
||||||
|
let node_b = game_tree
|
||||||
|
.get_mut(node_a)
|
||||||
|
.unwrap()
|
||||||
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
sgf::Color::Black,
|
||||||
|
Move::Move("dp".to_owned()),
|
||||||
|
))).node_id();
|
||||||
|
|
||||||
|
let node_c = game_tree
|
||||||
|
.get_mut(node_b)
|
||||||
|
.unwrap()
|
||||||
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
sgf::Color::Black,
|
||||||
|
Move::Move("dp".to_owned()),
|
||||||
|
))).node_id();
|
||||||
|
|
||||||
|
let node_d = game_tree
|
||||||
|
.get_mut(node_c)
|
||||||
|
.unwrap()
|
||||||
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
sgf::Color::Black,
|
||||||
|
Move::Move("dp".to_owned()),
|
||||||
|
))).node_id();
|
||||||
|
|
||||||
|
let node_e = game_tree
|
||||||
|
.get_mut(node_c)
|
||||||
|
.unwrap()
|
||||||
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
sgf::Color::Black,
|
||||||
|
Move::Move("dp".to_owned()),
|
||||||
|
))).node_id();
|
||||||
|
|
||||||
|
let node_f = game_tree
|
||||||
|
.get_mut(node_c)
|
||||||
|
.unwrap()
|
||||||
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
sgf::Color::Black,
|
||||||
|
Move::Move("dp".to_owned()),
|
||||||
|
))).node_id();
|
||||||
|
|
||||||
|
let node_g = game_tree
|
||||||
|
.get_mut(node_a)
|
||||||
|
.unwrap()
|
||||||
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
sgf::Color::Black,
|
||||||
|
Move::Move("dp".to_owned()),
|
||||||
|
))).node_id();
|
||||||
|
|
||||||
|
let node_h = game_tree
|
||||||
|
.get_mut(node_a)
|
||||||
|
.unwrap()
|
||||||
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
sgf::Color::Black,
|
||||||
|
Move::Move("dp".to_owned()),
|
||||||
|
))).node_id();
|
||||||
|
|
||||||
|
let _ = game_tree
|
||||||
|
.get_mut(node_h)
|
||||||
|
.unwrap()
|
||||||
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
sgf::Color::Black,
|
||||||
|
Move::Move("dp".to_owned()),
|
||||||
|
)));
|
||||||
|
|
||||||
|
game_tree
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_can_calculate_depth_from_game_tree() {
|
fn it_can_calculate_depth_from_game_tree() {
|
||||||
let mut node_a = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
let game_tree = branching_tree();
|
||||||
let mut node_b = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
let tree = DepthTree::from(&game_tree);
|
||||||
let mut node_c = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_d = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_e = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_f = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_g = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let mut node_h = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_i = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
|
|
||||||
node_c.children.push(GameNode::MoveNode(node_d));
|
|
||||||
node_c.children.push(GameNode::MoveNode(node_e));
|
|
||||||
node_c.children.push(GameNode::MoveNode(node_f));
|
|
||||||
|
|
||||||
node_b.children.push(GameNode::MoveNode(node_c));
|
|
||||||
|
|
||||||
node_h.children.push(GameNode::MoveNode(node_i));
|
|
||||||
|
|
||||||
node_a.children.push(GameNode::MoveNode(node_b));
|
|
||||||
node_a.children.push(GameNode::MoveNode(node_g));
|
|
||||||
node_a.children.push(GameNode::MoveNode(node_h));
|
|
||||||
|
|
||||||
let game_tree = GameNode::MoveNode(node_a);
|
|
||||||
|
|
||||||
let tree = Tree::from(&game_tree);
|
|
||||||
|
|
||||||
assert_eq!(tree.max_depth(), 3);
|
assert_eq!(tree.max_depth(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A
|
|
||||||
// B G H
|
|
||||||
// C I
|
|
||||||
// D E F
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_calculates_horizontal_position_of_nodes() {
|
fn it_calculates_horizontal_position_of_nodes() {
|
||||||
let mut node_a = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
let game_tree = branching_tree();
|
||||||
let mut node_b = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
let tree = DepthTree::from(&game_tree);
|
||||||
let mut node_c = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_d = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_e = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_f = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_g = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let mut node_h = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_i = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
|
|
||||||
node_c.children.push(GameNode::MoveNode(node_d));
|
|
||||||
node_c.children.push(GameNode::MoveNode(node_e));
|
|
||||||
node_c.children.push(GameNode::MoveNode(node_f));
|
|
||||||
|
|
||||||
node_b.children.push(GameNode::MoveNode(node_c));
|
|
||||||
|
|
||||||
node_h.children.push(GameNode::MoveNode(node_i));
|
|
||||||
|
|
||||||
node_a.children.push(GameNode::MoveNode(node_b));
|
|
||||||
node_a.children.push(GameNode::MoveNode(node_g));
|
|
||||||
node_a.children.push(GameNode::MoveNode(node_h));
|
|
||||||
|
|
||||||
let game_tree = GameNode::MoveNode(node_a);
|
|
||||||
|
|
||||||
let tree = Tree::from(&game_tree);
|
|
||||||
|
|
||||||
assert_eq!(tree.position(2), (2, 0));
|
assert_eq!(tree.position(2), (2, 0));
|
||||||
assert_eq!(tree.position(1), (1, 0));
|
assert_eq!(tree.position(1), (1, 0));
|
||||||
assert_eq!(tree.position(0), (0, 0));
|
assert_eq!(tree.position(0), (0, 0));
|
||||||
|
@ -546,8 +591,10 @@ mod test {
|
||||||
assert_eq!(tree.position(7), (1, 4));
|
assert_eq!(tree.position(7), (1, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn breadth_first_iter() {
|
fn breadth_first_iter() {
|
||||||
|
/*
|
||||||
let mut node_a = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
let mut node_a = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||||
let mut node_b = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
let mut node_b = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||||
let mut node_c = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
let mut node_c = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||||
|
@ -558,6 +605,24 @@ mod test {
|
||||||
let mut node_h = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
let mut node_h = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||||
let node_i = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
let node_i = MoveNode::new(sgf::Color::Black, Move::Move("dp".to_owned()));
|
||||||
|
|
||||||
|
let game = GameRecord::new(
|
||||||
|
GameType::Go,
|
||||||
|
Size {
|
||||||
|
width: 19,
|
||||||
|
height: 19,
|
||||||
|
},
|
||||||
|
Player {
|
||||||
|
name: Some("Black".to_owned()),
|
||||||
|
rank: None,
|
||||||
|
team: None,
|
||||||
|
},
|
||||||
|
Player {
|
||||||
|
name: Some("White".to_owned()),
|
||||||
|
rank: None,
|
||||||
|
team: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
node_c.children.push(GameNode::MoveNode(node_d.clone()));
|
node_c.children.push(GameNode::MoveNode(node_d.clone()));
|
||||||
node_c.children.push(GameNode::MoveNode(node_e.clone()));
|
node_c.children.push(GameNode::MoveNode(node_e.clone()));
|
||||||
node_c.children.push(GameNode::MoveNode(node_f.clone()));
|
node_c.children.push(GameNode::MoveNode(node_f.clone()));
|
||||||
|
@ -585,5 +650,6 @@ mod test {
|
||||||
assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_d.id));
|
assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_d.id));
|
||||||
assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_e.id));
|
assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_e.id));
|
||||||
assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_f.id));
|
assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_f.id));
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use slab_tree::{NodeId, NodeMut, NodeRef, Tree};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet, VecDeque},
|
collections::{HashMap, HashSet, VecDeque},
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
ops::Deref,
|
ops::{Deref, DerefMut},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -309,6 +309,12 @@ impl<'a> Iterator for TreeIter<'a> {
|
||||||
|
|
||||||
pub struct GameTree(Tree<GameNode>);
|
pub struct GameTree(Tree<GameNode>);
|
||||||
|
|
||||||
|
impl Default for GameTree {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(Tree::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Clone for GameTree {
|
impl Clone for GameTree {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
match self.0.root() {
|
match self.0.root() {
|
||||||
|
@ -362,6 +368,12 @@ impl Deref for GameTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DerefMut for GameTree {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for GameTree {
|
impl PartialEq for GameTree {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
// Get pre-order iterators over both trees, zip them, and ensure that the data contents are
|
// Get pre-order iterators over both trees, zip them, and ensure that the data contents are
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
mod date;
|
mod date;
|
||||||
|
|
||||||
mod game;
|
mod game;
|
||||||
pub use game::{GameNode, GameRecord, MoveNode, Player};
|
pub use game::{GameNode, GameRecord, GameTree, MoveNode, Player};
|
||||||
|
|
||||||
mod parser;
|
mod parser;
|
||||||
pub use parser::{parse_collection, Move};
|
pub use parser::{parse_collection, Move};
|
||||||
|
|
Loading…
Reference in New Issue