Switch from my custom Tree setup to a slab tree in GameRecord

This commit is contained in:
Savanni D'Gerinel 2024-04-19 08:03:40 -04:00
parent 511f1080a7
commit bcc34ce4f6
3 changed files with 117 additions and 120 deletions

16
Cargo.lock generated
View File

@ -3687,6 +3687,7 @@ dependencies = [
"cool_asserts", "cool_asserts",
"nom", "nom",
"serde 1.0.193", "serde 1.0.193",
"slab_tree",
"thiserror", "thiserror",
"typeshare", "typeshare",
"uuid 0.8.2", "uuid 0.8.2",
@ -3760,12 +3761,27 @@ dependencies = [
"autocfg 1.1.0", "autocfg 1.1.0",
] ]
[[package]]
name = "slab_tree"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9e8b45abe77b7cab703054a11973cffe164c82c5ff5e211ae5a73af5e42e39f"
dependencies = [
"snowflake",
]
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.11.2" version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
[[package]]
name = "snowflake"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27207bb65232eda1f588cf46db2fee75c0808d557f6b3cf19a75f5d6d7c94df1"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.4.10" version = "0.4.10"

View File

@ -9,6 +9,7 @@ edition = "2021"
chrono = { version = "0.4", features = [ "serde" ] } chrono = { version = "0.4", features = [ "serde" ] }
nom = { version = "7" } nom = { version = "7" }
serde = { version = "1", features = [ "derive" ] } serde = { version = "1", features = [ "derive" ] }
slab_tree = { version = "0.3" }
thiserror = { version = "1"} thiserror = { version = "1"}
typeshare = { version = "1" } typeshare = { version = "1" }
uuid = { version = "0.8", features = ["v4", "serde"] } uuid = { version = "0.8", features = ["v4", "serde"] }

View File

