diff --git a/src/parser.rs b/src/parser.rs index 6dbee0c..2c0cb88 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -14,7 +14,7 @@ // along with this program. If not, see . use crate::error::Error; -use crate::types::{Action, Color, ColorDigit, Digit, GameAction, ReplAction, Slot, Slots}; +use crate::types::{Action, Card, Color, ColorDigit, Digit, GameAction, ReplAction, Slot, Slots}; use nom::{ branch::alt, bytes::complete::tag, @@ -23,6 +23,7 @@ use nom::{ multi::many0, IResult, }; +use std::convert::TryFrom; use std::str::FromStr; fn parse_color(i: &str) -> IResult<&str, ColorDigit> { @@ -61,9 +62,24 @@ fn parse_digit(i: &str) -> IResult<&str, ColorDigit> { Ok((i, digit.into())) } +fn parse_card(i: &str) -> IResult<&str, Card> { + let (i, color) = parse_color(i)?; + let (i, _) = space0(i)?; + let (i, digit) = parse_digit(i)?; + Ok(( + i, + Card { + digit: Digit::try_from(digit).unwrap(), + color: Color::try_from(color).unwrap(), + }, + )) +} + fn parse_play(i: &str) -> IResult<&str, GameAction> { let (i, _) = alt((tag("play"), tag("p")))(i)?; let (i, _) = space1(i)?; + let (i, card) = parse_card(i)?; + let (i, _) = space1(i)?; let (i, slot) = digit1(i)?; let slot = slot @@ -74,7 +90,7 @@ fn parse_play(i: &str) -> IResult<&str, GameAction> { return Err(nom::Err::Error(NomError::new("", ErrorKind::IsA))); } - Ok((i, GameAction::PlayCard(slot))) + Ok((i, GameAction::PlayCard(card, slot))) } fn parse_slot(i: &str) -> IResult<&str, Slot> { @@ -110,9 +126,11 @@ fn parse_slots1(i: &str) -> IResult<&str, Slots> { fn parse_drop(i: &str) -> IResult<&str, GameAction> { let (i, _) = alt((tag("drop"), tag("d")))(i)?; let (i, _) = space1(i)?; + let (i, card) = parse_card(i)?; + let (i, _) = space1(i)?; let (i, slot) = parse_slot(i)?; - Ok((i, GameAction::DropCard(slot))) + Ok((i, GameAction::DropCard(card, slot))) } fn parse_hint(i: &str) -> IResult<&str, GameAction> { diff --git a/src/types.rs b/src/types.rs index a1fd27c..9199812 100644 --- a/src/types.rs +++ b/src/types.rs @@ -13,6 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +use std::convert::TryFrom; use std::fmt; use std::ops::Deref; use std::str::FromStr; @@ -150,11 +151,51 @@ impl From for ColorDigit { } } +impl TryFrom for Digit { + type Error = Error; + + fn try_from(cd: ColorDigit) -> Result { + Ok(match cd { + ColorDigit::Digit(d) => d, + ColorDigit::Color(c) => return Err(Error::ParseDigitError(c.to_string())), + }) + } +} + +impl TryFrom for Color { + type Error = Error; + + fn try_from(cd: ColorDigit) -> Result { + Ok(match cd { + ColorDigit::Color(c) => c, + ColorDigit::Digit(d) => return Err(Error::ParseColorError(d.to_string())), + }) + } +} + /// A card #[derive(Clone, Debug, PartialEq)] pub struct Card { pub digit: Digit, - pub color: Option, + pub color: Color, +} + +impl fmt::Display for Card { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}{}", + match self.color { + Color::Blue => "b", + Color::Green => "g", + Color::Purple => "p", + Color::Red => "r", + Color::White => "w", + Color::Yellow => "y", + }, + self.digit + ) + } } /// Position in a player's hand @@ -197,8 +238,8 @@ impl fmt::Display for Slots { /// Possible actions during the game #[derive(Clone, Debug, PartialEq)] pub enum GameAction { - PlayCard(Slot), - DropCard(Slot), + PlayCard(Card, Slot), + DropCard(Card, Slot), ColorHint(Slots, Color), DigitHint(Slots, Digit), } @@ -215,8 +256,8 @@ impl From<(ColorDigit, Slots)> for GameAction { impl fmt::Display for GameAction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - GameAction::PlayCard(c) => write!(f, "play {}", c), - GameAction::DropCard(c) => write!(f, "drop {}", c), + GameAction::PlayCard(card, slot) => write!(f, "play {} {}", card, slot), + GameAction::DropCard(card, slot) => write!(f, "drop {} {}", card, slot), GameAction::ColorHint(slots, c) => write!(f, "hint {} {}", c, slots), GameAction::DigitHint(slots, d) => write!(f, "hint {} {}", d, slots), }