Initial commit

This commit is contained in:
2023-01-26 17:21:14 +01:00
commit fe671b8682
17 changed files with 1011 additions and 0 deletions

176
board-shared/src/tile.rs Normal file
View File

@@ -0,0 +1,176 @@
use std::fmt;
/// A single digit that can be wrapped in parentheses.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Digit {
pub value: u8,
pub has_left_parenthesis: bool,
pub has_right_parenthesis: bool,
}
impl Digit {
pub fn new(value: u8) -> Self {
Self {
value,
has_left_parenthesis: false,
has_right_parenthesis: false,
}
}
}
impl fmt::Display for Digit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.has_left_parenthesis {
write!(f, "(")?;
}
write!(f, "{}", self.value)?;
if self.has_right_parenthesis {
write!(f, ")")?;
}
Ok(())
}
}
impl TryFrom<&str> for Digit {
type Error = ();
fn try_from(value: &str) -> Result<Self, Self::Error> {
let mut res = Digit {
value: 0,
has_left_parenthesis: false,
has_right_parenthesis: false,
};
let mut it = value.chars();
let c = it.next().ok_or(())?;
if c == '(' {
res.has_left_parenthesis = true;
res.value = it.next().ok_or(())?.to_digit(10).ok_or(())? as u8;
} else {
res.value = c.to_digit(10).ok_or(())? as u8;
}
if let Some(c) = it.next() {
if c != ')' {
return Err(());
}
res.has_right_parenthesis = true;
}
Ok(res)
}
}
/// An operator that can be applied between two terms.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Operator {
Add,
Subtract,
Multiply,
Divide,
}
impl fmt::Display for Operator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Operator::Add => write!(f, "+"),
Operator::Subtract => write!(f, "-"),
Operator::Multiply => write!(f, "*"),
Operator::Divide => write!(f, "/"),
}
}
}
impl TryFrom<char> for Operator {
type Error = ();
fn try_from(value: char) -> Result<Self, Self::Error> {
match value {
'+' => Ok(Operator::Add),
'-' => Ok(Operator::Subtract),
'*' => Ok(Operator::Multiply),
'/' => Ok(Operator::Divide),
_ => Err(()),
}
}
}
/// A single piece of a mathematical expression.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Tile {
Digit(Digit),
Operator(Operator),
Equals,
}
impl TryFrom<&str> for Tile {
type Error = ();
fn try_from(value: &str) -> Result<Self, Self::Error> {
if let Ok(digit) = Digit::try_from(value) {
return Ok(Tile::Digit(digit));
}
match value {
"=" => Ok(Tile::Equals),
_ => Ok(Tile::Operator(value.chars().next().ok_or(())?.try_into()?)),
}
}
}
impl fmt::Display for Tile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Tile::Digit(digit) => write!(f, "{digit}"),
Tile::Operator(operator) => write!(f, "{operator}"),
Tile::Equals => write!(f, "="),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn digit_from_str() {
assert_eq!(Digit::try_from("1"), Ok(Digit::new(1)));
assert_eq!(
Digit::try_from("(5"),
Ok(Digit {
value: 5,
has_left_parenthesis: true,
has_right_parenthesis: false,
})
);
assert_eq!(
Digit::try_from("8)"),
Ok(Digit {
value: 8,
has_left_parenthesis: false,
has_right_parenthesis: true,
})
);
assert_eq!(Digit::try_from("+"), Err(()));
assert_eq!(Digit::try_from("1("), Err(()));
assert_eq!(Digit::try_from(""), Err(()));
}
#[test]
fn operator_from_str() {
assert_eq!(Operator::try_from('+'), Ok(Operator::Add));
assert_eq!(Operator::try_from('-'), Ok(Operator::Subtract));
assert_eq!(Operator::try_from('²'), Err(()));
}
#[test]
fn piece_from_str() {
assert_eq!(Tile::try_from("+"), Ok(Tile::Operator(Operator::Add)));
assert_eq!(
Tile::try_from("(7)"),
Ok(Tile::Digit(Digit {
value: 7,
has_left_parenthesis: true,
has_right_parenthesis: true,
}))
);
assert_eq!(Tile::try_from("="), Ok(Tile::Equals));
assert_eq!(Tile::try_from(""), Err(()));
}
}