@ -3,7 +3,11 @@ use crate::{
Color, Date, GameResult, GameType, Color, Date, GameResult, GameType,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::HashSet, time::Duration}; use slab_tree::{NodeRef, Tree};
use std::{
collections::{HashSet, VecDeque},
time::Duration,
};
use uuid::Uuid; use uuid::Uuid;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -52,7 +56,6 @@ pub struct Player {
/// syntax issues, the result of the GameRecord is to have a fully-understood game. However, this /// 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 /// doesn't (yet?) go quite to the level of apply the game type (i.e., this is Go, Chess, Yinsh, or
/// whatever). /// whatever).
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct GameRecord { pub struct GameRecord {
pub game_type: GameType, pub game_type: GameType,
@ -78,7 +81,7 @@ pub struct GameRecord {
pub overtime: Option<String>, pub overtime: Option<String>,
pub transcriber: Option<String>, pub transcriber: Option<String>,
pub children: Vec<GameNode>, pub trees: Vec<Tree<GameNode>>,
} }
impl GameRecord { impl GameRecord {
@ -111,48 +114,34 @@ impl GameRecord {
overtime: None, overtime: None,
transcriber: None, transcriber: None,
children: vec![], trees: vec![],
} }
} }
pub fn nodes(&self) -> Vec<&GameNode> {
self.iter().collect()
}
pub fn iter(&self) -> impl Iterator<Item = &'_ GameNode> {
self.trees
.iter()
.flat_map(|tree| tree.root().unwrap().traverse_pre_order())
.map(|nr| nr.data())
}
/// Generate a list of moves which constitute the main line of the game. This is the game as it /// Generate a list of moves which constitute the main line of the game. This is the game as it
/// was actually played out, and by convention consists of the first node in each list of /// was actually played out, and by convention consists of the first node in each list of
/// children. /// children.
pub fn mainline(&self) -> Vec<&GameNode> { pub fn mainline(&self) -> Option<impl Iterator<Item = &'_ GameNode>> {
let mut moves: Vec<&GameNode> = vec![]; println!("number of trees: {}", self.trees.len());
if self.trees.len() > 0 {
let mut next = self.children.first(); Some(MainlineIter {
while let Some(node) = next { next: self.trees[0].root(),
// Given that I know that I have a node, and I know that I'm going to push a reference tree: &self.trees[0],
// to it onto my final list, I want to get the first of its children. And I want to })
// keep doing that until there are no more first children. } else {
// None
// Just going to push references onto the list. No need to copy the nodes for this.
//
// Pushing a reference onto the list implicitely clones the reference, but not the data
// it is pointing to. This means that each time through the loop, `next` points to
// something else. This isn't being described very well, though, so it's worth
// reviewing in the future.
moves.push(node);
next = match node {
GameNode::MoveNode(node) => node.children.first(),
GameNode::SetupNode(node) => node.children.first(),
};
} }
moves
}
}
impl Node for GameRecord {
fn children<'a>(&'a self) -> Vec<&'a GameNode> {
self.children.iter().collect::<Vec<&'a GameNode>>()
}
fn add_child(&mut self, node: GameNode) -> &mut GameNode {
self.children.push(node);
self.children.last_mut().unwrap()
} }
} }
@ -234,6 +223,7 @@ impl TryFrom<&parser::Tree> for GameRecord {
} }
} }
/*
s.children = tree s.children = tree
.root .root
.next .next
@ -241,35 +231,66 @@ impl TryFrom<&parser::Tree> for GameRecord {
.map(GameNode::try_from) .map(GameNode::try_from)
.collect::<Result<Vec<GameNode>, GameNodeError>>() .collect::<Result<Vec<GameNode>, GameNodeError>>()
.map_err(GameError::InvalidGameNode)?; .map_err(GameError::InvalidGameNode)?;
*/
s.trees = vec![];
Ok(s) Ok(s)
} }
} }
pub struct TreeIter<'a> {
queue: VecDeque<NodeRef<'a, &'a GameNode>>,
}
impl<'a> Default for TreeIter<'a> {
fn default() -> Self {
TreeIter {
queue: VecDeque::default(),
}
}
}
impl<'a> Iterator for TreeIter<'a> {
type Item = &'a GameNode;
fn next(&mut self) -> Option<Self::Item> {
let retval = self.queue.pop_front();
if let Some(ref retval) = retval {
retval
.children()
.for_each(|node| self.queue.push_back(node));
}
retval.map(|rv| *rv.data())
}
}
pub struct MainlineIter<'a> {
next: Option<NodeRef<'a, GameNode>>,
tree: &'a Tree<GameNode>,
}
impl<'a> Iterator for MainlineIter<'a> {
type Item = &'a GameNode;
fn next(&mut self) -> Option<Self::Item> {
if let Some(next) = self.next.take() {
let ret = self.tree.get(next.node_id())?;
self.next = next
.first_child()
.and_then(|child| self.tree.get(child.node_id()));
Some(ret.data())
} else {
None
}
}
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum GameNode { pub enum GameNode {
MoveNode(MoveNode), MoveNode(MoveNode),
SetupNode(SetupNode), SetupNode(SetupNode),
} }
pub trait Node {
/// Provide a pre-order traversal of all of the nodes in the game tree.
fn nodes<'a>(&'a self) -> Vec<&'a GameNode> {
self.children()
.iter()
.flat_map(|node| {
let mut children = node.nodes();
let mut v = vec![*node];
v.append(&mut children);
v
})
.collect::<Vec<&'a GameNode>>()
}
fn children(&self) -> Vec<&GameNode>;
fn add_child(&mut self, node: GameNode) -> &mut GameNode;
}
impl GameNode { impl GameNode {
pub fn id(&self) -> Uuid { pub fn id(&self) -> Uuid {
match self { match self {
@ -279,29 +300,6 @@ impl GameNode {
} }
} }
impl Node for GameNode {
fn children(&self) -> Vec<&GameNode> {
match self {
GameNode::MoveNode(node) => node.children(),
GameNode::SetupNode(node) => node.children(),
}
}
fn nodes(&self) -> Vec<&GameNode> {
match self {
GameNode::MoveNode(node) => node.nodes(),
GameNode::SetupNode(node) => node.nodes(),
}
}
fn add_child(&mut self, new_node: GameNode) -> &mut GameNode {
match self {
GameNode::MoveNode(node) => node.add_child(new_node),
GameNode::SetupNode(node) => node.add_child(new_node),
}
}
}
impl TryFrom<&parser::Node> for GameNode { impl TryFrom<&parser::Node> for GameNode {
type Error = GameNodeError; type Error = GameNodeError;
@ -322,27 +320,21 @@ impl TryFrom<&parser::Node> for GameNode {
// to parse all possible games. So, still, treat each branch of the game as a single line. // 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 // Iterate over that line, don't recurse. Create bookmarks at each branch point, and then
// come back to each one. // come back to each one.
/*
let children = n let children = n
.next .next
.iter() .iter()
.map(GameNode::try_from) .map(GameNode::try_from)
.collect::<Result<Vec<Self>, Self::Error>>()?; .collect::<Result<Vec<Self>, Self::Error>>()?;
*/
let node = match (move_node, setup_node) { match (move_node, setup_node) {
(Ok(mut node), _) => { (Ok(mut node), _) => Ok(Self::MoveNode(node)),
node.children = children; (Err(_), Ok(mut node)) => Ok(Self::SetupNode(node)),
Ok(Self::MoveNode(node))
}
(Err(_), Ok(mut node)) => {
node.children = children;
Ok(Self::SetupNode(node))
}
(Err(move_err), Err(setup_err)) => { (Err(move_err), Err(setup_err)) => {
Err(Self::Error::UnsupportedGameNode(move_err, setup_err)) Err(Self::Error::UnsupportedGameNode(move_err, setup_err))
} }
}?; }
Ok(node)
} }
} }
@ -351,7 +343,6 @@ pub struct MoveNode {
pub id: Uuid, pub id: Uuid,
pub color: Color, pub color: Color,
pub mv: Move, pub mv: Move,
pub children: Vec<GameNode>,
pub time_left: Option<Duration>, pub time_left: Option<Duration>,
pub moves_left: Option<usize>, pub moves_left: Option<usize>,
@ -369,7 +360,6 @@ impl MoveNode {
id: Uuid::new_v4(), id: Uuid::new_v4(),
color, color,
mv, mv,
children: Vec::new(),
time_left: None, time_left: None,
moves_left: None, moves_left: None,
@ -383,17 +373,6 @@ impl MoveNode {
} }
} }
impl Node for MoveNode {
fn children<'a>(&'a self) -> Vec<&'a GameNode> {
self.children.iter().collect::<Vec<&'a GameNode>>()
}
fn add_child(&mut self, node: GameNode) -> &mut GameNode {
self.children.push(node);
self.children.last_mut().unwrap()
}
}
impl TryFrom<&parser::Node> for MoveNode { impl TryFrom<&parser::Node> for MoveNode {
type Error = MoveNodeError; type Error = MoveNodeError;
@ -460,7 +439,6 @@ pub struct SetupNode {
id: Uuid, id: Uuid,
pub positions: Vec<parser::SetupInstr>, pub positions: Vec<parser::SetupInstr>,
pub children: Vec<GameNode>,
} }
impl SetupNode { impl SetupNode {
@ -480,22 +458,10 @@ impl SetupNode {
Ok(Self { Ok(Self {
id: Uuid::new_v4(), id: Uuid::new_v4(),
positions, positions,
children: Vec::new(),
}) })
} }
} }
impl Node for SetupNode {
fn children<'a>(&'a self) -> Vec<&'a GameNode> {
self.children.iter().collect::<Vec<&'a GameNode>>()
}
#[allow(dead_code)]
fn add_child(&mut self, _node: GameNode) -> &mut GameNode {
unimplemented!()
}
}
impl TryFrom<&parser::Node> for SetupNode { impl TryFrom<&parser::Node> for SetupNode {
type Error = SetupNodeError; type Error = SetupNodeError;
@ -507,6 +473,7 @@ impl TryFrom<&parser::Node> for SetupNode {
} }
} }
/*
#[allow(dead_code)] #[allow(dead_code)]
pub fn path_to_node(node: &GameNode, id: Uuid) -> Vec<&GameNode> { pub fn path_to_node(node: &GameNode, id: Uuid) -> Vec<&GameNode> {
if node.id() == id { if node.id() == id {
@ -523,6 +490,7 @@ pub fn path_to_node(node: &GameNode, id: Uuid) -> Vec<&GameNode> {
Vec::new() Vec::new()
} }
*/
#[cfg(test)] #[cfg(test)]
mod test { mod test {
@ -555,15 +523,19 @@ mod test {
Player::default(), Player::default(),
); );
/*
let first_move = MoveNode::new(Color::Black, Move::Move("dd".to_owned())); let first_move = MoveNode::new(Color::Black, Move::Move("dd".to_owned()));
let first_ = game.add_child(GameNode::MoveNode(first_move.clone())); let first_ = game.add_child(GameNode::MoveNode(first_move.clone()));
let second_move = MoveNode::new(Color::White, Move::Move("qq".to_owned())); let second_move = MoveNode::new(Color::White, Move::Move("qq".to_owned()));
first_.add_child(GameNode::MoveNode(second_move.clone())); first_.add_child(GameNode::MoveNode(second_move.clone()));
*/
/*
let nodes = game.nodes(); let nodes = game.nodes();
assert_eq!(nodes.len(), 2); assert_eq!(nodes.len(), 2);
assert_eq!(nodes[0].id(), first_move.id); assert_eq!(nodes[0].id(), first_move.id);
assert_eq!(nodes[1].id(), second_move.id); assert_eq!(nodes[1].id(), second_move.id);
*/
} }
#[ignore] #[ignore]
@ -633,7 +605,7 @@ mod move_node_tests {
assert_matches!(MoveNode::try_from(&n), Ok(node) => { assert_matches!(MoveNode::try_from(&n), Ok(node) => {
assert_eq!(node.color, Color::White); assert_eq!(node.color, Color::White);
assert_eq!(node.mv, Move::Move("dp".to_owned())); assert_eq!(node.mv, Move::Move("dp".to_owned()));
assert_eq!(node.children, vec![]); // assert_eq!(node.children, vec![]);
assert_eq!(node.time_left, Some(Duration::from_secs(176))); assert_eq!(node.time_left, Some(Duration::from_secs(176)));
assert_eq!(node.comments, Some("Comments in the game".to_owned())); assert_eq!(node.comments, Some("Comments in the game".to_owned()));
}); });
@ -722,7 +694,10 @@ mod path_test {
|games| { |games| {
let game = &games[0]; let game = &games[0];
let moves = game.mainline(); let moves = game
.mainline()
.expect("there should be a mainline in this file")
.collect::<Vec<&GameNode>>();
assert_matches!(moves[0], GameNode::MoveNode(node) => { assert_matches!(moves[0], GameNode::MoveNode(node) => {
assert_eq!(node.color, Color::Black); assert_eq!(node.color, Color::Black);
assert_eq!(node.mv, Move::Move("pp".to_owned())); assert_eq!(node.mv, Move::Move("pp".to_owned()));
@ -744,7 +719,10 @@ mod path_test {
with_file(std::path::Path::new("test_data/branch_test.sgf"), |games| { with_file(std::path::Path::new("test_data/branch_test.sgf"), |games| {
let game = &games[0]; let game = &games[0];
let moves = game.mainline(); let moves = game
.mainline()
.expect("there should be a mainline in this file")
.collect::<Vec<&GameNode>>();
assert_matches!(moves[1], GameNode::MoveNode(node) => { assert_matches!(moves[1], GameNode::MoveNode(node) => {
assert_eq!(node.color, Color::White); assert_eq!(node.color, Color::White);
assert_eq!(node.mv, Move::Move("dd".to_owned())); assert_eq!(node.mv, Move::Move("dd".to_owned()));
@ -875,6 +853,7 @@ mod file_test {
} }
*/ */
/*
let children = game.children(); let children = game.children();
let node = children.first().unwrap(); let node = children.first().unwrap();
assert_matches!(node, GameNode::MoveNode(node) => { assert_matches!(node, GameNode::MoveNode(node) => {
@ -892,6 +871,7 @@ mod file_test {
assert_eq!(node.time_left, Some(Duration::from_secs(1765))); assert_eq!(node.time_left, Some(Duration::from_secs(1765)));
assert_eq!(node.comments, None); assert_eq!(node.comments, None);
}); });
*/
/* /*
let node = node.next().unwrap(); let node = node.next().unwrap();
let expected_properties = vec![ let expected_properties = vec![