
Implements the Silver Standard conversion on a given list of currency values, defaulting to gold coins. The list of coins are each converted to a base copper coin value, then added together, and finally converted to the given Silver Standard value.
120 lines
3.3 KiB
Rust
120 lines
3.3 KiB
Rust
#[macro_use]
|
|
extern crate clap;
|
|
#[macro_use]
|
|
extern crate lazy_static;
|
|
extern crate regex;
|
|
|
|
use std::fmt;
|
|
use std::ops::Add;
|
|
use std::process;
|
|
|
|
use regex::Regex;
|
|
|
|
fn main() {
|
|
lazy_static! {
|
|
static ref RE: Regex = Regex::new(r"(\d+)([cegps])?").unwrap();
|
|
}
|
|
|
|
let app = clap_app!(sterling =>
|
|
(version: "0.1.0")
|
|
(about: "Converts a given D&D 5e currency value to the Silver Standard.")
|
|
(@arg VALUE: ... "The value to be converted; should be suffixed with the coin's short-hand abbreviation, i.e. p, g, e, s, or c. Defaults coin type to 'g'.")
|
|
);
|
|
|
|
if let Some(values) = app.get_matches().values_of("VALUE") {
|
|
let coins: Vec<&str> = values.collect();
|
|
|
|
let total_copper_value: usize = coins
|
|
.iter()
|
|
.map(|coin| {
|
|
if let Some(captures) = RE.captures(coin) {
|
|
let amount: usize = captures.get(1).unwrap().as_str().parse().unwrap();
|
|
let denomination = captures.get(2).map_or("g", |d| d.as_str());
|
|
|
|
convert_to_copper(amount, denomination)
|
|
} else {
|
|
panic!("Error: Invalid coin value \"{}\"", coin);
|
|
}
|
|
})
|
|
.fold(0 as usize, |total, value| total + value);
|
|
|
|
println!("{}", exchange_copper(total_copper_value));
|
|
} else {
|
|
println!("Please enter at least one value; should be suffixed with the coin's short-hand abbreviation, i.e. p, g, e, s, or c. Defaults coin type to 'g'.");
|
|
process::exit(1);
|
|
}
|
|
}
|
|
|
|
fn convert_to_copper(amount: usize, coin_denomination: &str) -> usize {
|
|
match coin_denomination {
|
|
"p" => amount * 1000,
|
|
"g" => amount * 100,
|
|
"e" => amount * 50,
|
|
"s" => amount * 10,
|
|
"c" => amount,
|
|
_ => unreachable!("Invalid coin type; must be a valid coin found in the PHB."),
|
|
}
|
|
}
|
|
|
|
fn exchange_copper(copper: usize) -> CurrencyValue {
|
|
CurrencyValue {
|
|
platinum: copper / 1000000,
|
|
gold: (copper % 1000000) / 10000,
|
|
silver: ((copper % 1000000) % 10000) / 100,
|
|
copper: ((copper % 1000000) % 10000) % 100,
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct CurrencyValue {
|
|
platinum: usize,
|
|
gold: usize,
|
|
silver: usize,
|
|
copper: usize,
|
|
}
|
|
|
|
impl fmt::Display for CurrencyValue {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let &CurrencyValue {
|
|
platinum,
|
|
gold,
|
|
silver,
|
|
copper,
|
|
} = self;
|
|
|
|
let mut output = String::new();
|
|
|
|
if platinum > 0 {
|
|
output = output + &format!("{}p ", platinum);
|
|
}
|
|
|
|
if gold > 0 {
|
|
output = output + &format!("{}g ", gold);
|
|
}
|
|
|
|
if silver > 0 {
|
|
output = output + &format!("{}s ", silver);
|
|
}
|
|
|
|
if copper > 0 {
|
|
output = output + &format!("{}c", copper);
|
|
} else if output.is_empty() {
|
|
output.push_str("0cp");
|
|
}
|
|
|
|
write!(f, "{}", output)
|
|
}
|
|
}
|
|
|
|
impl Add for CurrencyValue {
|
|
type Output = CurrencyValue;
|
|
|
|
fn add(self, other: CurrencyValue) -> CurrencyValue {
|
|
CurrencyValue {
|
|
platinum: self.platinum + other.platinum,
|
|
gold: self.gold + other.gold,
|
|
silver: self.silver + other.silver,
|
|
copper: self.copper + other.copper,
|
|
}
|
|
}
|
|
}
|