1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
use std::fmt::Debug;
use crate::{go, unknown_game, SgfNode, SgfParseError};
/// The game recorded in a [`GameTree`].
///
/// Any [`GameTree`] retured by [`parse`](`crate::parse`) will have a game type which corresponds to
/// the SGF `GM` property of the root node.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GameType {
Go,
Unknown,
}
/// An SGF [GameTree](https://www.red-bean.com/sgf/sgf4.html#ebnf-def) value.
///
/// This type allows creating a collection of [`SgfNode`] values for different games. This is
/// used in the return type of the [`parse`](`crate::parse()`) function. Users of the
/// [`serialize`](`crate::serialize()`) function will need to build these.
///
/// For now, all non-Go games will parse as [`GameTree::Unknown`] which should also be used for any
/// serialization of non-Go games.
#[derive(Clone, Debug, PartialEq)]
pub enum GameTree {
GoGame(SgfNode<go::Prop>),
Unknown(SgfNode<unknown_game::Prop>),
}
impl GameTree {
/// Consumes a Go game `GameTree` and returns the contained [`SgfNode`].
///
/// This is a convenience method for go games.
///
/// # Errors
/// Returns an error if the variant isn't a [`GameTree::GoGame`].
///
/// # Examples
/// ```
/// use sgf_parse::parse;
///
/// let gametree = parse("(;B[de]C[A comment])").unwrap().into_iter().next().unwrap();
/// let sgf_node = gametree.into_go_node().unwrap();
/// ```
pub fn into_go_node(self) -> Result<SgfNode<go::Prop>, SgfParseError> {
match self {
Self::GoGame(sgf_node) => Ok(sgf_node),
_ => Err(SgfParseError::UnexpectedGameType),
}
}
/// Returns the [`GameType`] for this [`GameTree`].
///
/// # Examples
/// ```
/// use sgf_parse::{parse, GameType};
///
/// let gametree = parse("(;GM[1]B[de]C[A comment])").unwrap().into_iter().next().unwrap();
/// assert_eq!(gametree.gametype(), GameType::Go);
/// ```
pub fn gametype(&self) -> GameType {
match self {
Self::GoGame(_) => GameType::Go,
Self::Unknown(_) => GameType::Unknown,
}
}
}
impl std::fmt::Display for GameTree {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let node_text = match self {
Self::GoGame(sgf_node) => sgf_node.serialize(),
Self::Unknown(sgf_node) => sgf_node.serialize(),
};
std::fmt::Display::fmt(&node_text, f)
}
}
impl std::convert::From<SgfNode<go::Prop>> for GameTree {
fn from(sgf_node: SgfNode<go::Prop>) -> Self {
Self::GoGame(sgf_node)
}
}
impl std::convert::From<SgfNode<unknown_game::Prop>> for GameTree {
fn from(sgf_node: SgfNode<unknown_game::Prop>) -> Self {
Self::Unknown(sgf_node)
}
}