sterling/src/main.rs
Zachary Dziura cc1e49c794 Release v0.1.0
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.
2018-03-09 23:05:39 -05:00

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,
}
}
}