From 2bf0b3d782a3950133c89994b328bc70a3cf35c8 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Thu, 14 Sep 2023 09:22:40 -0400 Subject: [PATCH] Start building the second layer of game validation --- sgf/src/game.rs | 121 +++++++++++---------------------- sgf/src/lib.rs | 6 +- sgf/src/{tree.rs => parser.rs} | 49 ++++--------- 3 files changed, 53 insertions(+), 123 deletions(-) rename sgf/src/{tree.rs => parser.rs} (97%) diff --git a/sgf/src/game.rs b/sgf/src/game.rs index 8db25d0..b59b9b9 100644 --- a/sgf/src/game.rs +++ b/sgf/src/game.rs @@ -1,4 +1,4 @@ -use crate::{tree, Color, Position}; +use crate::{parser, Color}; use std::{collections::HashSet, time::Duration}; use uuid::Uuid; @@ -227,9 +227,9 @@ impl Node for GameNode { } } -impl TryFrom<&tree::Node> for GameNode { +impl TryFrom<&parser::Node> for GameNode { type Error = ConversionError; - fn try_from(n: &tree::Node) -> Result { + fn try_from(n: &parser::Node) -> Result { unimplemented!() } } @@ -260,7 +260,7 @@ impl Node for GameTree { pub struct MoveNode { id: Uuid, color: Color, - position: Position, + position: String, children: Vec, time_left: Option, @@ -274,7 +274,7 @@ pub struct MoveNode { } impl MoveNode { - pub fn new(color: Color, position: Position) -> Self { + pub fn new(color: Color, position: String) -> Self { Self { id: Uuid::new_v4(), color, @@ -304,42 +304,41 @@ impl Node for MoveNode { } } -impl TryFrom<&tree::Node> for MoveNode { +impl TryFrom<&parser::Node> for MoveNode { type Error = ConversionError; - fn try_from(n: &tree::Node) -> Result { - let move_ = match (n.find_prop("W"), n.find_prop("B")) { - (Some(white_move), _) => Some((Color::White, Position{ row: white_move - (None, Some(black_move)) => unimplemented!(), - (None, None) => None, - }; - - match move_ { - Some((color, position)) => unimplemented!(), + fn try_from(n: &parser::Node) -> Result { + match n.move_() { + Some((color, position)) => Ok(MoveNode::new(color, position)), None => Err(ConversionError::IncompatibleNodeType), } } } +/* fn parse_position(s: &str) -> Result { if s.len() == 2 { - Ok(Position{ row: s[0], column: s[1] }) + Ok(Position { + row: s[0], + column: s[1], + }) } else { Err(ConversionError::InvalidPositionSyntax) } } +*/ #[derive(Clone, Debug, PartialEq)] pub struct SetupNode { id: Uuid, - positions: Vec<(Option, Position)>, + positions: Vec<(Option, String)>, children: Vec, } impl SetupNode { - pub fn new(positions: Vec<(Option, Position)>) -> Result { - let mut coords: HashSet = HashSet::new(); + pub fn new(positions: Vec<(Option, String)>) -> Result { + let mut coords: HashSet = HashSet::new(); for coord in positions.iter().map(|p| p.1.clone()) { if coords.contains(&coord) { return Err(SetupError::ConflictingPosition); @@ -396,21 +395,9 @@ mod test { fn it_can_add_moves_to_a_game() { let mut tree = GameTree::new(); - let first_move = MoveNode::new( - Color::Black, - Position { - row: 'd', - column: 'd', - }, - ); + let first_move = MoveNode::new(Color::Black, "dd".to_owned()); let first_ = tree.add_child(GameNode::MoveNode(first_move.clone())); - let second_move = MoveNode::new( - Color::White, - Position { - row: 'q', - column: 'q', - }, - ); + let second_move = MoveNode::new(Color::White, "qq".to_owned()); first_.add_child(GameNode::MoveNode(second_move.clone())); let nodes = tree.nodes(); @@ -429,20 +416,19 @@ mod test { #[test] fn game_node_can_parse_sgf_move_node() { - let n = tree::Node { + let n = parser::Node { properties: vec![ - tree::Property { - ident: "W".to_owned(), - values: vec!["dp".to_owned()], - }, - tree::Property { + parser::Property::Move((Color::White, "dp".to_owned())), + /* + parser::Property { ident: "WL".to_owned(), values: vec!["176.099".to_owned()], }, - tree::Property { + parser::Property { ident: "C".to_owned(), values: vec!["Comments in the game".to_owned()], }, + */ ], next: vec![], }; @@ -472,26 +458,25 @@ mod move_node_tests { #[test] fn it_can_parse_an_sgf_move_node() { - let n = tree::Node { + let n = parser::Node { properties: vec![ - tree::Property { - ident: "W".to_owned(), - values: vec!["dp".to_owned()], - }, - tree::Property { + parser::Property::Move((Color::White, "dp".to_owned())), + /* + parser::Property { ident: "WL".to_owned(), values: vec!["176.099".to_owned()], }, - tree::Property { + parser::Property { ident: "C".to_owned(), values: vec!["Comments in the game".to_owned()], }, + */ ], next: vec![], }; assert_matches!(MoveNode::try_from(&n), Ok(node) => { assert_eq!(node.color, Color::White); - assert_eq!(node.position, Position{ row: 'd', column: 'p' }); + assert_eq!(node.position, "dp".to_owned()); assert_eq!(node.children, vec![]); assert_eq!(node.time_left, Some(Duration::from_secs(176))); assert_eq!(node.comments, vec!["Comments in the game".to_owned()]); @@ -517,46 +502,16 @@ mod setup_node_tests { fn it_rejects_conflicting_placement_properties() { assert_matches!( SetupNode::new(vec![ - ( - Some(Color::Black), - Position { - row: 'd', - column: 'd', - }, - ), - ( - Some(Color::Black), - Position { - row: 'd', - column: 'd', - }, - ), + (Some(Color::Black), "dd".to_owned(),), + (Some(Color::Black), "dd".to_owned(),), ]), 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', - }, - ), + (Some(Color::Black), "dd".to_owned(),), + (Some(Color::Black), "ee".to_owned(),), + (Some(Color::White), "ee".to_owned(),), ]), Err(SetupError::ConflictingPosition) ); diff --git a/sgf/src/lib.rs b/sgf/src/lib.rs index 51e55e8..520abaf 100644 --- a/sgf/src/lib.rs +++ b/sgf/src/lib.rs @@ -3,10 +3,10 @@ pub use date::Date; // pub mod go; -mod tree; -use tree::{parse_collection, Tree}; +mod game; -// mod game; +mod parser; +use parser::{parse_collection, Tree}; use thiserror::Error; diff --git a/sgf/src/tree.rs b/sgf/src/parser.rs similarity index 97% rename from sgf/src/tree.rs rename to sgf/src/parser.rs index 234ffe1..371db39 100644 --- a/sgf/src/tree.rs +++ b/sgf/src/parser.rs @@ -238,6 +238,18 @@ pub struct Node { pub next: Vec, } +impl Node { + pub fn move_(&self) -> Option<(Color, String)> { + self.properties + .iter() + .filter_map(|prop| match prop { + Property::Move(val) => Some(val.clone()), + _ => None, + }) + .next() + } +} + impl ToString for Node { fn to_string(&self) -> String { let props = self @@ -263,21 +275,6 @@ impl ToString for Node { } } -/* -impl Node { - pub fn find_prop(&self, ident: &str) -> Option { - self.properties - .iter() - .find(|prop| prop.ident == ident) - .cloned() - } - - pub fn next(&self) -> Option<&Node> { - self.next.get(0) - } -} -*/ - // KO // MN // N @@ -437,14 +434,6 @@ pub struct UnknownProperty { value: String, } -/* -#[derive(Clone, Debug, PartialEq)] -pub struct Property { - pub ident: String, - pub values: Vec, -} -*/ - impl ToString for Property { fn to_string(&self) -> String { match self { @@ -509,10 +498,6 @@ impl ToString for Property { format!("{}[{}]", ident, value) } } - /* - let values = self - .collect::(); - */ } } @@ -641,12 +626,6 @@ fn parse_move<'a, E: nom::error::ParseError<&'a str>>( } } -fn parse_propvals<'a, E: nom::error::ParseError<&'a str>>( - parser: impl Parser<&'a str, Property, E>, -) -> impl FnMut(&'a str) -> IResult<&'a str, Vec, E> { - many1(parse_propval(parser)) -} - fn parse_propval<'a, E: nom::error::ParseError<&'a str>>( mut parser: impl Parser<&'a str, Property, E>, ) -> impl FnMut(&'a str) -> IResult<&'a str, Property, E> { @@ -660,10 +639,6 @@ fn parse_propval<'a, E: nom::error::ParseError<&'a str>>( } } -fn discard_propvals<'a, E: nom::error::ParseError<&'a str>>() -> impl Parser<&'a str, (), E> { - many1(discard_propval()).map(|_| ()) -} - fn discard_propval<'a, E: nom::error::ParseError<&'a str>>() -> impl Parser<&'a str, (), E> { |input| { let (input, _) = multispace0(input)?;