Skip to content

Commit

Permalink
Support newlines and passing. (#5)
Browse files Browse the repository at this point in the history
* Support newline in SGF file
* Support for passing, with rewrite of `SgfToken::Move`
  • Loading branch information
Sagebati authored and Michael committed Sep 10, 2019
1 parent 92dd827 commit 834dc4a
Show file tree
Hide file tree
Showing 13 changed files with 165 additions and 85 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target
**/*.rs.bk
Cargo.lock
.idea
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ keywords = ["parser", "sgf", "go", "baduk", "weiqi"]
[dependencies]
pest = "2.1.0"
pest_derive = "2.1.0"
derive_more = "0.14.0"
derive_more = "0.15.0"
3 changes: 3 additions & 0 deletions sgf.pest
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
WHITESPACE = _{ " " | NEWLINE}

game_tree = { "(" ~ sequence? ~ game_tree* ~ ")"}
sequence = { node{1,} }
node = { ";" ~ property+ }
Expand All @@ -9,3 +11,4 @@ char = {
"\\" ~ "]"
| !("]") ~ ANY
}

2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ mod tree;
pub use crate::error::{SgfError, SgfErrorKind};
pub use crate::node::GameNode;
pub use crate::parser::parse;
pub use crate::token::{Color, SgfToken};
pub use crate::token::{Color, SgfToken, Action};
pub use crate::tree::GameTree;
4 changes: 2 additions & 2 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ impl GameNode {
SgfToken::Unknown(_) => true,
_ => false,
})
.collect::<Vec<_>>()
.collect()
}

/// Gets a vector of all `SgfToken::Invalid` tokens
Expand All @@ -26,7 +26,7 @@ impl GameNode {
SgfToken::Invalid(_) => true,
_ => false,
})
.collect::<Vec<_>>()
.collect()
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,8 @@ fn parse_pair(pair: Pair<'_, Rule>) -> ParserNode<'_> {
Rule::char => {
unreachable!();
}
Rule::WHITESPACE => {
unreachable!();
}
}
}
78 changes: 47 additions & 31 deletions src/token.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{SgfError, SgfErrorKind};
use std::ops::Not;
use crate::token::Action::{Pass, Move};

/// Indicates what color the token is related to
#[derive(Debug, PartialEq, Copy, Clone)]
Expand All @@ -18,11 +19,17 @@ impl Not for Color {
}
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Action {
Move(u8, u8),
Pass,
}

/// Enum describing all possible SGF Properties
#[derive(Debug, PartialEq, Clone)]
pub enum SgfToken {
Add { color: Color, coordinate: (u8, u8) },
Move { color: Color, coordinate: (u8, u8) },
Move { color: Color, action: Action },
Time { color: Color, time: u32 },
PlayerName { color: Color, name: String },
PlayerRank { color: Color, rank: String },
Expand Down Expand Up @@ -53,7 +60,10 @@ impl SgfToken {
/// use sgf_parser::*;
///
/// let token = SgfToken::from_pair("B", "aa");
/// assert_eq!(token, SgfToken::Move { color: Color::Black, coordinate: (1, 1) });
/// assert_eq!(token, SgfToken::Move { color: Color::Black, action: Action::Move(1, 1) });
///
/// let token = SgfToken::from_pair("B", "");
/// assert_eq!(token, SgfToken::Move { color: Color::Black, action: Action::Pass });
///
/// let token = SgfToken::from_pair("B", "not_coord");
/// assert_eq!(token, SgfToken::Invalid(("B".to_string(), "not_coord".to_string())));
Expand Down Expand Up @@ -87,11 +97,11 @@ impl SgfToken {
color: Color::Black,
coordinate,
}),
"B" => str_to_coordinates(value)
"B" => move_str_to_coord(value)
.ok()
.map(|coordinate| SgfToken::Move {
color: Color::Black,
coordinate,
action: coordinate,
}),
"BL" => value.parse().ok().map(|time| SgfToken::Time {
color: Color::Black,
Expand All @@ -111,11 +121,11 @@ impl SgfToken {
color: Color::White,
coordinate,
}),
"W" => str_to_coordinates(value)
"W" => move_str_to_coord(value)
.ok()
.map(|coordinate| SgfToken::Move {
color: Color::White,
coordinate,
action: coordinate,
}),
"WL" => value.parse().ok().map(|time| SgfToken::Time {
color: Color::White,
Expand Down Expand Up @@ -201,12 +211,15 @@ impl Into<String> for &SgfToken {
let value = coordinate_to_str(*coordinate);
format!("{}[{}]", token, value)
}
SgfToken::Move { color, coordinate } => {
SgfToken::Move { color, action } => {
let token = match color {
Color::Black => "B",
Color::White => "W",
};
let value = coordinate_to_str(*coordinate);
let value = match *action {
Move(x,y) => coordinate_to_str((x,y)),
Pass => String::new()
};
format!("{}[{}]", token, value)
}
SgfToken::Time { color, time } => {
Expand Down Expand Up @@ -260,14 +273,11 @@ fn split_size_text(input: &str) -> Option<(u32, u32)> {
Some((width, height))
}


/// Converts goban coordinates to string representation
fn coordinate_to_str(coordinate: (u8, u8)) -> String {
let conv = |n| {
// skips 'I' as a valid coordinate
n + if n >= 9 { 97 } else { 96 }
};
let x = conv(coordinate.0) as char;
let y = conv(coordinate.1) as char;
let x = (coordinate.0 + 96) as char;
let y = (coordinate.1 + 96) as char;
[x, y].iter().collect()
}

Expand All @@ -280,29 +290,35 @@ fn split_label_text(input: &str) -> Option<(&str, &str)> {
}
}

fn move_str_to_coord(input: &str) -> Result<Action, SgfError> {
if input.is_empty() {
Ok(Pass)
} else {
match str_to_coordinates(input) {
Ok(coordinates) => Ok(Move(coordinates.0, coordinates.1)),
Err(e) => Err(e)
}
}
}

/// Converts a string describing goban coordinates to numeric coordinates
/// skips 'I' as a valid coordinate
fn str_to_coordinates(input: &str) -> Result<(u8, u8), SgfError> {
if input.len() != 2 {
return Err(SgfErrorKind::ParseError.into());
Err(SgfErrorKind::ParseError.into())
} else {
let coords = input
.to_lowercase()
.as_bytes()
.iter()
.map(|c| convert_u8_to_coordinate(*c))
.collect::<Vec<_>>();
Ok((coords[0], coords[1]))
}
let coords = input
.to_lowercase()
.as_bytes()
.iter()
.map(|&c| convert_u8_to_coordinate(c))
.take(2)
.collect::<Vec<_>>();
Ok((coords[0], coords[1]))
}

/// Converts a u8 char to numeric coordinates
///
#[inline]
fn convert_u8_to_coordinate(c: u8) -> u8 {
let n = c - 96;
// skips 'I' as a valid coordinate
if n >= 9 {
n - 1
} else {
n
}
c - 96
}
19 changes: 10 additions & 9 deletions tests/model.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[cfg(test)]
mod model_tests {
use sgf_parser::*;
use sgf_parser::Action::Move;

#[test]
fn can_get_unknown_nodes() {
Expand All @@ -13,7 +14,7 @@ mod model_tests {
tokens: vec![
SgfToken::Move {
color: Color::White,
coordinate: (5, 6)
action: Move(5, 6),
},
SgfToken::Unknown(("AC".to_string(), "23".to_string()))
]
Expand Down Expand Up @@ -56,7 +57,7 @@ mod model_tests {
Some(&GameNode {
tokens: vec![SgfToken::Move {
color: Color::Black,
coordinate: (4, 3)
action: Move(4, 3),
}]
})
);
Expand All @@ -65,7 +66,7 @@ mod model_tests {
Some(&GameNode {
tokens: vec![SgfToken::Move {
color: Color::White,
coordinate: (5, 6)
action: Move(5, 6),
}]
})
);
Expand All @@ -82,7 +83,7 @@ mod model_tests {
Some(&GameNode {
tokens: vec![SgfToken::Move {
color: Color::Black,
coordinate: (4, 3)
action: Move(4, 3),
}]
})
);
Expand All @@ -91,7 +92,7 @@ mod model_tests {
Some(&GameNode {
tokens: vec![SgfToken::Move {
color: Color::White,
coordinate: (5, 6)
action: Move(5, 6),
}]
})
);
Expand All @@ -100,7 +101,7 @@ mod model_tests {
Some(&GameNode {
tokens: vec![SgfToken::Move {
color: Color::Black,
coordinate: (1, 1)
action: Move(1, 1),
}]
})
);
Expand All @@ -122,7 +123,7 @@ mod model_tests {
Some(&GameNode {
tokens: vec![SgfToken::Move {
color: Color::Black,
coordinate: (4, 3)
action: Move(4, 3),
}]
})
);
Expand All @@ -131,7 +132,7 @@ mod model_tests {
Some(&GameNode {
tokens: vec![SgfToken::Move {
color: Color::White,
coordinate: (5, 6)
action: Move(5, 6),
}]
})
);
Expand All @@ -140,7 +141,7 @@ mod model_tests {
Some(&GameNode {
tokens: vec![SgfToken::Move {
color: Color::Black,
coordinate: (3, 3)
action: Move(3, 3),
}]
})
);
Expand Down
Loading

0 comments on commit 834dc4a

Please sign in to comment.