Start building the second layer of game validation
This commit is contained in:
parent
aa8cd9e178
commit
52f663264e
121
sgf/src/game.rs
121
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<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)
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)?;
|
Loading…
Reference in New Issue