Implement game tree navigation #237
|
@ -243,6 +243,39 @@ pub struct Tree<T> {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// https://llimllib.github.io/pymag-trees/
|
||||||
|
// I want to take advantage of the Wetherell Shannon algorithm, but I want some variations. In
|
||||||
|
// their diagram, they got a tree that looks like this.
|
||||||
|
//
|
||||||
|
// O
|
||||||
|
// |\
|
||||||
|
// O O
|
||||||
|
// |\ \ \
|
||||||
|
// O O O O
|
||||||
|
// |\ |\
|
||||||
|
// O O O O
|
||||||
|
//
|
||||||
|
// In the same circumstance, what I want is this:
|
||||||
|
//
|
||||||
|
// O--
|
||||||
|
// | \
|
||||||
|
// O O
|
||||||
|
// |\ |\
|
||||||
|
// O O O O
|
||||||
|
// |\
|
||||||
|
// O O
|
||||||
|
//
|
||||||
|
// In order to keep things from being overly smooshed, I want to ensure that if a branch overlaps
|
||||||
|
// with another branch, there is some extra drawing space. This might actually be similar to adding
|
||||||
|
// the principal that "A parent should be centered over its children".
|
||||||
|
//
|
||||||
|
// So, given a tree, I need to know how many children exist at each level. Then I build parents
|
||||||
|
// atop the children. At level 3, I have four children, and that happens to be the maximum width of
|
||||||
|
// the graph.
|
||||||
|
//
|
||||||
|
// A bottom-up traversal:
|
||||||
|
// - Figure out the number of nodes at each depth
|
||||||
|
|
||||||
pub struct DepthTree(nary_tree::Tree<SizeNode>);
|
pub struct DepthTree(nary_tree::Tree<SizeNode>);
|
||||||
|
|
||||||
impl Deref for DepthTree {
|
impl Deref for DepthTree {
|
||||||
|
@ -621,7 +654,7 @@ mod test {
|
||||||
)))
|
)))
|
||||||
.node_id();
|
.node_id();
|
||||||
|
|
||||||
let node_d = game_tree
|
let _node_d = game_tree
|
||||||
.get_mut(node_c)
|
.get_mut(node_c)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
@ -630,7 +663,7 @@ mod test {
|
||||||
)))
|
)))
|
||||||
.node_id();
|
.node_id();
|
||||||
|
|
||||||
let node_e = game_tree
|
let _node_e = game_tree
|
||||||
.get_mut(node_c)
|
.get_mut(node_c)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
@ -639,7 +672,7 @@ mod test {
|
||||||
)))
|
)))
|
||||||
.node_id();
|
.node_id();
|
||||||
|
|
||||||
let node_f = game_tree
|
let _node_f = game_tree
|
||||||
.get_mut(node_c)
|
.get_mut(node_c)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
@ -648,7 +681,7 @@ mod test {
|
||||||
)))
|
)))
|
||||||
.node_id();
|
.node_id();
|
||||||
|
|
||||||
let node_g = game_tree
|
let _node_g = game_tree
|
||||||
.get_mut(node_a)
|
.get_mut(node_a)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.append(GameNode::MoveNode(MoveNode::new(
|
.append(GameNode::MoveNode(MoveNode::new(
|
||||||
|
|
|
@ -118,138 +118,3 @@ impl ReviewTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://llimllib.github.io/pymag-trees/
|
|
||||||
// I want to take advantage of the Wetherell Shannon algorithm, but I want some variations. In
|
|
||||||
// their diagram, they got a tree that looks like this.
|
|
||||||
//
|
|
||||||
// O
|
|
||||||
// |\
|
|
||||||
// O O
|
|
||||||
// |\ \ \
|
|
||||||
// O O O O
|
|
||||||
// |\ |\
|
|
||||||
// O O O O
|
|
||||||
//
|
|
||||||
// In the same circumstance, what I want is this:
|
|
||||||
//
|
|
||||||
// O--
|
|
||||||
// | \
|
|
||||||
// O O
|
|
||||||
// |\ |\
|
|
||||||
// O O O O
|
|
||||||
// |\
|
|
||||||
// O O
|
|
||||||
//
|
|
||||||
// In order to keep things from being overly smooshed, I want to ensure that if a branch overlaps
|
|
||||||
// with another branch, there is some extra drawing space. This might actually be similar to adding
|
|
||||||
// the principal that "A parent should be centered over its children".
|
|
||||||
//
|
|
||||||
// So, given a tree, I need to know how many children exist at each level. Then I build parents
|
|
||||||
// atop the children. At level 3, I have four children, and that happens to be the maximum width of
|
|
||||||
// the graph.
|
|
||||||
//
|
|
||||||
// A bottom-up traversal:
|
|
||||||
// - Figure out the number of nodes at each depth
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use sgf::{Color, GameNode, Move, MoveNode};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_calculates_width_for_single_node() {
|
|
||||||
let node = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
|
||||||
|
|
||||||
assert_eq!(node_width(&node), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_calculates_width_for_node_with_children() {
|
|
||||||
let mut node_a = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_b = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
|
||||||
let node_c = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
|
||||||
let node_d = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
|
||||||
|
|
||||||
node_a.children.push(node_b);
|
|
||||||
node_a.children.push(node_c);
|
|
||||||
node_a.children.push(node_d);
|
|
||||||
|
|
||||||
assert_eq!(node_width(&GameNode::MoveNode(node_a)), 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A
|
|
||||||
// B E
|
|
||||||
// C D
|
|
||||||
#[test]
|
|
||||||
fn it_calculates_width_with_one_deep_child() {
|
|
||||||
let mut node_a = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let mut node_b = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_c = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_d = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_e = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
|
|
||||||
node_b.children.push(GameNode::MoveNode(node_c));
|
|
||||||
node_b.children.push(GameNode::MoveNode(node_d));
|
|
||||||
assert_eq!(node_width(&GameNode::MoveNode(node_b.clone())), 2);
|
|
||||||
|
|
||||||
node_a.children.push(GameNode::MoveNode(node_b));
|
|
||||||
node_a.children.push(GameNode::MoveNode(node_e));
|
|
||||||
assert_eq!(node_width(&GameNode::MoveNode(node_a)), 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A
|
|
||||||
// B G H
|
|
||||||
// C I
|
|
||||||
// D E F
|
|
||||||
#[test]
|
|
||||||
fn it_calculates_a_complex_tree() {
|
|
||||||
let mut node_a = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let mut node_b = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let mut node_c = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_d = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_e = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_f = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_g = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let mut node_h = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_i = MoveNode::new(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));
|
|
||||||
assert_eq!(node_width(&GameNode::MoveNode(node_c.clone())), 3);
|
|
||||||
|
|
||||||
node_b.children.push(GameNode::MoveNode(node_c));
|
|
||||||
assert_eq!(node_width(&GameNode::MoveNode(node_b.clone())), 3);
|
|
||||||
|
|
||||||
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));
|
|
||||||
// This should be 4 if I were collapsing levels correctly, but it is 5 until I return to
|
|
||||||
// figure that step out.
|
|
||||||
assert_eq!(node_width(&GameNode::MoveNode(node_a.clone())), 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn a_nodes_children_get_separate_columns() {
|
|
||||||
let mut node_a = MoveNode::new(Color::Black, Move::Move("dp".to_owned()));
|
|
||||||
let node_b = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
|
||||||
let node_c = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
|
||||||
let node_d = GameNode::MoveNode(MoveNode::new(Color::Black, Move::Move("dp".to_owned())));
|
|
||||||
|
|
||||||
node_a.children.push(node_b.clone());
|
|
||||||
node_a.children.push(node_c.clone());
|
|
||||||
node_a.children.push(node_d.clone());
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
node_children_columns(&GameNode::MoveNode(node_a)),
|
|
||||||
vec![0, 1, 2]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn text_renderer() {
|
|
||||||
assert!(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue