Compare commits

..

No commits in common. "8fc9f18d842865ec73a54be6f886bc73caed97e8" and "511f1080a75dfa9492ee503a1e265e222ac9e74a" have entirely different histories.

5 changed files with 139 additions and 196 deletions

16
Cargo.lock generated
View File

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

View File

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

View File

@ -3,11 +3,7 @@ use crate::{
Color, Date, GameResult, GameType,
};
use serde::{Deserialize, Serialize};
use slab_tree::{NodeId, NodeMut, NodeRef, Tree};
use std::{
collections::{HashSet, VecDeque},
time::Duration,
};
use std::{collections::HashSet, time::Duration};
use uuid::Uuid;
#[derive(Clone, Debug, PartialEq)]
@ -36,7 +32,7 @@ pub enum SetupNodeError {
#[derive(Clone, Debug, PartialEq)]
pub enum GameNodeError {
UnsupportedGameNode(MoveNodeError, SetupNodeError, parser::Node),
UnsupportedGameNode(MoveNodeError, SetupNodeError),
ConflictingProperty,
ConflictingPosition,
}
@ -56,6 +52,7 @@ pub struct Player {
/// 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
/// whatever).
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct GameRecord {
pub game_type: GameType,
@ -81,7 +78,7 @@ pub struct GameRecord {
pub overtime: Option<String>,
pub transcriber: Option<String>,
pub trees: Vec<Tree<GameNode>>,
pub children: Vec<GameNode>,
}
impl GameRecord {
@ -114,41 +111,55 @@ impl GameRecord {
overtime: None,
transcriber: None,
trees: vec![],
children: 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
/// was actually played out, and by convention consists of the first node in each list of
/// children.
pub fn mainline(&self) -> Option<impl Iterator<Item = &'_ GameNode>> {
println!("number of trees: {}", self.trees.len());
if self.trees.len() > 0 {
Some(MainlineIter {
next: self.trees[0].root(),
tree: &self.trees[0],
})
} else {
None
pub fn mainline(&self) -> Vec<&GameNode> {
let mut moves: Vec<&GameNode> = vec![];
let mut next = self.children.first();
while let Some(node) = next {
// Given that I know that I have a node, and I know that I'm going to push a reference
// 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.
//
// 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 TryFrom<parser::Tree> for GameRecord {
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()
}
}
impl TryFrom<&parser::Tree> for GameRecord {
type Error = GameError;
fn try_from(tree: parser::Tree) -> Result<Self, Self::Error> {
fn try_from(tree: &parser::Tree) -> Result<Self, Self::Error> {
let mut ty = None;
let mut size = None;
let mut black_player = Player {
@ -223,7 +234,6 @@ impl TryFrom<parser::Tree> for GameRecord {
}
}
/*
s.children = tree
.root
.next
@ -231,100 +241,35 @@ impl TryFrom<parser::Tree> for GameRecord {
.map(GameNode::try_from)
.collect::<Result<Vec<GameNode>, GameNodeError>>()
.map_err(GameError::InvalidGameNode)?;
*/
s.trees = tree.root.next.into_iter()
.map(recursive_tree_to_slab_tree)
.collect::<Result<Vec<Tree<GameNode>>, GameError>>()?;
Ok(s)
}
}
fn recursive_tree_to_slab_tree(node: parser::Node) -> Result<Tree<GameNode>, GameError> {
let mut slab = Tree::new();
let mut nodes: VecDeque<(NodeId, parser::Node)> = VecDeque::new();
let root_id =
slab.set_root(GameNode::try_from(node.clone()).map_err(GameError::InvalidGameNode)?);
nodes.push_back((root_id, node));
// I need to keep track of the current parent, and I need to keep on digging deeper into the
// tree. Given that I have the root, I can then easily find out all of the children.
//
// So, maybe I take the list of children. Assign each one of them to a place in the slab tree.
// Then push the child *and* its ID into a dequeue. So long as the dequeue is not empty, I want
// to pop a node and its ID from the dequeue. The retrieve the NodeMut for it and work on the
// node's children.
while let Some((node_id, node)) = nodes.pop_front() {
let mut game_node: NodeMut<GameNode> = slab
.get_mut(node_id)
.expect("invalid node_id when retrieving nodes from the game");
// I have a node that is in the tree. Now run across all of its children, adding each one
// to the tree and pushing them into the deque along with their IDs.
for child in node.next {
let slab_child = game_node
.append(GameNode::try_from(child.clone()).map_err(GameError::InvalidGameNode)?);
nodes.push_back((slab_child.node_id(), child));
}
}
Ok(slab)
}
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)]
pub enum GameNode {
MoveNode(MoveNode),
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 {
pub fn id(&self) -> Uuid {
match self {
@ -334,10 +279,33 @@ impl GameNode {
}
}
impl TryFrom<parser::Node> for 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 {
type Error = GameNodeError;
fn try_from(n: parser::Node) -> Result<Self, Self::Error> {
fn try_from(n: &parser::Node) -> Result<Self, Self::Error> {
// I originally wrote this recursively. However, on an ordinary game of a couple hundred
// moves, that meant that I was recursing 500 functions, and that exceeded the stack limit.
// So, instead, I need to unroll everything to non-recursive form.
@ -346,29 +314,35 @@ impl TryFrom<parser::Node> for GameNode {
// only use the MoveNode::try_from and SetupNode::try_from if those functions don't
// recurse. Instead, I'm going to process just that node, then return to here and process
// the children.
let move_node = MoveNode::try_from(n.clone());
let setup_node = SetupNode::try_from(n.clone());
let move_node = MoveNode::try_from(n);
let setup_node = SetupNode::try_from(n);
// I'm much too tired when writing this. I'm still recursing, but I did cut the number of
// recursions in half. This helps, but it still doesn't guarantee that I'm going to be able
// 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
// come back to each one.
/*
let children = n
.next
.iter()
.map(GameNode::try_from)
.collect::<Result<Vec<Self>, Self::Error>>()?;
*/
match (move_node, setup_node) {
(Ok(mut node), _) => Ok(Self::MoveNode(node)),
(Err(_), Ok(mut node)) => Ok(Self::SetupNode(node)),
let node = match (move_node, setup_node) {
(Ok(mut node), _) => {
node.children = children;
Ok(Self::MoveNode(node))
}
(Err(_), Ok(mut node)) => {
node.children = children;
Ok(Self::SetupNode(node))
}
(Err(move_err), Err(setup_err)) => {
Err(Self::Error::UnsupportedGameNode(move_err, setup_err, n))
}
Err(Self::Error::UnsupportedGameNode(move_err, setup_err))
}
}?;
Ok(node)
}
}
@ -377,6 +351,7 @@ pub struct MoveNode {
pub id: Uuid,
pub color: Color,
pub mv: Move,
pub children: Vec<GameNode>,
pub time_left: Option<Duration>,
pub moves_left: Option<usize>,
@ -394,6 +369,7 @@ impl MoveNode {
id: Uuid::new_v4(),
color,
mv,
children: Vec::new(),
time_left: None,
moves_left: None,
@ -407,10 +383,21 @@ impl MoveNode {
}
}
impl TryFrom<parser::Node> for 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 {
type Error = MoveNodeError;
fn try_from(n: parser::Node) -> Result<Self, Self::Error> {
fn try_from(n: &parser::Node) -> Result<Self, Self::Error> {
let s = match n.mv() {
Some((color, mv)) => {
let mut s = Self::new(color, mv);
@ -473,6 +460,7 @@ pub struct SetupNode {
id: Uuid,
pub positions: Vec<parser::SetupInstr>,
pub children: Vec<GameNode>,
}
impl SetupNode {
@ -492,14 +480,26 @@ impl SetupNode {
Ok(Self {
id: Uuid::new_v4(),
positions,
children: Vec::new(),
})
}
}
impl TryFrom<parser::Node> for SetupNode {
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 {
type Error = SetupNodeError;
fn try_from(n: parser::Node) -> Result<Self, Self::Error> {
fn try_from(n: &parser::Node) -> Result<Self, Self::Error> {
match n.setup() {
Some(elements) => Self::new(elements),
None => Err(Self::Error::NotASetupNode),
@ -507,7 +507,6 @@ impl TryFrom<parser::Node> for SetupNode {
}
}
/*
#[allow(dead_code)]
pub fn path_to_node(node: &GameNode, id: Uuid) -> Vec<&GameNode> {
if node.id() == id {
@ -524,7 +523,6 @@ pub fn path_to_node(node: &GameNode, id: Uuid) -> Vec<&GameNode> {
Vec::new()
}
*/
#[cfg(test)]
mod test {
@ -557,19 +555,15 @@ mod test {
Player::default(),
);
/*
let first_move = MoveNode::new(Color::Black, Move::Move("dd".to_owned()));
let first_ = game.add_child(GameNode::MoveNode(first_move.clone()));
let second_move = MoveNode::new(Color::White, Move::Move("qq".to_owned()));
first_.add_child(GameNode::MoveNode(second_move.clone()));
*/
/*
let nodes = game.nodes();
assert_eq!(nodes.len(), 2);
assert_eq!(nodes[0].id(), first_move.id);
assert_eq!(nodes[1].id(), second_move.id);
*/
}
#[ignore]
@ -594,7 +588,7 @@ mod test {
],
next: vec![],
};
assert_matches!(GameNode::try_from(n), Ok(GameNode::MoveNode(_)));
assert_matches!(GameNode::try_from(&n), Ok(GameNode::MoveNode(_)));
}
}
@ -636,10 +630,10 @@ mod move_node_tests {
],
next: vec![],
};
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.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.comments, Some("Comments in the game".to_owned()));
});
@ -659,7 +653,7 @@ mod move_node_tests {
next: vec![],
};
assert_matches!(
MoveNode::try_from(n),
MoveNode::try_from(&n),
Err(MoveNodeError::IncompatibleProperty(_))
);
}
@ -709,7 +703,7 @@ mod path_test {
let (_, games) = parse_collection::<nom::error::VerboseError<&str>>(text).unwrap();
let games = games
.into_iter()
.map(|game| GameRecord::try_from(game).expect("game to parse"))
.map(|game| GameRecord::try_from(&game).expect("game to parse"))
.collect::<Vec<GameRecord>>();
f(games);
}
@ -728,10 +722,7 @@ mod path_test {
|games| {
let game = &games[0];
let moves = game
.mainline()
.expect("there should be a mainline in this file")
.collect::<Vec<&GameNode>>();
let moves = game.mainline();
assert_matches!(moves[0], GameNode::MoveNode(node) => {
assert_eq!(node.color, Color::Black);
assert_eq!(node.mv, Move::Move("pp".to_owned()));
@ -753,10 +744,7 @@ mod path_test {
with_file(std::path::Path::new("test_data/branch_test.sgf"), |games| {
let game = &games[0];
let moves = game
.mainline()
.expect("there should be a mainline in this file")
.collect::<Vec<&GameNode>>();
let moves = game.mainline();
assert_matches!(moves[1], GameNode::MoveNode(node) => {
assert_eq!(node.color, Color::White);
assert_eq!(node.mv, Move::Move("dd".to_owned()));
@ -803,7 +791,7 @@ mod file_test {
let (_, games) = parse_collection::<nom::error::VerboseError<&str>>(text).unwrap();
let games = games
.into_iter()
.map(|game| GameRecord::try_from(game).expect("game to parse"))
.map(|game| GameRecord::try_from(&game).expect("game to parse"))
.collect::<Vec<GameRecord>>();
f(games);
}
@ -887,7 +875,6 @@ mod file_test {
}
*/
/*
let children = game.children();
let node = children.first().unwrap();
assert_matches!(node, GameNode::MoveNode(node) => {
@ -905,7 +892,6 @@ mod file_test {
assert_eq!(node.time_left, Some(Duration::from_secs(1765)));
assert_eq!(node.comments, None);
});
*/
/*
let node = node.next().unwrap();
let expected_properties = vec![
@ -925,29 +911,4 @@ mod file_test {
},
);
}
#[test]
fn it_can_load_a_file_with_multiple_roots() {
with_file(std::path::Path::new("test_data/multi-tree.sgf"), |games| {
assert_eq!(games.len(), 1);
let game = &games[0];
assert_eq!(game.game_type, GameType::Go);
assert_eq!(
game.board_size,
Size {
width: 19,
height: 19
}
);
assert_eq!(game.trees.len(), 2);
assert_matches!(game.trees[0].root().unwrap().data(), GameNode::MoveNode(node) => {
assert_eq!(node.color, Color::Black);
assert_eq!(node.mv, Move::Move("pd".to_owned()));
});
assert_matches!(game.trees[1].root().unwrap().data(), GameNode::MoveNode(node) => {
assert_eq!(node.color, Color::Black);
assert_eq!(node.mv, Move::Move("pc".to_owned()));
});
});
}
}

View File

@ -73,7 +73,7 @@ pub fn parse_sgf(input: &str) -> Result<Vec<Result<GameRecord, game::GameError>>
let (_, games) = parse_collection::<nom::error::VerboseError<&str>>(input)?;
let games = games
.into_iter()
.map(|game| GameRecord::try_from(game))
.map(|game| GameRecord::try_from(&game))
.collect::<Vec<Result<GameRecord, game::GameError>>>();
Ok(games)

View File

@ -1 +0,0 @@
(;GM[1]FF[4]CA[UTF-8]AP[Sabaki:0.52.2]KM[7.5]SZ[19]DT[2024-04-19](;B[pd](;W[qc];B[qd];W[pc];B[oc];W[ob];B[nc];W[nb];B[mc];W[rd];B[re];W[rc];B[qf])(;W[qf];B[nc];W[rd];B[qc];W[pi]))(;B[pc];W[qe];B[oe];W[pg];B[ld];W[qj]))