diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/calculator.rs | 40 | ||||
| -rw-r--r-- | src/oneroll/grammar.pest | 10 | ||||
| -rw-r--r-- | src/parser.rs | 19 | ||||
| -rw-r--r-- | src/types.rs | 5 |
4 files changed, 71 insertions, 3 deletions
diff --git a/src/calculator.rs b/src/calculator.rs index 7289921..5376f76 100644 --- a/src/calculator.rs +++ b/src/calculator.rs @@ -35,6 +35,12 @@ impl DiceCalculator { final_rolls.push(roll as i32); } } + DiceModifier::ExplodeAlias => { + while roll == dice.sides as u32 { + roll = rand::random::<u32>() % dice.sides as u32 + 1; + final_rolls.push(roll as i32); + } + } _ => {} } } @@ -61,9 +67,19 @@ impl DiceCalculator { rolls.push(final_rolls); } - // handle high/low, discard high/low and unique deduplication + // handle keep alias before global aggregation let mut final_rolls = rolls; for modifier in &dice.modifiers { + if let DiceModifier::KeepAlias(n) = modifier { + let all_values: Vec<i32> = final_rolls.iter().flatten().cloned().collect(); + let mut sorted = all_values; + sorted.sort_by(|a, b| b.cmp(a)); + final_rolls = sorted.iter().take(*n as usize).map(|&v| vec![v]).collect(); + } + } + + // handle high/low, discard high/low and unique/sort/count + for modifier in &dice.modifiers { match modifier { DiceModifier::KeepHigh(n) => { let all_values: Vec<i32> = final_rolls.iter().flatten().cloned().collect(); @@ -89,6 +105,13 @@ impl DiceCalculator { sorted.sort(); final_rolls = sorted.iter().skip(*n as usize).map(|&v| vec![v]).collect(); } + DiceModifier::ExplodeKeepHigh(n) => { + // equivalent to explode then keep high n + let all_values: Vec<i32> = final_rolls.iter().flatten().cloned().collect(); + let mut sorted = all_values; + sorted.sort_by(|a, b| b.cmp(a)); + final_rolls = sorted.iter().take(*n as usize).map(|&v| vec![v]).collect(); + } DiceModifier::Unique => { use std::collections::HashSet; let mut seen = HashSet::new(); @@ -100,6 +123,16 @@ impl DiceCalculator { } final_rolls = uniques.into_iter().map(|v| vec![v]).collect(); } + DiceModifier::Sort => { + let mut values: Vec<i32> = final_rolls.iter().flatten().cloned().collect(); + values.sort(); + final_rolls = values.into_iter().map(|v| vec![v]).collect(); + } + DiceModifier::Count(target) => { + let values: Vec<i32> = final_rolls.iter().flatten().cloned().collect(); + let count = values.iter().filter(|&&v| v == *target).count() as i32; + final_rolls = vec![vec![count]]; + } _ => {} } } @@ -209,13 +242,18 @@ impl DiceCalculator { for modifier in modifiers { match modifier { DiceModifier::Explode => result.push('!'), + DiceModifier::ExplodeAlias => result.push('e'), + DiceModifier::ExplodeKeepHigh(n) => result.push_str(&format!("K{}", n)), DiceModifier::Reroll(n) => result.push_str(&format!("r{}", n)), DiceModifier::RerollOnce(n) => result.push_str(&format!("ro{}", n)), + DiceModifier::KeepAlias(n) => result.push_str(&format!("k{}", n)), DiceModifier::KeepHigh(n) => result.push_str(&format!("kh{}", n)), DiceModifier::KeepLow(n) => result.push_str(&format!("kl{}", n)), DiceModifier::DropHigh(n) => result.push_str(&format!("dh{}", n)), DiceModifier::DropLow(n) => result.push_str(&format!("dl{}", n)), DiceModifier::Unique => result.push('u'), + DiceModifier::Sort => result.push('s'), + DiceModifier::Count(v) => result.push_str(&format!("c{}", v)), } } result diff --git a/src/oneroll/grammar.pest b/src/oneroll/grammar.pest index 27d1c5e..09b86f8 100644 --- a/src/oneroll/grammar.pest +++ b/src/oneroll/grammar.pest @@ -22,23 +22,33 @@ dice_sides = @{ number } modifiers = { modifier+ } modifier = { explode + | explode_alias + | explode_keep_high | reroll | reroll_once + | keep_alias | keep_high | keep_low | drop_high | drop_low | unique + | sort + | count } explode = { "!" } +explode_alias = { "e" } +explode_keep_high = { "K" ~ number } reroll = { "r" ~ number } reroll_once = { "ro" ~ number } +keep_alias = { "k" ~ number } keep_high = { "kh" ~ number } keep_low = { "kl" ~ number } drop_high = { "dh" ~ number } drop_low = { "dl" ~ number } unique = { "u" } +sort = { "s" } +count = { "c" ~ number } op = { "+" | "-" | "*" | "/" | "^" } diff --git a/src/parser.rs b/src/parser.rs index a1800a2..50231c0 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -110,6 +110,12 @@ impl DiceParser { let inner = pair.into_inner().next().unwrap(); match inner.as_rule() { Rule::explode => Ok(DiceModifier::Explode), + Rule::explode_alias => Ok(DiceModifier::ExplodeAlias), + Rule::explode_keep_high => { + let num = inner.into_inner().next().unwrap().as_str().parse::<i32>() + .map_err(|_| DiceError::ParseError("无效的ExplodeKeepHigh数值".to_string()))?; + Ok(DiceModifier::ExplodeKeepHigh(num)) + } Rule::reroll => { let num = inner.into_inner().next().unwrap().as_str().parse::<i32>() .map_err(|_| DiceError::ParseError("无效的重投数值".to_string()))?; @@ -120,6 +126,11 @@ impl DiceParser { .map_err(|_| DiceError::ParseError("无效的条件重投数值".to_string()))?; Ok(DiceModifier::RerollOnce(num)) } + Rule::keep_alias => { + let num = inner.into_inner().next().unwrap().as_str().parse::<i32>() + .map_err(|_| DiceError::ParseError("无效的取高数值".to_string()))?; + Ok(DiceModifier::KeepAlias(num)) + } Rule::keep_high => { let num = inner.into_inner().next().unwrap().as_str().parse::<i32>() .map_err(|_| DiceError::ParseError("无效的取高数值".to_string()))?; @@ -140,8 +151,12 @@ impl DiceParser { .map_err(|_| DiceError::ParseError("无效的丢弃低数值".to_string()))?; Ok(DiceModifier::DropLow(num)) } - Rule::unique => { - Ok(DiceModifier::Unique) + Rule::unique => Ok(DiceModifier::Unique), + Rule::sort => Ok(DiceModifier::Sort), + Rule::count => { + let num = inner.into_inner().next().unwrap().as_str().parse::<i32>() + .map_err(|_| DiceError::ParseError("无效的计数数值".to_string()))?; + Ok(DiceModifier::Count(num)) } _ => Err(DiceError::ParseError("未知的修饰符".to_string())), } diff --git a/src/types.rs b/src/types.rs index 6f4c54c..aad0080 100644 --- a/src/types.rs +++ b/src/types.rs @@ -20,13 +20,18 @@ pub struct DiceRoll { #[derive(Debug, Clone, PartialEq)] pub enum DiceModifier { Explode, // ! + ExplodeAlias, // e (alias of !) + ExplodeKeepHigh(i32), // KX == explode then keep high X Reroll(i32), // rX RerollOnce(i32), // roX + KeepAlias(i32), // kX == khX KeepHigh(i32), // khX KeepLow(i32), // klX DropHigh(i32), // dhX DropLow(i32), // dlX Unique, // u + Sort, // s (sort results) + Count(i32), // cV (count value V) } |
