Start setting up properties for Move and Setup nodes

This commit is contained in:
Savanni D'Gerinel 2023-09-02 22:24:27 -04:00
parent aa053cd10f
commit a6be0129d6
3 changed files with 213 additions and 59 deletions

View File

@ -6,6 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
cool_asserts = { version = "*" }
chrono = { version = "0.4", features = [ "serde" ] } chrono = { version = "0.4", features = [ "serde" ] }
nom = { version = "7" } nom = { version = "7" }
serde = { version = "1", features = [ "derive" ] } serde = { version = "1", features = [ "derive" ] }

View File

@ -1,6 +1,90 @@
use std::collections::HashSet;
use crate::{Color, Position}; use crate::{Color, Position};
use uuid::Uuid; use uuid::Uuid;
#[derive(Clone, Debug, PartialEq)]
pub enum PropertyError {
ConflictingProperty,
}
#[derive(Clone, Debug, PartialEq)]
pub enum SetupError {
ConflictingPosition,
}
#[derive(Clone, Debug, PartialEq)]
pub enum NodeProperty {
Comment(String),
EvenResult(f64),
GoodForBlack(f64),
GoodForWhite(f64),
Hotspot(f64),
NodeName(String),
Unclear(f64),
Value(f64),
}
#[derive(Clone, Debug, PartialEq)]
pub enum TimingProperty {
BlackTimeLeft(f64),
BlackMovesLeft(f64),
WhiteMovesLeft(f64),
WhiteTimeLeft(f64),
}
#[derive(Clone, Debug, PartialEq)]
pub enum MoveAnnotationProperty {
BadMove(f64),
DoubtfulMove(f64),
InterestingMove(f64),
Tesuji(f64),
}
#[derive(Clone, Debug, PartialEq)]
pub enum MoveProperty {
NodeProperty(NodeProperty),
TimingProperty(TimingProperty),
MoveAnnotationProperty(MoveAnnotationProperty),
}
#[derive(Clone, Debug, PartialEq, Default)]
pub struct MoveProperties(Vec<MoveProperty>);
impl MoveProperties {
pub fn add_property(&mut self, prop: MoveProperty) -> Result<(), PropertyError> {
match prop {
MoveProperty::NodeProperty(_) => {}
MoveProperty::TimingProperty(_) => {}
MoveProperty::MoveAnnotationProperty(_) => {
if contains_move_annotation_property(&self.0) {
return Err(PropertyError::ConflictingProperty);
}
self.0.push(prop);
}
}
return Ok(());
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum SetupProperty {
NodeProperty(NodeProperty),
AddBlack(Vec<Position>),
AddWhite(Vec<Position>),
ClearPoints(Vec<Position>),
PlayerTurn(Color),
}
#[derive(Clone, Debug, PartialEq, Default)]
pub struct SetupProperties(Vec<SetupProperty>);
impl SetupProperties {
pub fn add_property(&mut self, prop: SetupProperty) {
unimplemented!()
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum GameNode { pub enum GameNode {
MoveNode(MoveNode), MoveNode(MoveNode),
@ -8,8 +92,6 @@ pub enum GameNode {
} }
pub trait Node { pub trait Node {
fn children<'a>(&'a self) -> Vec<&'a GameNode>;
/// Provide a pre-order traversal of all of the nodes in the game tree. /// Provide a pre-order traversal of all of the nodes in the game tree.
fn nodes<'a>(&'a self) -> Vec<&'a GameNode> { fn nodes<'a>(&'a self) -> Vec<&'a GameNode> {
self.children() self.children()
@ -24,8 +106,8 @@ pub trait Node {
.collect::<Vec<&'a GameNode>>() .collect::<Vec<&'a GameNode>>()
} }
fn children<'a>(&'a self) -> Vec<&'a GameNode>;
fn add_child<'a>(&'a mut self, node: GameNode) -> &'a mut GameNode; fn add_child<'a>(&'a mut self, node: GameNode) -> &'a mut GameNode;
fn add_annotation(&mut self, label: String, note: String);
} }
impl GameNode { impl GameNode {
@ -35,10 +117,6 @@ impl GameNode {
GameNode::SetupNode(node) => node.id, GameNode::SetupNode(node) => node.id,
} }
} }
fn children<'a>(&'a self) -> Vec<&'a GameNode> {
unimplemented!("GameNode::children")
}
} }
impl Node for GameNode { impl Node for GameNode {
@ -62,10 +140,6 @@ impl Node for GameNode {
GameNode::SetupNode(node) => node.add_child(new_node), GameNode::SetupNode(node) => node.add_child(new_node),
} }
} }
fn add_annotation(&mut self, label: String, note: String) {
unimplemented!()
}
} }
// Root node // Root node
@ -77,11 +151,6 @@ impl GameTree {
fn new() -> Self { fn new() -> Self {
Self { children: vec![] } Self { children: vec![] }
} }
fn add_child<'a>(&'a mut self, node: GameNode) -> &'a mut GameNode {
self.children.push(node);
self.children.last_mut().unwrap()
}
} }
impl Node for GameTree { impl Node for GameTree {
@ -90,11 +159,8 @@ impl Node for GameTree {
} }
fn add_child<'a>(&'a mut self, node: GameNode) -> &'a mut GameNode { fn add_child<'a>(&'a mut self, node: GameNode) -> &'a mut GameNode {
unimplemented!() self.children.push(node);
} self.children.last_mut().unwrap()
fn add_annotation(&mut self, label: String, note: String) {
unimplemented!()
} }
} }
@ -104,7 +170,7 @@ pub struct MoveNode {
color: Color, color: Color,
position: Position, position: Position,
annotations: Vec<(String, String)>, properties: MoveProperties,
children: Vec<GameNode>, children: Vec<GameNode>,
} }
@ -115,10 +181,14 @@ impl MoveNode {
color, color,
position, position,
annotations: Vec::new(), properties: MoveProperties::default(),
children: Vec::new(), children: Vec::new(),
} }
} }
fn add_property(&mut self, prop: MoveProperty) -> Result<(), PropertyError> {
self.properties.add_property(prop)
}
} }
impl Node for MoveNode { impl Node for MoveNode {
@ -130,29 +200,31 @@ impl Node for MoveNode {
self.children.push(node); self.children.push(node);
self.children.last_mut().unwrap() self.children.last_mut().unwrap()
} }
fn add_annotation(&mut self, label: String, note: String) {
unimplemented!()
}
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct SetupNode { pub struct SetupNode {
id: Uuid, id: Uuid,
positions: Vec<(Color, Position)>, positions: Vec<(Option<Color>, Position)>,
annotations: Vec<(String, String)>,
children: Vec<GameNode>, children: Vec<GameNode>,
} }
impl SetupNode { impl SetupNode {
pub fn new(positions: Vec<(Color, Position)>) -> Self { pub fn new(positions: Vec<(Option<Color>, Position)>) -> Result<Self, SetupError> {
Self { let mut coords: HashSet<Position> = HashSet::new();
for coord in positions.iter().map(|p| p.1.clone()) {
if coords.contains(&coord) {
return Err(SetupError::ConflictingPosition);
}
coords.insert(coord);
}
Ok(Self {
id: Uuid::new_v4(), id: Uuid::new_v4(),
positions, positions,
annotations: Vec::new(),
children: Vec::new(), children: Vec::new(),
} })
} }
} }
@ -164,10 +236,6 @@ impl Node for SetupNode {
fn add_child<'a>(&'a mut self, node: GameNode) -> &'a mut GameNode { fn add_child<'a>(&'a mut self, node: GameNode) -> &'a mut GameNode {
unimplemented!() unimplemented!()
} }
fn add_annotation(&mut self, label: String, note: String) {
unimplemented!()
}
} }
pub fn path_to_node<'a>(node: &'a GameNode, id: Uuid) -> Vec<&'a GameNode> { pub fn path_to_node<'a>(node: &'a GameNode, id: Uuid) -> Vec<&'a GameNode> {
@ -200,9 +268,21 @@ mod test {
fn it_can_add_moves_to_a_game() { fn it_can_add_moves_to_a_game() {
let mut tree = GameTree::new(); let mut tree = GameTree::new();
let first_move = MoveNode::new(Color::Black, Position {}); let first_move = MoveNode::new(
Color::Black,
Position {
row: 'd',
column: 'd',
},
);
let first_ = tree.add_child(GameNode::MoveNode(first_move.clone())); let first_ = tree.add_child(GameNode::MoveNode(first_move.clone()));
let second_move = MoveNode::new(Color::White, Position {}); let second_move = MoveNode::new(
Color::White,
Position {
row: 'q',
column: 'q',
},
);
first_.add_child(GameNode::MoveNode(second_move.clone())); first_.add_child(GameNode::MoveNode(second_move.clone()));
let nodes = tree.nodes(); let nodes = tree.nodes();
@ -222,6 +302,13 @@ mod test {
} }
} }
fn contains_move_annotation_property(lst: &Vec<MoveProperty>) -> bool {
lst.iter().any(|item| match item {
MoveProperty::MoveAnnotationProperty(_) => true,
_ => false,
})
}
#[cfg(test)] #[cfg(test)]
mod root_node_tests { mod root_node_tests {
#[test] #[test]
@ -242,6 +329,9 @@ mod root_node_tests {
#[cfg(test)] #[cfg(test)]
mod move_node_tests { mod move_node_tests {
use super::*;
use cool_asserts::assert_matches;
#[test] #[test]
fn it_rejects_setup_properties() { fn it_rejects_setup_properties() {
unimplemented!() unimplemented!()
@ -258,22 +348,38 @@ mod move_node_tests {
} }
#[test] #[test]
fn it_rejects_an_sgf_setup_node() { fn it_rejects_an_sgf_setup_property() {
unimplemented!() unimplemented!()
} }
#[test]
fn it_prevents_multiple_move_annotation_properties() {
let mut node = MoveNode::new(
Color::Black,
Position {
row: 'a',
column: 'b',
},
);
assert_matches!(
node.add_property(MoveProperty::MoveAnnotationProperty(
MoveAnnotationProperty::BadMove(5.),
)),
Ok(_)
);
assert_matches!(
node.add_property(MoveProperty::MoveAnnotationProperty(
MoveAnnotationProperty::Tesuji(5.),
)),
Err(PropertyError::ConflictingProperty)
);
}
} }
#[cfg(test)] #[cfg(test)]
mod setup_node_tests { mod setup_node_tests {
#[test] use super::*;
fn it_rejects_move_properties() { use cool_asserts::assert_matches;
unimplemented!()
}
#[test]
fn it_rejects_root_properties() {
unimplemented!()
}
#[test] #[test]
fn it_can_parse_an_sgf_setup_node() { fn it_can_parse_an_sgf_setup_node() {
@ -281,8 +387,52 @@ mod setup_node_tests {
} }
#[test] #[test]
fn it_rejects_an_sgf_move_node() { fn it_rejects_conflicting_placement_properties() {
unimplemented!() assert_matches!(
SetupNode::new(vec![
(
Some(Color::Black),
Position {
row: 'd',
column: 'd',
},
),
(
Some(Color::Black),
Position {
row: 'd',
column: 'd',
},
),
]),
Err(SetupError::ConflictingPosition)
);
assert_matches!(
SetupNode::new(vec![
(
Some(Color::Black),
Position {
row: 'd',
column: 'd',
},
),
(
Some(Color::Black),
Position {
row: 'e',
column: 'e',
},
),
(
Some(Color::White),
Position {
row: 'e',
column: 'e',
},
),
]),
Err(SetupError::ConflictingPosition)
);
} }
} }

View File

@ -24,8 +24,11 @@ pub enum Color {
White, White,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Position {} pub struct Position {
row: char,
column: char,
}
#[derive(Debug)] #[derive(Debug)]
pub struct VerboseNomError(nom::error::VerboseError<String>); pub struct VerboseNomError(nom::error::VerboseError<String>);