Switch to a standardized tree library in the game tree and depth tree #236
|
@ -14,18 +14,18 @@ General Public License for more details.
|
||||||
You should have received a copy of the GNU General Public License along with On the Grid. If not, see <https://www.gnu.org/licenses/>.
|
You should have received a copy of the GNU General Public License along with On the Grid. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::{Core};
|
use crate::Core;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sgf::GameRecord;
|
use sgf::GameRecord;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum LibraryRequest {
|
pub enum LibraryRequest {
|
||||||
ListGames
|
ListGames,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum LibraryResponse {
|
pub enum LibraryResponse {
|
||||||
Games(Vec<GameRecord>)
|
Games(Vec<GameRecord>),
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_list_games(model: &Core) -> LibraryResponse {
|
async fn handle_list_games(model: &Core) -> LibraryResponse {
|
||||||
|
@ -39,10 +39,8 @@ async fn handle_list_games(model: &Core) -> LibraryResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn handle(model: &Core, request: LibraryRequest) -> LibraryResponse {
|
pub async fn handle(model: &Core, request: LibraryRequest) -> LibraryResponse {
|
||||||
match request {
|
match request {
|
||||||
LibraryRequest::ListGames => handle_list_games(model).await,
|
LibraryRequest::ListGames => handle_list_games(model).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@ use config::define_config;
|
||||||
use config_derive::ConfigOption;
|
use config_derive::ConfigOption;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sgf::GameTree;
|
use sgf::GameTree;
|
||||||
use std::{cell::RefCell, collections::VecDeque, fmt, path::PathBuf, time::Duration};
|
use std::{
|
||||||
|
cell::RefCell, collections::{HashMap, VecDeque}, fmt, ops::Deref, path::PathBuf, time::Duration
|
||||||
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
define_config! {
|
define_config! {
|
||||||
|
@ -242,19 +244,39 @@ pub struct Tree<T> {
|
||||||
|
|
||||||
struct DepthTree(slab_tree::Tree<SizeNode>);
|
struct DepthTree(slab_tree::Tree<SizeNode>);
|
||||||
|
|
||||||
|
impl Deref for DepthTree {
|
||||||
|
type Target = slab_tree::Tree<SizeNode>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SizeNode {
|
pub struct SizeNode {
|
||||||
pub id: usize,
|
|
||||||
node_id: slab_tree::NodeId,
|
node_id: slab_tree::NodeId,
|
||||||
parent: Option<usize>,
|
parent: Option<slab_tree::NodeId>,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
width: RefCell<Option<usize>>,
|
width: usize,
|
||||||
children: Vec<usize>,
|
}
|
||||||
|
|
||||||
|
impl SizeNode {
|
||||||
|
pub fn position(&self) -> (usize, usize) {
|
||||||
|
(self.depth, self.width)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DepthTree {
|
impl DepthTree {
|
||||||
|
// My previous work to convert from a node tree to this tree-with-width dependend on the node tree
|
||||||
|
// being a recursive data structure. Now I need to find a way to convert a slab tree to this width
|
||||||
|
// tree.
|
||||||
|
//
|
||||||
|
// It all feels like a lot of custom weirdness. I shouldn't need a bunch of custom data structures,
|
||||||
|
// so I want to eliminate the "Tree" above and keep using the slab tree. I think I should be able
|
||||||
|
// to build these Node objects without needing a custom data structure.
|
||||||
|
fn new() -> Self {
|
||||||
|
Self(slab_tree::Tree::new())
|
||||||
/*
|
/*
|
||||||
fn new(root: T) -> Self {
|
|
||||||
Tree {
|
Tree {
|
||||||
nodes: vec![Node {
|
nodes: vec![Node {
|
||||||
id: 0,
|
id: 0,
|
||||||
|
@ -265,8 +287,10 @@ impl DepthTree {
|
||||||
children: vec![],
|
children: vec![],
|
||||||
}],
|
}],
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
pub fn node(&self, idx: usize) -> &T {
|
pub fn node(&self, idx: usize) -> &T {
|
||||||
&self.nodes[idx].node
|
&self.nodes[idx].node
|
||||||
}
|
}
|
||||||
|
@ -293,13 +317,18 @@ impl DepthTree {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub fn max_depth(&self) -> usize {
|
pub fn max_depth(&self) -> usize {
|
||||||
unimplemented!()
|
self.0
|
||||||
/*
|
.root()
|
||||||
self.nodes.iter().fold(
|
.unwrap()
|
||||||
0,
|
.traverse_pre_order()
|
||||||
|max, node| if node.depth > max { node.depth } else { max },
|
.fold(0, |max, node| {
|
||||||
)
|
println!("node depth: {}", node.data().depth);
|
||||||
*/
|
if node.data().depth > max {
|
||||||
|
node.data().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
|
||||||
|
@ -317,8 +346,8 @@ impl DepthTree {
|
||||||
// amounts to the position of the parent node.
|
// amounts to the position of the parent node.
|
||||||
//
|
//
|
||||||
// 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) {
|
|
||||||
unimplemented!()
|
// unimplemented!()
|
||||||
/*
|
/*
|
||||||
let node = &self.nodes[idx];
|
let node = &self.nodes[idx];
|
||||||
match node.parent {
|
match node.parent {
|
||||||
|
@ -337,7 +366,6 @@ impl DepthTree {
|
||||||
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
|
||||||
|
@ -375,8 +403,88 @@ impl DepthTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a GameTree> for DepthTree {
|
impl<'a> From<&'a GameTree> for DepthTree {
|
||||||
fn from(root: &'a GameTree) -> Self {
|
fn from(tree: &'a GameTree) -> Self {
|
||||||
unimplemented!()
|
// Like in the conversion from SGF to GameTree, I need to traverse the entire tree one node
|
||||||
|
// at a time, keeping track of node ids as we go. I'm going to go with a depth-first
|
||||||
|
// traversal. When generating each node, I think I want to generate all of the details of
|
||||||
|
// the node as we go.
|
||||||
|
let source_root_node = tree.root();
|
||||||
|
match source_root_node {
|
||||||
|
Some(source_root_node) => {
|
||||||
|
// Do the real work
|
||||||
|
// The id_map indexes from the source tree to the destination tree. Reverse
|
||||||
|
// indexing is accomplished by looking at the node_id in a node in the destination
|
||||||
|
// tree.
|
||||||
|
let mut id_map: HashMap<slab_tree::NodeId, slab_tree::NodeId> = HashMap::new();
|
||||||
|
let mut tree = slab_tree::Tree::new();
|
||||||
|
|
||||||
|
let mut iter = source_root_node.traverse_pre_order();
|
||||||
|
let _ = iter.next().unwrap(); // we already know that the first element to be
|
||||||
|
// returned is the root node, and that the root node
|
||||||
|
// already exists. Otherwise we wouldn't even be in
|
||||||
|
// this branch.
|
||||||
|
|
||||||
|
let dest_root_id = tree.set_root(SizeNode {
|
||||||
|
node_id: source_root_node.node_id(),
|
||||||
|
parent: None,
|
||||||
|
depth: 0,
|
||||||
|
width: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
id_map.insert(source_root_node.node_id(), dest_root_id);
|
||||||
|
|
||||||
|
for source_node in iter {
|
||||||
|
let dest_parent_id = id_map
|
||||||
|
.get(&source_node.parent().unwrap().node_id())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut dest_parent = tree.get_mut(*dest_parent_id).unwrap();
|
||||||
|
|
||||||
|
let new_depth_node = SizeNode {
|
||||||
|
node_id: source_node.node_id(),
|
||||||
|
parent: Some(*dest_parent_id),
|
||||||
|
depth: 1 + dest_parent.data().depth,
|
||||||
|
width: dest_parent.data().width,
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_node_id = dest_parent.append(new_depth_node).node_id();
|
||||||
|
|
||||||
|
match tree
|
||||||
|
.get(new_node_id)
|
||||||
|
.unwrap()
|
||||||
|
.prev_sibling()
|
||||||
|
.map(|node| node.data().width)
|
||||||
|
{
|
||||||
|
None => {}
|
||||||
|
Some(previous_width) => {
|
||||||
|
let mut new_node = tree.get_mut(new_node_id).unwrap();
|
||||||
|
new_node.data().width = previous_width + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
let new_node = tree.get_mut(*dest_parent_id).unwrap().append(new_depth_node);
|
||||||
|
let previous_node = new_node.prev_sibling();
|
||||||
|
|
||||||
|
match previous_node {
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
match dest_noderef.prev_sibling() {
|
||||||
|
None => {}
|
||||||
|
Some(mut node) => { dest_noderef.data().width = node.data().width + 1 }
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
id_map.insert(source_node.node_id(), new_node_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self(tree)
|
||||||
|
}
|
||||||
|
None => Self::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,7 +618,8 @@ mod test {
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
sgf::Color::Black,
|
sgf::Color::Black,
|
||||||
Move::Move("dp".to_owned()),
|
Move::Move("dp".to_owned()),
|
||||||
))).node_id();
|
)))
|
||||||
|
.node_id();
|
||||||
|
|
||||||
let node_c = game_tree
|
let node_c = game_tree
|
||||||
.get_mut(node_b)
|
.get_mut(node_b)
|
||||||
|
@ -518,7 +627,8 @@ mod test {
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
sgf::Color::Black,
|
sgf::Color::Black,
|
||||||
Move::Move("dp".to_owned()),
|
Move::Move("dp".to_owned()),
|
||||||
))).node_id();
|
)))
|
||||||
|
.node_id();
|
||||||
|
|
||||||
let node_d = game_tree
|
let node_d = game_tree
|
||||||
.get_mut(node_c)
|
.get_mut(node_c)
|
||||||
|
@ -526,7 +636,8 @@ mod test {
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
sgf::Color::Black,
|
sgf::Color::Black,
|
||||||
Move::Move("dp".to_owned()),
|
Move::Move("dp".to_owned()),
|
||||||
))).node_id();
|
)))
|
||||||
|
.node_id();
|
||||||
|
|
||||||
let node_e = game_tree
|
let node_e = game_tree
|
||||||
.get_mut(node_c)
|
.get_mut(node_c)
|
||||||
|
@ -534,7 +645,8 @@ mod test {
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
sgf::Color::Black,
|
sgf::Color::Black,
|
||||||
Move::Move("dp".to_owned()),
|
Move::Move("dp".to_owned()),
|
||||||
))).node_id();
|
)))
|
||||||
|
.node_id();
|
||||||
|
|
||||||
let node_f = game_tree
|
let node_f = game_tree
|
||||||
.get_mut(node_c)
|
.get_mut(node_c)
|
||||||
|
@ -542,7 +654,8 @@ mod test {
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
sgf::Color::Black,
|
sgf::Color::Black,
|
||||||
Move::Move("dp".to_owned()),
|
Move::Move("dp".to_owned()),
|
||||||
))).node_id();
|
)))
|
||||||
|
.node_id();
|
||||||
|
|
||||||
let node_g = game_tree
|
let node_g = game_tree
|
||||||
.get_mut(node_a)
|
.get_mut(node_a)
|
||||||
|
@ -550,7 +663,8 @@ mod test {
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
sgf::Color::Black,
|
sgf::Color::Black,
|
||||||
Move::Move("dp".to_owned()),
|
Move::Move("dp".to_owned()),
|
||||||
))).node_id();
|
)))
|
||||||
|
.node_id();
|
||||||
|
|
||||||
let node_h = game_tree
|
let node_h = game_tree
|
||||||
.get_mut(node_a)
|
.get_mut(node_a)
|
||||||
|
@ -558,7 +672,8 @@ mod test {
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
sgf::Color::Black,
|
sgf::Color::Black,
|
||||||
Move::Move("dp".to_owned()),
|
Move::Move("dp".to_owned()),
|
||||||
))).node_id();
|
)))
|
||||||
|
.node_id();
|
||||||
|
|
||||||
let _ = game_tree
|
let _ = game_tree
|
||||||
.get_mut(node_h)
|
.get_mut(node_h)
|
||||||
|
@ -566,7 +681,8 @@ mod test {
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
sgf::Color::Black,
|
sgf::Color::Black,
|
||||||
Move::Move("dp".to_owned()),
|
Move::Move("dp".to_owned()),
|
||||||
)));
|
)))
|
||||||
|
.node_id();
|
||||||
|
|
||||||
game_tree
|
game_tree
|
||||||
}
|
}
|
||||||
|
@ -575,6 +691,10 @@ mod test {
|
||||||
fn it_can_calculate_depth_from_game_tree() {
|
fn it_can_calculate_depth_from_game_tree() {
|
||||||
let game_tree = branching_tree();
|
let game_tree = branching_tree();
|
||||||
let tree = DepthTree::from(&game_tree);
|
let tree = DepthTree::from(&game_tree);
|
||||||
|
assert_eq!(
|
||||||
|
game_tree.root().unwrap().traverse_pre_order().count(),
|
||||||
|
tree.0.root().unwrap().traverse_pre_order().count()
|
||||||
|
);
|
||||||
assert_eq!(tree.max_depth(), 3);
|
assert_eq!(tree.max_depth(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,13 +702,35 @@ mod test {
|
||||||
fn it_calculates_horizontal_position_of_nodes() {
|
fn it_calculates_horizontal_position_of_nodes() {
|
||||||
let game_tree = branching_tree();
|
let game_tree = branching_tree();
|
||||||
let tree = DepthTree::from(&game_tree);
|
let tree = DepthTree::from(&game_tree);
|
||||||
assert_eq!(tree.position(2), (2, 0));
|
|
||||||
assert_eq!(tree.position(1), (1, 0));
|
let node_a = tree.root().unwrap();
|
||||||
assert_eq!(tree.position(0), (0, 0));
|
assert_eq!(node_a.data().position(), (0, 0));
|
||||||
assert_eq!(tree.position(4), (3, 1));
|
|
||||||
assert_eq!(tree.position(5), (3, 2));
|
let node_b = node_a.first_child().unwrap();
|
||||||
assert_eq!(tree.position(6), (1, 3));
|
assert_eq!(node_b.data().position(), (1, 0));
|
||||||
assert_eq!(tree.position(7), (1, 4));
|
let node_g = node_b.next_sibling().unwrap();
|
||||||
|
assert_eq!(node_g.data().position(), (1, 1));
|
||||||
|
let node_h = node_g.next_sibling().unwrap();
|
||||||
|
assert_eq!(node_h.data().position(), (1, 2));
|
||||||
|
|
||||||
|
let node_c = node_b.first_child().unwrap();
|
||||||
|
assert_eq!(node_c.data().position(), (2, 0));
|
||||||
|
|
||||||
|
let node_d = node_c.first_child().unwrap();
|
||||||
|
assert_eq!(node_d.data().position(), (3, 0));
|
||||||
|
|
||||||
|
let node_i = node_h.first_child().unwrap();
|
||||||
|
assert_eq!(node_i.data().position(), (2, 2));
|
||||||
|
|
||||||
|
/*
|
||||||
|
assert_eq!(tree.position(test_tree.node_c), (2, 0));
|
||||||
|
assert_eq!(tree.position(test_tree.node_b), (1, 0));
|
||||||
|
assert_eq!(tree.position(test_tree.node_a), (0, 0));
|
||||||
|
assert_eq!(tree.position(test_tree.node_d), (3, 1));
|
||||||
|
assert_eq!(tree.position(test_tree.node_e), (3, 2));
|
||||||
|
assert_eq!(tree.position(test_tree.node_f), (1, 3));
|
||||||
|
assert_eq!(tree.position(test_tree.node_g), (1, 4));
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
#[ignore]
|
||||||
|
|
Loading…
Reference in New Issue