use clap::Parser;
#[derive(Parser, Debug)]
#[command(version, about, long_about = Some("DnD Dice Roller on the command line!"))]
pub struct Args {
#[arg(short, long, value_parser = clap::value_parser!(u32).range(1..), default_value_t = 20)]
pub die: u32,
#[arg(short, long, value_parser = clap::value_parser!(u32).range(1..),default_value_t = 1)]
pub number: u32,
#[arg(short, long, default_value_t = 0)]
pub modifier: u32,
#[arg(short, long)]
pub raw: Option<String>,
}
fn calculate(die: u32, number: u32, modifier: u32) -> usize {
let mut value = (0..number)
.map(|_| rand::random_range(1..=die as usize))
.sum::<usize>();
value += modifier as usize;
value
}
fn parse_raw(raw: &str) -> Result<(u32, u32, u32), ()> {
let Some((number, rest)) = raw.split_once("d") else {
eprintln!("Raw values expected to be in the format: '[number]d[die] + [modifier]'!");
return Err(());
};
let Ok(number) = number.parse::<u32>() else {
eprintln!("{number} is not a valid number!");
return Err(());
};
let (die, modifier) = match rest.split_once("+") {
Some((die, modifier)) => {
let Ok(die) = die.trim().parse::<u32>() else {
eprintln!("{die} is not a valid number!");
return Err(());
};
let Ok(modifier) = modifier.trim().parse::<u32>() else {
eprintln!("{modifier} is not a valid number!");
return Err(());
};
(die, modifier)
}
None => {
let Ok(die) = rest.parse::<u32>() else {
eprintln!("{rest} is not a valid number!");
return Err(());
};
(die, 0)
}
};
Ok((number, die, modifier))
}
fn display(die: u32, number: u32, modifier: u32, value: usize) {
if modifier > 0 {
println!(
"You rolled {}d{} + {} for a total of {value}!",
number, die, modifier
);
} else {
println!("You rolled {}d{} for a total of {value}!", number, die);
}
}
fn main() {
let args = Args::parse();
match args.raw {
Some(r) => {
let Ok((number, die, modifier)) = parse_raw(&r) else {
return;
};
let value = calculate(die, number, modifier);
display(die, number, modifier, value);
}
None => {
let value = calculate(args.die, args.number, args.modifier);
display(args.die, args.number, args.modifier, value);
}
}
}