forked from projectmoon/tenebrous-dicebot
get roller working correctly
This commit is contained in:
parent
a9e1ccbf2e
commit
087e20c261
|
@ -1,9 +1,13 @@
|
||||||
|
use axfive_matrix_dicebot::dice::parser::parse_element_expression;
|
||||||
|
use axfive_matrix_dicebot::roll::{Roll, Rolled};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), String> {
|
||||||
let _roll_string = std::env::args().skip(1).collect::<Vec<String>>().join(" ");
|
let roll_string = std::env::args().skip(1).collect::<Vec<String>>().join(" ");
|
||||||
// first regex needs to be different because the sign is mandatory for the rest
|
let (_tail, expression) = match parse_element_expression(&roll_string) {
|
||||||
//let expression = parse_expression(&roll_string);
|
Ok(response) => response,
|
||||||
//println!("{:?}", expression);
|
Err(e) => return Err(e.to_string()),
|
||||||
|
};
|
||||||
|
println!("{}", expression.roll());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use nom::{
|
||||||
tag, IResult,
|
tag, IResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::dice::{Dice, Element, SignedElement, ElementExpression};
|
use crate::dice::{Dice, Element, ElementExpression, SignedElement};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
enum Sign {
|
enum Sign {
|
||||||
|
@ -78,7 +78,7 @@ fn parse_signed_element(input: &str) -> IResult<&str, SignedElement> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a full element expression. Eats whitespace.
|
// Parse a full element expression. Eats whitespace.
|
||||||
fn parse_element_expression(input: &str) -> IResult<&str, ElementExpression> {
|
pub fn parse_element_expression(input: &str) -> IResult<&str, ElementExpression> {
|
||||||
named!(first_element(&str) -> SignedElement, alt!(
|
named!(first_element(&str) -> SignedElement, alt!(
|
||||||
parse_signed_element => { |e| e } |
|
parse_signed_element => { |e| e } |
|
||||||
parse_element => { |e| SignedElement::Positive(e) }
|
parse_element => { |e| SignedElement::Positive(e) }
|
||||||
|
@ -180,4 +180,3 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
231
src/roll.rs
231
src/roll.rs
|
@ -1,5 +1,8 @@
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use crate::dice;
|
use crate::dice;
|
||||||
|
use std::fmt;
|
||||||
|
use std::string::ToString;
|
||||||
|
|
||||||
pub trait Roll {
|
pub trait Roll {
|
||||||
type Output;
|
type Output;
|
||||||
|
@ -7,33 +10,237 @@ pub trait Roll {
|
||||||
fn roll(&self) -> Self::Output;
|
fn roll(&self) -> Self::Output;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Roll for dice::Dice {
|
pub trait Rolled {
|
||||||
type Output = u32;
|
fn rolled_value(&self) -> i32;
|
||||||
|
}
|
||||||
|
|
||||||
fn roll(&self) -> u32 {
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub struct DiceRoll(Vec<u32>);
|
||||||
|
|
||||||
|
impl DiceRoll {
|
||||||
|
pub fn rolls(&self) -> &[u32] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn total(&self) -> u32 {
|
||||||
|
self.0.iter().sum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rolled for DiceRoll {
|
||||||
|
fn rolled_value(&self) -> i32 {
|
||||||
|
self.total() as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for DiceRoll {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.rolled_value())?;
|
||||||
|
let rolls = self.rolls();
|
||||||
|
let mut iter = rolls.iter();
|
||||||
|
if let Some(first) = iter.next() {
|
||||||
|
write!(f, " ({}", first)?;
|
||||||
|
for roll in iter {
|
||||||
|
write!(f, " + {}", roll)?;
|
||||||
|
}
|
||||||
|
write!(f, ")")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Roll for dice::Dice {
|
||||||
|
type Output = DiceRoll;
|
||||||
|
|
||||||
|
fn roll(&self) -> DiceRoll {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
(0..self.count).map(|_| rng.gen_range(1, self.sides + 1)).sum()
|
let rolls = (0..self.count).map(|_| rng.gen_range(1, self.sides + 1)).collect();
|
||||||
|
DiceRoll(rolls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub enum ElementRoll {
|
||||||
|
Dice(DiceRoll),
|
||||||
|
Bonus(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rolled for ElementRoll {
|
||||||
|
fn rolled_value(&self) -> i32 {
|
||||||
|
match self {
|
||||||
|
ElementRoll::Dice(d) => d.rolled_value(),
|
||||||
|
ElementRoll::Bonus(b) => *b as i32,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Roll for dice::Element {
|
impl Roll for dice::Element {
|
||||||
type Output = u32;
|
type Output = ElementRoll;
|
||||||
|
|
||||||
fn roll(&self) -> u32 {
|
fn roll(&self) -> ElementRoll {
|
||||||
match self {
|
match self {
|
||||||
dice::Element::Dice(d) => d.roll(),
|
dice::Element::Dice(d) => ElementRoll::Dice(d.roll()),
|
||||||
dice::Element::Bonus(b) => *b,
|
dice::Element::Bonus(b) => ElementRoll::Bonus(*b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ElementRoll {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ElementRoll::Dice(d) => write!(f, "{}", d),
|
||||||
|
ElementRoll::Bonus(b) => write!(f, "{}", b),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub enum SignedElementRoll {
|
||||||
|
Positive(ElementRoll),
|
||||||
|
Negative(ElementRoll),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rolled for SignedElementRoll {
|
||||||
|
fn rolled_value(&self) -> i32 {
|
||||||
|
match self {
|
||||||
|
SignedElementRoll::Positive(e) => e.rolled_value(),
|
||||||
|
SignedElementRoll::Negative(e) => -e.rolled_value(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Roll for dice::SignedElement {
|
impl Roll for dice::SignedElement {
|
||||||
type Output = i32;
|
type Output = SignedElementRoll;
|
||||||
|
|
||||||
fn roll(&self) -> i32 {
|
fn roll(&self) -> SignedElementRoll {
|
||||||
match self {
|
match self {
|
||||||
dice::SignedElement::Positive(e) => e.roll() as i32,
|
dice::SignedElement::Positive(e) => SignedElementRoll::Positive(e.roll()),
|
||||||
dice::SignedElement::Negative(e) => -(e.roll() as i32),
|
dice::SignedElement::Negative(e) => SignedElementRoll::Negative(e.roll()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SignedElementRoll {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
SignedElementRoll::Positive(e) => write!(f, "{}", e),
|
||||||
|
SignedElementRoll::Negative(e) => write!(f, "-{}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub struct ElementExpressionRoll(Vec<SignedElementRoll>);
|
||||||
|
|
||||||
|
impl Deref for ElementExpressionRoll {
|
||||||
|
type Target = Vec<SignedElementRoll>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for ElementExpressionRoll {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rolled for ElementExpressionRoll {
|
||||||
|
fn rolled_value(&self) -> i32 {
|
||||||
|
self.iter().map(Rolled::rolled_value).sum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Roll for dice::ElementExpression {
|
||||||
|
type Output = ElementExpressionRoll;
|
||||||
|
|
||||||
|
fn roll(&self) -> ElementExpressionRoll {
|
||||||
|
ElementExpressionRoll(self.iter().map(Roll::roll).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ElementExpressionRoll {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if self.len() > 1 {
|
||||||
|
write!(f, "{}", self.rolled_value())?;
|
||||||
|
let mut iter = self.0.iter();
|
||||||
|
if let Some(first) = iter.next() {
|
||||||
|
write!(f, " ({}", first)?;
|
||||||
|
for roll in iter {
|
||||||
|
match roll {
|
||||||
|
SignedElementRoll::Positive(e) => write!(f, " + {}", e)?,
|
||||||
|
SignedElementRoll::Negative(e) => write!(f, " - {}", e)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, ")")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else if self.len() > 0 {
|
||||||
|
// For a single item, just show the inner item to avoid redundancy
|
||||||
|
let first = self.0.iter().next().unwrap();
|
||||||
|
write!(f, "{}", first)
|
||||||
|
} else {
|
||||||
|
write!(f, "0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn dice_roll_display_test() {
|
||||||
|
assert_eq!(DiceRoll(vec![1, 3, 4]).to_string(), "8 (1 + 3 + 4)");
|
||||||
|
assert_eq!(DiceRoll(vec![]).to_string(), "0");
|
||||||
|
assert_eq!(DiceRoll(vec![4, 7, 2, 10]).to_string(), "23 (4 + 7 + 2 + 10)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn element_roll_display_test() {
|
||||||
|
assert_eq!(ElementRoll::Dice(DiceRoll(vec![1, 3, 4])).to_string(), "8 (1 + 3 + 4)");
|
||||||
|
assert_eq!(ElementRoll::Bonus(7).to_string(), "7");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn signed_element_roll_display_test() {
|
||||||
|
assert_eq!(SignedElementRoll::Positive(ElementRoll::Dice(DiceRoll(vec![1, 3, 4]))).to_string(), "8 (1 + 3 + 4)");
|
||||||
|
assert_eq!(SignedElementRoll::Negative(ElementRoll::Dice(DiceRoll(vec![1, 3, 4]))).to_string(), "-8 (1 + 3 + 4)");
|
||||||
|
assert_eq!(SignedElementRoll::Positive(ElementRoll::Bonus(7)).to_string(), "7");
|
||||||
|
assert_eq!(SignedElementRoll::Negative(ElementRoll::Bonus(7)).to_string(), "-7");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn element_expression_roll_display_test() {
|
||||||
|
assert_eq!(
|
||||||
|
ElementExpressionRoll(vec![
|
||||||
|
SignedElementRoll::Positive(ElementRoll::Dice(DiceRoll(vec![1, 3, 4]))),
|
||||||
|
]).to_string(), "8 (1 + 3 + 4)");
|
||||||
|
assert_eq!(
|
||||||
|
ElementExpressionRoll(vec![
|
||||||
|
SignedElementRoll::Negative(ElementRoll::Dice(DiceRoll(vec![1, 3, 4]))),
|
||||||
|
]).to_string(), "-8 (1 + 3 + 4)");
|
||||||
|
assert_eq!(
|
||||||
|
ElementExpressionRoll(vec![
|
||||||
|
SignedElementRoll::Positive(ElementRoll::Bonus(7)),
|
||||||
|
]).to_string(), "7");
|
||||||
|
assert_eq!(
|
||||||
|
ElementExpressionRoll(vec![
|
||||||
|
SignedElementRoll::Negative(ElementRoll::Bonus(7)),
|
||||||
|
]).to_string(), "-7");
|
||||||
|
assert_eq!(
|
||||||
|
ElementExpressionRoll(vec![
|
||||||
|
SignedElementRoll::Positive(ElementRoll::Dice(DiceRoll(vec![1, 3, 4]))),
|
||||||
|
SignedElementRoll::Negative(ElementRoll::Dice(DiceRoll(vec![1, 2]))),
|
||||||
|
SignedElementRoll::Positive(ElementRoll::Bonus(4)),
|
||||||
|
SignedElementRoll::Negative(ElementRoll::Bonus(7)),
|
||||||
|
]).to_string(), "2 (8 (1 + 3 + 4) - 3 (1 + 2) + 4 - 7)");
|
||||||
|
assert_eq!(
|
||||||
|
ElementExpressionRoll(vec![
|
||||||
|
SignedElementRoll::Negative(ElementRoll::Dice(DiceRoll(vec![1, 3, 4]))),
|
||||||
|
SignedElementRoll::Positive(ElementRoll::Dice(DiceRoll(vec![1, 2]))),
|
||||||
|
SignedElementRoll::Negative(ElementRoll::Bonus(4)),
|
||||||
|
SignedElementRoll::Positive(ElementRoll::Bonus(7)),
|
||||||
|
]).to_string(), "-2 (-8 (1 + 3 + 4) + 3 (1 + 2) - 4 + 7)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue