Start building the second layer of game validation

This commit is contained in:
Savanni D'Gerinel 2023-09-14 09:22:40 -04:00
parent aa8cd9e178
commit 52f663264e
3 changed files with 53 additions and 123 deletions

View File

@ -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<Self, Self::Error> {
fn try_from(n: &parser::Node) -> Result<Self, Self::Error> {
unimplemented!()
}
}
@ -260,7 +260,7 @@ impl Node for GameTree {
pub struct MoveNode {
id: Uuid,
color: Color,
position: Position,
position: String,
children: Vec<GameNode>,
time_left: Option<Duration>,
@ -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<Self, Self::Error> {
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<Self, Self::Error> {
match n.move_() {
Some((color, position)) => Ok(MoveNode::new(color, position)),
None => Err(ConversionError::IncompatibleNodeType),
}
}
}
/*
fn parse_position(s: &str) -> Result<Position, ConversionError> {
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<Color>, Position)>,
positions: Vec<(Option<Color>, String)>,
children: Vec<GameNode>,
}
impl SetupNode {
pub fn new(positions: Vec<(Option<Color>, Position)>) -> Result<Self, SetupError> {
let mut coords: HashSet<Position> = HashSet::new();
pub fn new(positions: Vec<(Option<Color>, String)>) -> Result<Self, SetupError> {
let mut coords: HashSet<String> = 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)
);

View File

@ -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;

View File

@ -238,6 +238,18 @@ pub struct Node {
pub next: Vec<Node>,
}
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<Property> {
self.properties
.iter()
.find(|prop| prop.ident == ident)
.cloned()
}
pub fn next<'a>(&'a self) -> Option<&'a 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<String>,
}
*/
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::<String>();
*/
}
}
@ -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<Property>, 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)?;