Set up a tree container that allows for some certain traversals #79

Merged
savanni merged 6 commits from tree-traversals into main 2023-10-25 03:13:39 +00:00
5 changed files with 127 additions and 0 deletions
Showing only changes of commit 52f814e663 - Show all commits

4
Cargo.lock generated
View File

@ -4060,6 +4060,10 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
[[package]]
name = "tree"
version = "0.1.0"
[[package]] [[package]]
name = "try-lock" name = "try-lock"
version = "0.2.4" version = "0.2.4"

View File

@ -20,4 +20,5 @@ members = [
"result-extended", "result-extended",
"screenplay", "screenplay",
"sgf", "sgf",
"tree",
] ]

View File

@ -23,6 +23,7 @@ RUST_ALL_TARGETS=(
"result-extended" "result-extended"
"screenplay" "screenplay"
"sgf" "sgf"
"tree"
) )
build_rust_targets() { build_rust_targets() {

8
tree/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "tree"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

113
tree/src/lib.rs Normal file
View File

@ -0,0 +1,113 @@
//! This data structure is a generic tree which can contain any data. That data itself need to keep
//! track of its own tree structure.
//!
//! This surely already exists. I am created it to test my own ability to do things in Rust.
use std::{cell::RefCell, collections::VecDeque, rc::Rc};
#[derive(Debug)]
pub enum Tree<T> {
Empty,
Root(Rc<RefCell<Node<T>>>),
}
impl<T> Default for Tree<T> {
fn default() -> Self {
Tree::Empty
}
}
impl<T> Tree<T> {
pub fn set_value(&mut self, value: T) {
*self = Tree::Root(Rc::new(RefCell::new(Node::new(value))));
}
pub fn find_bfs<'a, F>(&'a self, op: F) -> Option<Rc<RefCell<Node<T>>>>
where
F: FnOnce(&T) -> bool + Copy,
{
let mut queue: VecDeque<Rc<RefCell<Node<T>>>> = match self {
Tree::Empty => VecDeque::new(),
Tree::Root(node) => {
let mut queue = VecDeque::new();
queue.push_back(node.clone());
queue
}
};
while let Some(node) = queue.pop_front() {
if op(&node.borrow().value) {
return Some(node.clone());
}
for child in node.borrow().children.iter() {
queue.push_back(child.clone());
}
}
None
}
}
#[derive(Debug, PartialEq)]
pub struct Node<T> {
value: T,
children: Vec<Rc<RefCell<Node<T>>>>,
}
impl<T> Node<T> {
pub fn new(value: T) -> Self {
Self {
value,
children: vec![],
}
}
pub fn children<'a>(&'a self) -> &'a Vec<Rc<RefCell<Node<T>>>> {
&self.children
}
pub fn value<'a>(&'a self) -> &'a T {
&self.value
}
pub fn value_mut<'a>(&'a mut self) -> &'a mut T {
&mut self.value
}
pub fn add_child_node(&mut self, child: Node<T>) {
self.children.push(Rc::new(RefCell::new(child)));
}
pub fn add_child_value(&mut self, value: T) {
self.children.push(Rc::new(RefCell::new(Node::new(value))));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn can_find_node_in_tree() {
let mut tree = Tree::default();
tree.set_value(15);
assert!(tree.find_bfs(|val| *val == 15).is_some());
assert!(tree.find_bfs(|val| *val == 16).is_none());
{
let node_ref = tree.find_bfs(|val| *val == 15).unwrap();
node_ref.borrow_mut().add_child_value(20);
}
assert!(tree.find_bfs(|val| *val == 20).is_some());
}
#[test]
fn node_can_add_children() {
let mut n = Node::new(15);
n.add_child_value(20);
assert_eq!(n.value, 15);
assert_eq!(n.children, vec![Rc::new(RefCell::new(Node::new(20)))]);
}
}