Switch to a standardized tree library in the game tree and depth tree #236
|
@ -29,5 +29,6 @@ pub mod library;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
|
||||||
mod types;
|
mod types;
|
||||||
pub use types::{BoardError, Color, Config, ConfigOption, LibraryPath, Player, Rank, Size};
|
pub use types::{
|
||||||
|
BoardError, Color, Config, ConfigOption, DepthTree, LibraryPath, Player, Rank, Size,
|
||||||
|
};
|
||||||
|
|
|
@ -242,7 +242,7 @@ pub struct Tree<T> {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct DepthTree(slab_tree::Tree<SizeNode>);
|
pub struct DepthTree(slab_tree::Tree<SizeNode>);
|
||||||
|
|
||||||
impl Deref for DepthTree {
|
impl Deref for DepthTree {
|
||||||
type Target = slab_tree::Tree<SizeNode>;
|
type Target = slab_tree::Tree<SizeNode>;
|
||||||
|
@ -393,13 +393,13 @@ impl DepthTree {
|
||||||
|
|
||||||
width
|
width
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
pub fn bfs_iter(&self) -> BFSIter<T> {
|
pub fn bfs_iter(&self) -> BFSIter<'_, SizeNode> {
|
||||||
let mut queue = VecDeque::new();
|
let mut queue = VecDeque::new();
|
||||||
queue.push_back(&self.nodes[0]);
|
queue.push_back(self.0.root().unwrap());
|
||||||
BFSIter { tree: self, queue }
|
BFSIter { tree: self, queue }
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a GameTree> for DepthTree {
|
impl<'a> From<&'a GameTree> for DepthTree {
|
||||||
|
@ -520,27 +520,24 @@ impl<'a> From<&'a GameNode> for Tree<Uuid> {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
pub struct BFSIter<'a, T> {
|
pub struct BFSIter<'a, T> {
|
||||||
tree: &'a Tree<T>,
|
tree: &'a DepthTree,
|
||||||
queue: VecDeque<&'a Node<T>>,
|
queue: VecDeque<slab_tree::NodeRef<'a, T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Iterator for BFSIter<'a, T> {
|
impl<'a, T> Iterator for BFSIter<'a, T> {
|
||||||
type Item = &'a Node<T>;
|
type Item = &'a T;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
let retval = self.queue.pop_front();
|
let retval = self.queue.pop_front();
|
||||||
if let Some(retval) = retval {
|
if let Some(ref retval) = retval {
|
||||||
retval
|
retval
|
||||||
.children
|
.children()
|
||||||
.iter()
|
.for_each(|noderef| self.queue.push_back(noderef));
|
||||||
.for_each(|idx| self.queue.push_back(&self.tree.nodes[*idx]));
|
|
||||||
}
|
}
|
||||||
retval
|
retval.map(|retval| retval.data())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
|
@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with On
|
||||||
use cairo::Context;
|
use cairo::Context;
|
||||||
use glib::Object;
|
use glib::Object;
|
||||||
use gtk::{prelude::*, subclass::prelude::*};
|
use gtk::{prelude::*, subclass::prelude::*};
|
||||||
use otg_core::Tree;
|
use otg_core::DepthTree;
|
||||||
use sgf::GameRecord;
|
use sgf::GameRecord;
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -28,7 +28,7 @@ const HEIGHT: i32 = 800;
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ReviewTreePrivate {
|
pub struct ReviewTreePrivate {
|
||||||
record: Rc<RefCell<Option<GameRecord>>>,
|
record: Rc<RefCell<Option<GameRecord>>>,
|
||||||
tree: Rc<RefCell<Option<Tree<Uuid>>>>,
|
tree: Rc<RefCell<Option<DepthTree>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
@ -50,7 +50,9 @@ impl ReviewTree {
|
||||||
pub fn new(record: GameRecord) -> Self {
|
pub fn new(record: GameRecord) -> Self {
|
||||||
let s: Self = Object::new();
|
let s: Self = Object::new();
|
||||||
|
|
||||||
*s.imp().tree.borrow_mut() = Some(Tree::from(&record.children[0]));
|
// TODO: there can be more than one tree, especially in instructional files. Either unify
|
||||||
|
// them into a single tree in the GameTree, or draw all of them here.
|
||||||
|
*s.imp().tree.borrow_mut() = Some(DepthTree::from(&record.trees[0]));
|
||||||
*s.imp().record.borrow_mut() = Some(record);
|
*s.imp().record.borrow_mut() = Some(record);
|
||||||
|
|
||||||
s.set_width_request(WIDTH);
|
s.set_width_request(WIDTH);
|
||||||
|
@ -67,7 +69,7 @@ impl ReviewTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redraw(&self, ctx: &Context, _width: i32, _height: i32) {
|
pub fn redraw(&self, ctx: &Context, _width: i32, _height: i32) {
|
||||||
let tree: &Option<Tree<Uuid>> = &self.imp().tree.borrow();
|
let tree: &Option<DepthTree> = &self.imp().tree.borrow();
|
||||||
match tree {
|
match tree {
|
||||||
Some(ref tree) => {
|
Some(ref tree) => {
|
||||||
for node in tree.bfs_iter() {
|
for node in tree.bfs_iter() {
|
||||||
|
@ -76,7 +78,7 @@ impl ReviewTree {
|
||||||
// the parent? do I need to just make it more intrinsically a part of the position
|
// the parent? do I need to just make it more intrinsically a part of the position
|
||||||
// code?
|
// code?
|
||||||
ctx.set_source_rgb(0.7, 0.7, 0.7);
|
ctx.set_source_rgb(0.7, 0.7, 0.7);
|
||||||
let (row, column) = tree.position(node.id);
|
let (row, column) = node.position();
|
||||||
let y = (row as f64) * 20. + 10.;
|
let y = (row as f64) * 20. + 10.;
|
||||||
let x = (column as f64) * 20. + 10.;
|
let x = (column as f64) * 20. + 10.;
|
||||||
ctx.arc(x, y, 5., 0., 2. * std::f64::consts::PI);
|
ctx.arc(x, y, 5., 0., 2. * std::f64::consts::PI);
|
||||||
|
|
|
@ -55,9 +55,10 @@ impl GameReview {
|
||||||
// It's actually really bad to be just throwing away errors. Panics make everyone unhappy.
|
// It's actually really bad to be just throwing away errors. Panics make everyone unhappy.
|
||||||
// This is not a fatal error, so I'll replace this `unwrap` call with something that
|
// This is not a fatal error, so I'll replace this `unwrap` call with something that
|
||||||
// renders the board and notifies the user of a problem that cannot be resolved.
|
// renders the board and notifies the user of a problem that cannot be resolved.
|
||||||
let board_repr = otg_core::Goban::default()
|
let board_repr = match record.mainline() {
|
||||||
.apply_moves(record.mainline())
|
Some(iter) => otg_core::Goban::default().apply_moves(iter).unwrap(),
|
||||||
.unwrap();
|
None => otg_core::Goban::default(),
|
||||||
|
};
|
||||||
let board = Goban::new(board_repr, resources);
|
let board = Goban::new(board_repr, resources);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -136,7 +136,6 @@ impl GameRecord {
|
||||||
/// 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) -> Option<impl Iterator<Item = &'_ GameNode>> {
|
pub fn mainline(&self) -> Option<impl Iterator<Item = &'_ GameNode>> {
|
||||||
println!("number of trees: {}", self.trees.len());
|
|
||||||
if !self.trees.is_empty() {
|
if !self.trees.is_empty() {
|
||||||
Some(MainlineIter {
|
Some(MainlineIter {
|
||||||
next: self.trees[0].root(),
|
next: self.trees[0].root(),
|
||||||
|
|
Loading…
Reference in New Issue