Set up the game review page along with #229
|
@ -11,9 +11,5 @@ fn main() {
|
||||||
println!("{:?}", file);
|
println!("{:?}", file);
|
||||||
|
|
||||||
let games = parse_sgf_file(&file).unwrap();
|
let games = parse_sgf_file(&file).unwrap();
|
||||||
for sgf in games {
|
games.into_iter().flatten().for_each(|sgf| println!("{:?}", sgf.white_player));
|
||||||
if let Ok(sgf) = sgf {
|
|
||||||
println!("{:?}", sgf.white_player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,7 @@ impl GameRecord {
|
||||||
/// Generate a list of moves which constitute the main line of the game. This is the game as it
|
/// Generate a list of moves which constitute the main line of the game. This is the game as it
|
||||||
/// was actually played out, and by convention consists of the first node in each list of
|
/// was actually played out, and by convention consists of the first node in each list of
|
||||||
/// children.
|
/// children.
|
||||||
pub fn mainline<'a>(&'a self) -> Vec<&'a GameNode> {
|
pub fn mainline(&self) -> Vec<&GameNode> {
|
||||||
let mut moves: Vec<&GameNode> = vec![];
|
let mut moves: Vec<&GameNode> = vec![];
|
||||||
|
|
||||||
let mut next = self.children.get(0);
|
let mut next = self.children.get(0);
|
||||||
|
@ -150,7 +150,7 @@ impl Node for GameRecord {
|
||||||
self.children.iter().collect::<Vec<&'a GameNode>>()
|
self.children.iter().collect::<Vec<&'a GameNode>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_child<'a>(&'a mut self, node: GameNode) -> &'a mut GameNode {
|
fn add_child(&mut self, node: GameNode) -> &mut GameNode {
|
||||||
self.children.push(node);
|
self.children.push(node);
|
||||||
self.children.last_mut().unwrap()
|
self.children.last_mut().unwrap()
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ impl TryFrom<&parser::Tree> for GameRecord {
|
||||||
parser::Property::Round(v) => s.round = Some(v.clone()),
|
parser::Property::Round(v) => s.round = Some(v.clone()),
|
||||||
parser::Property::Ruleset(v) => s.rules = Some(v.clone()),
|
parser::Property::Ruleset(v) => s.rules = Some(v.clone()),
|
||||||
parser::Property::Source(v) => s.source = Some(v.clone()),
|
parser::Property::Source(v) => s.source = Some(v.clone()),
|
||||||
parser::Property::TimeLimit(v) => s.time_limit = Some(v.clone()),
|
parser::Property::TimeLimit(v) => s.time_limit = Some(*v),
|
||||||
parser::Property::Overtime(v) => s.overtime = Some(v.clone()),
|
parser::Property::Overtime(v) => s.overtime = Some(v.clone()),
|
||||||
// parser::Property::Data(v) => s.transcriber = Some(v.clone()),
|
// parser::Property::Data(v) => s.transcriber = Some(v.clone()),
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -238,7 +238,7 @@ impl TryFrom<&parser::Tree> for GameRecord {
|
||||||
.root
|
.root
|
||||||
.next
|
.next
|
||||||
.iter()
|
.iter()
|
||||||
.map(|node| GameNode::try_from(node))
|
.map(GameNode::try_from)
|
||||||
.collect::<Result<Vec<GameNode>, GameNodeError>>()
|
.collect::<Result<Vec<GameNode>, GameNodeError>>()
|
||||||
.map_err(GameError::InvalidGameNode)?;
|
.map_err(GameError::InvalidGameNode)?;
|
||||||
|
|
||||||
|
@ -257,18 +257,17 @@ pub trait Node {
|
||||||
fn nodes<'a>(&'a self) -> Vec<&'a GameNode> {
|
fn nodes<'a>(&'a self) -> Vec<&'a GameNode> {
|
||||||
self.children()
|
self.children()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|node| {
|
.flat_map(|node| {
|
||||||
let mut children = node.nodes();
|
let mut children = node.nodes();
|
||||||
let mut v = vec![*node];
|
let mut v = vec![*node];
|
||||||
v.append(&mut children);
|
v.append(&mut children);
|
||||||
v
|
v
|
||||||
})
|
})
|
||||||
.flatten()
|
|
||||||
.collect::<Vec<&'a GameNode>>()
|
.collect::<Vec<&'a GameNode>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children<'a>(&'a self) -> Vec<&'a GameNode>;
|
fn children(&self) -> Vec<&GameNode>;
|
||||||
fn add_child<'a>(&'a mut self, node: GameNode) -> &'a mut GameNode;
|
fn add_child(&mut self, node: GameNode) -> &mut GameNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameNode {
|
impl GameNode {
|
||||||
|
@ -281,21 +280,21 @@ impl GameNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for GameNode {
|
impl Node for GameNode {
|
||||||
fn children<'a>(&'a self) -> Vec<&'a GameNode> {
|
fn children(&self) -> Vec<&GameNode> {
|
||||||
match self {
|
match self {
|
||||||
GameNode::MoveNode(node) => node.children(),
|
GameNode::MoveNode(node) => node.children(),
|
||||||
GameNode::SetupNode(node) => node.children(),
|
GameNode::SetupNode(node) => node.children(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nodes<'a>(&'a self) -> Vec<&'a GameNode> {
|
fn nodes(&self) -> Vec<&GameNode> {
|
||||||
match self {
|
match self {
|
||||||
GameNode::MoveNode(node) => node.nodes(),
|
GameNode::MoveNode(node) => node.nodes(),
|
||||||
GameNode::SetupNode(node) => node.nodes(),
|
GameNode::SetupNode(node) => node.nodes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_child<'a>(&'a mut self, new_node: GameNode) -> &'a mut GameNode {
|
fn add_child(&mut self, new_node: GameNode) -> &mut GameNode {
|
||||||
match self {
|
match self {
|
||||||
GameNode::MoveNode(node) => node.add_child(new_node),
|
GameNode::MoveNode(node) => node.add_child(new_node),
|
||||||
GameNode::SetupNode(node) => node.add_child(new_node),
|
GameNode::SetupNode(node) => node.add_child(new_node),
|
||||||
|
@ -326,7 +325,7 @@ impl TryFrom<&parser::Node> for GameNode {
|
||||||
let children = n
|
let children = n
|
||||||
.next
|
.next
|
||||||
.iter()
|
.iter()
|
||||||
.map(|n| GameNode::try_from(n))
|
.map(GameNode::try_from)
|
||||||
.collect::<Result<Vec<Self>, Self::Error>>()?;
|
.collect::<Result<Vec<Self>, Self::Error>>()?;
|
||||||
|
|
||||||
let node = match (move_node, setup_node) {
|
let node = match (move_node, setup_node) {
|
||||||
|
@ -389,7 +388,7 @@ impl Node for MoveNode {
|
||||||
self.children.iter().collect::<Vec<&'a GameNode>>()
|
self.children.iter().collect::<Vec<&'a GameNode>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_child<'a>(&'a mut self, node: GameNode) -> &'a mut GameNode {
|
fn add_child(&mut self, node: GameNode) -> &mut GameNode {
|
||||||
self.children.push(node);
|
self.children.push(node);
|
||||||
self.children.last_mut().unwrap()
|
self.children.last_mut().unwrap()
|
||||||
}
|
}
|
||||||
|
@ -417,7 +416,7 @@ impl TryFrom<&parser::Node> for MoveNode {
|
||||||
if s.time_left.is_some() {
|
if s.time_left.is_some() {
|
||||||
return Err(Self::Error::ConflictingProperty);
|
return Err(Self::Error::ConflictingProperty);
|
||||||
}
|
}
|
||||||
s.time_left = Some(duration.clone());
|
s.time_left = Some(*duration);
|
||||||
}
|
}
|
||||||
parser::Property::Comment(cmt) => {
|
parser::Property::Comment(cmt) => {
|
||||||
if s.comments.is_some() {
|
if s.comments.is_some() {
|
||||||
|
@ -492,7 +491,7 @@ impl Node for SetupNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn add_child<'a>(&'a mut self, _node: GameNode) -> &'a mut GameNode {
|
fn add_child(&mut self, _node: GameNode) -> &mut GameNode {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,7 +508,7 @@ impl TryFrom<&parser::Node> for SetupNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn path_to_node<'a>(node: &'a GameNode, id: Uuid) -> Vec<&'a GameNode> {
|
pub fn path_to_node(node: &GameNode, id: Uuid) -> Vec<&GameNode> {
|
||||||
if node.id() == id {
|
if node.id() == id {
|
||||||
return vec![node];
|
return vec![node];
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ impl From<nom::error::Error<&str>> for ParseError {
|
||||||
/// The inner Result is for errors in each individual game in the file. All of the other games can
|
/// The inner Result is for errors in each individual game in the file. All of the other games can
|
||||||
/// still be kept as valid.
|
/// still be kept as valid.
|
||||||
pub fn parse_sgf(input: &str) -> Result<Vec<Result<GameRecord, game::GameError>>, Error> {
|
pub fn parse_sgf(input: &str) -> Result<Vec<Result<GameRecord, game::GameError>>, Error> {
|
||||||
let (_, games) = parse_collection::<nom::error::VerboseError<&str>>(&input)?;
|
let (_, games) = parse_collection::<nom::error::VerboseError<&str>>(input)?;
|
||||||
let games = games
|
let games = games
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|game| GameRecord::try_from(&game))
|
.map(|game| GameRecord::try_from(&game))
|
||||||
|
|
|
@ -10,7 +10,7 @@ use nom::{
|
||||||
IResult, Parser,
|
IResult, Parser,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{num::ParseIntError, time::Duration};
|
use std::{fmt::Write, num::ParseIntError, time::Duration};
|
||||||
|
|
||||||
impl From<ParseSizeError> for Error {
|
impl From<ParseSizeError> for Error {
|
||||||
fn from(_: ParseSizeError) -> Self {
|
fn from(_: ParseSizeError) -> Self {
|
||||||
|
@ -303,9 +303,9 @@ impl Move {
|
||||||
if s.len() == 2 {
|
if s.len() == 2 {
|
||||||
let mut parts = s.chars();
|
let mut parts = s.chars();
|
||||||
let row_char = parts.next().unwrap();
|
let row_char = parts.next().unwrap();
|
||||||
let row = row_char as u8 - 'a' as u8;
|
let row = row_char as u8 - b'a';
|
||||||
let column_char = parts.next().unwrap();
|
let column_char = parts.next().unwrap();
|
||||||
let column = column_char as u8 - 'a' as u8;
|
let column = column_char as u8 - b'a';
|
||||||
Some((row, column))
|
Some((row, column))
|
||||||
} else {
|
} else {
|
||||||
unimplemented!("moves must contain exactly two characters");
|
unimplemented!("moves must contain exactly two characters");
|
||||||
|
@ -527,22 +527,20 @@ impl ToString for Property {
|
||||||
Property::WhiteRank(value) => format!("WR[{}]", value),
|
Property::WhiteRank(value) => format!("WR[{}]", value),
|
||||||
Property::WhiteTeam(value) => format!("WT[{}]", value),
|
Property::WhiteTeam(value) => format!("WT[{}]", value),
|
||||||
Property::Territory(Color::White, positions) => {
|
Property::Territory(Color::White, positions) => {
|
||||||
format!(
|
positions
|
||||||
"TW{}",
|
.iter()
|
||||||
positions
|
.fold("TW".to_owned(), |mut output, Position(p)| {
|
||||||
.iter()
|
let _ = write!(output, "{}", p);
|
||||||
.map(|Position(p)| format!("[{}]", p))
|
output
|
||||||
.collect::<String>()
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Property::Territory(Color::Black, positions) => {
|
Property::Territory(Color::Black, positions) => {
|
||||||
format!(
|
positions
|
||||||
"TB{}",
|
.iter()
|
||||||
positions
|
.fold("TB".to_owned(), |mut output, Position(p)| {
|
||||||
.iter()
|
let _ = write!(output, "{}", p);
|
||||||
.map(|Position(p)| format!("[{}]", p))
|
output
|
||||||
.collect::<String>()
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
Property::Unknown(UnknownProperty { ident, value }) => {
|
Property::Unknown(UnknownProperty { ident, value }) => {
|
||||||
format!("{}[{}]", ident, value)
|
format!("{}[{}]", ident, value)
|
||||||
|
@ -965,7 +963,7 @@ fn parse_win_score<'a, E: nom::error::ParseError<&'a str>>() -> impl Parser<&'a
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const EXAMPLE: &'static str = "(;FF[4]C[root](;C[a];C[b](;C[c])
|
const EXAMPLE: &str = "(;FF[4]C[root](;C[a];C[b](;C[c])
|
||||||
(;C[d];C[e]))
|
(;C[d];C[e]))
|
||||||
(;C[f](;C[g];C[h];C[i])
|
(;C[f](;C[g];C[h];C[i])
|
||||||
(;C[j])))";
|
(;C[j])))";
|
||||||
|
|
Loading…
Reference in New Issue