From bc5042c0045c8545acb6eabea34fbf405ee9789c Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 28 Apr 2024 13:48:52 -0400 Subject: [PATCH] Start propogating the slab_tree up to OTG --- Cargo.lock | 1 + otg/core/Cargo.toml | 1 + otg/core/src/api.rs | 2 +- otg/core/src/database.rs | 3 +- otg/core/src/lib.rs | 2 +- otg/core/src/library.rs | 2 +- otg/core/src/types.rs | 250 +++++++++++++++++++++++++-------------- sgf/src/game.rs | 16 ++- sgf/src/lib.rs | 2 +- 9 files changed, 180 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 470b2a9..93efbef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2708,6 +2708,7 @@ dependencies = [ "serde 1.0.193", "serde_json", "sgf", + "slab_tree", "thiserror", "uuid 0.8.2", ] diff --git a/otg/core/Cargo.toml b/otg/core/Cargo.toml index dc8954d..a6b7215 100644 --- a/otg/core/Cargo.toml +++ b/otg/core/Cargo.toml @@ -14,6 +14,7 @@ sgf = { path = "../../sgf" } grid = { version = "0.9" } serde_json = { version = "1" } serde = { version = "1", features = [ "derive" ] } +slab_tree = { version = "0.3" } thiserror = { version = "1" } uuid = { version = "0.8", features = ["v4", "serde"] } diff --git a/otg/core/src/api.rs b/otg/core/src/api.rs index 0f5d914..153984b 100644 --- a/otg/core/src/api.rs +++ b/otg/core/src/api.rs @@ -81,7 +81,7 @@ impl From for Player { } */ -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug)] pub enum CoreResponse { Library(library::LibraryResponse), Settings(settings::SettingsResponse), diff --git a/otg/core/src/database.rs b/otg/core/src/database.rs index 035cd61..e144b57 100644 --- a/otg/core/src/database.rs +++ b/otg/core/src/database.rs @@ -42,7 +42,8 @@ impl Database { .unwrap(); match parse_sgf(&buffer) { Ok(sgfs) => { - let mut sgfs = sgfs.into_iter().flatten().collect::>(); + let mut sgfs = + sgfs.into_iter().flatten().collect::>(); games.append(&mut sgfs); } Err(err) => println!("Error parsing {:?}: {:?}", entry.path(), err), diff --git a/otg/core/src/lib.rs b/otg/core/src/lib.rs index 3168a04..5fde824 100644 --- a/otg/core/src/lib.rs +++ b/otg/core/src/lib.rs @@ -29,5 +29,5 @@ pub mod library; pub mod settings; 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}; diff --git a/otg/core/src/library.rs b/otg/core/src/library.rs index a18d454..135bb47 100644 --- a/otg/core/src/library.rs +++ b/otg/core/src/library.rs @@ -23,7 +23,7 @@ pub enum LibraryRequest { ListGames } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug)] pub enum LibraryResponse { Games(Vec) } diff --git a/otg/core/src/types.rs b/otg/core/src/types.rs index 09a0a0f..12153eb 100644 --- a/otg/core/src/types.rs +++ b/otg/core/src/types.rs @@ -2,10 +2,9 @@ use crate::goban::{Coordinate, Goban}; use config::define_config; use config_derive::ConfigOption; use serde::{Deserialize, Serialize}; -use sgf::GameNode; +use sgf::GameTree; use std::{cell::RefCell, collections::VecDeque, fmt, path::PathBuf, time::Duration}; use thiserror::Error; -use uuid::Uuid; define_config! { 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 // 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. @@ -238,18 +238,22 @@ impl GameState { pub struct Tree { nodes: Vec>, } +*/ + +struct DepthTree(slab_tree::Tree); #[derive(Debug)] -pub struct Node { +pub struct SizeNode { pub id: usize, - node: T, + node_id: slab_tree::NodeId, parent: Option, depth: usize, width: RefCell>, children: Vec, } -impl Tree { +impl DepthTree { + /* fn new(root: T) -> Self { Tree { nodes: vec![Node { @@ -286,12 +290,16 @@ impl Tree { parent.children.push(next_idx); next_idx } + */ pub fn max_depth(&self) -> usize { + unimplemented!() + /* self.nodes.iter().fold( 0, |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 @@ -310,6 +318,8 @@ impl Tree { // // When drawing nodes, I don't know how to persist the level of indent. pub fn position(&self, idx: usize) -> (usize, usize) { + unimplemented!() + /* let node = &self.nodes[idx]; match node.parent { Some(parent_idx) => { @@ -326,8 +336,10 @@ impl Tree { // Root nodes won't have a parent, so just put them in the first column None => (0, 0), } + */ } + /* // 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. // @@ -359,8 +371,16 @@ impl Tree { queue.push_back(&self.nodes[0]); 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 { fn from(root: &'a GameNode) -> Self { fn add_subtree(tree: &mut Tree, parent_idx: usize, node: &GameNode) { @@ -390,7 +410,9 @@ impl<'a> From<&'a GameNode> for Tree { tree } } +*/ +/* pub struct BFSIter<'a, T> { tree: &'a Tree, queue: VecDeque<&'a Node>, @@ -410,12 +432,13 @@ impl<'a, T> Iterator for BFSIter<'a, T> { retval } } +*/ #[cfg(test)] mod test { use super::*; - use cool_asserts::assert_matches; - use sgf::{Move, MoveNode}; + // use sgf::{GameRecord, GameTree, GameType, Move, MoveNode}; + use sgf::{GameNode, GameTree, Move, MoveNode}; #[test] fn current_player_changes_after_move() { @@ -474,69 +497,91 @@ mod test { // B G H // C I // 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] fn it_can_calculate_depth_from_game_tree() { - 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_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); - + let game_tree = branching_tree(); + let tree = DepthTree::from(&game_tree); assert_eq!(tree.max_depth(), 3); } - // A - // B G H - // C I - // D E F #[test] fn it_calculates_horizontal_position_of_nodes() { - 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_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); - + let game_tree = branching_tree(); + let tree = DepthTree::from(&game_tree); assert_eq!(tree.position(2), (2, 0)); assert_eq!(tree.position(1), (1, 0)); assert_eq!(tree.position(0), (0, 0)); @@ -546,44 +591,65 @@ mod test { assert_eq!(tree.position(7), (1, 4)); } + #[ignore] #[test] fn breadth_first_iter() { - 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_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())); + /* + 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_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.clone())); - node_c.children.push(GameNode::MoveNode(node_e.clone())); - node_c.children.push(GameNode::MoveNode(node_f.clone())); + 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_b.children.push(GameNode::MoveNode(node_c.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_f.clone())); - node_h.children.push(GameNode::MoveNode(node_i.clone())); + node_b.children.push(GameNode::MoveNode(node_c.clone())); - node_a.children.push(GameNode::MoveNode(node_b.clone())); - node_a.children.push(GameNode::MoveNode(node_g.clone())); - node_a.children.push(GameNode::MoveNode(node_h.clone())); + node_h.children.push(GameNode::MoveNode(node_i.clone())); - let game_tree = GameNode::MoveNode(node_a.clone()); + node_a.children.push(GameNode::MoveNode(node_b.clone())); + node_a.children.push(GameNode::MoveNode(node_g.clone())); + node_a.children.push(GameNode::MoveNode(node_h.clone())); - let tree = Tree::from(&game_tree); + let game_tree = GameNode::MoveNode(node_a.clone()); - let mut iter = tree.bfs_iter(); + let tree = Tree::from(&game_tree); - assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_a.id)); - assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_b.id)); - assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_g.id)); - assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_h.id)); - assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_c.id)); - assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_i.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_f.id)); + let mut iter = tree.bfs_iter(); + + assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_a.id)); + assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_b.id)); + assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_g.id)); + assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_h.id)); + assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_c.id)); + assert_matches!(iter.next(), Some(Node { node: uuid, .. }) => assert_eq!(*uuid, node_i.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_f.id)); + */ } } diff --git a/sgf/src/game.rs b/sgf/src/game.rs index 9f748da..5d64737 100644 --- a/sgf/src/game.rs +++ b/sgf/src/game.rs @@ -7,7 +7,7 @@ use slab_tree::{NodeId, NodeMut, NodeRef, Tree}; use std::{ collections::{HashMap, HashSet, VecDeque}, fmt::Debug, - ops::Deref, + ops::{Deref, DerefMut}, time::Duration, }; use uuid::Uuid; @@ -137,7 +137,7 @@ impl GameRecord { /// children. pub fn mainline(&self) -> Option> { println!("number of trees: {}", self.trees.len()); - if !self.trees.is_empty(){ + if !self.trees.is_empty() { Some(MainlineIter { next: self.trees[0].root(), tree: &self.trees[0], @@ -309,6 +309,12 @@ impl<'a> Iterator for TreeIter<'a> { pub struct GameTree(Tree); +impl Default for GameTree { + fn default() -> Self { + Self(Tree::new()) + } +} + impl Clone for GameTree { fn clone(&self) -> Self { 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 { fn eq(&self, other: &Self) -> bool { // Get pre-order iterators over both trees, zip them, and ensure that the data contents are diff --git a/sgf/src/lib.rs b/sgf/src/lib.rs index d06b8fc..9fc15ca 100644 --- a/sgf/src/lib.rs +++ b/sgf/src/lib.rs @@ -1,7 +1,7 @@ mod date; mod game; -pub use game::{GameNode, GameRecord, MoveNode, Player}; +pub use game::{GameNode, GameRecord, GameTree, MoveNode, Player}; mod parser; pub use parser::{parse_collection, Move};