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.
This commit is contained in:
Zachary Dziura 2018-03-09 23:05:39 -05:00
commit cc1e49c794
8 changed files with 261 additions and 0 deletions

16
.gitignore vendored Normal file
View file

@ -0,0 +1,16 @@
# Created by https://www.gitignore.io/api/rust
### Rust ###
# Generated by Cargo
# will have compiled files and executables
/target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# End of https://www.gitignore.io/api/rust

0
.gitlab-ci.yml Normal file
View file

13
Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "sterling"
version = "0.1.0"
description = "Converts a given D&D 5e currency value to the Silver Standard."
authors = ["Zachary Dziura <zcdziura@gmail.com>"]
[dependencies]
clap = "2.31.1"
lazy_static = "1.0.0"
regex = "0.2"
[profile.release]
lto = true

26
MIT.md Normal file
View file

@ -0,0 +1,26 @@
The MIT License (MIT)
=====================
Copyright © `<year>` `<copyright holders>`
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the “Software”), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

35
README.md Normal file
View file

@ -0,0 +1,35 @@
# Sterling
Converts a given D&D 5e currency value to the Silver Standard. Inspired by the Reddit posts titled
[The Silver Hack: Making Money Matter](https://www.reddit.com/r/DnDBehindTheScreen/comments/80f6kt/the_silver_hack_making_money_matter/),
and [I make Silver Standard for 5th Edition (Spreadsheets.)](https://www.reddit.com/r/dndnext/comments/5tt5g8/i_make_silver_standard_for_5_edition_spreadsheets/).
## Usage
```
sterling [VALUE]...
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
ARGS:
<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'.
```
## Abstract
Items and expenses are, by default, assigned arbitrary currency values within the official D&D 5th
edition source books. Many of the officially priced items use the "Gold Standard"; that is, items
are priced in gold coins by default. While there is nothing wrong with using official currency
values within your campaign, it leads to the perceived value of gold to be less in the eyes of your
players. Gold has been sought after as both a commodity and a currency for centuries, and your
campaign aught to treat gold similarly!
## Explanation
The basis of the Silver Standard treats 1 gold coin from the official D&D 5e source books as 1
silver coin, and that there are one hundred of a given coin to every one of the next highest valued
coin. That's all. Thus, one-hundred fifty copper coins equals one silver and fifty copper coins,
while a suit of heavy plate armor equals fifteen gold coins, rather than fifteen hundred.

27
UNLICENSE.md Normal file
View file

@ -0,0 +1,27 @@
Unlicense (Public Domain)
============================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to &lt;<http://unlicense.org/>&gt;

24
WAIVER.sigs Normal file
View file

@ -0,0 +1,24 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
I dedicate any and all copyright interest in this software to the
public domain. I make this dedication for the benefit of the public at
large and to the detriment of my heirs and successors. I intend this
dedication to be an overt act of relinquishment in perpetuity of all
present and future rights to this software under copyright law.
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEMqo2ba6LuiYDXB5kdkVeHsxAMfYFAlqjHbsACgkQdkVeHsxA
MfZy5hAAoSrAqT7Mm3d/r0rRuVTTotvZye6PgKdIx+XSdAYVeRjFrtOumldEDq84
peE9JjunmfUxqvYPmk8CC6gzdVkkHNh0MM4WHop/qoQGwSQD36G5TvnTEc2SjIYd
NVHbTCz8MpIJ8wzn2EH5x8S3BWIy7XB3NJhIuPBsJzSUSniP5d4J3tJw/2hiO34E
PaKGSfLk9fAErgXUk+PEn98dXuPHeyrFYsSRQZP5yiTlH7eVloe8VTFIjUF+P0qA
XrHWKaEVQYWPXMBTpF8pfPg4rFVnu7F7Pl145AAmQJJo45VLmfDBNWAGQHYMXoyZ
bsCd9hQ9zhZMSXi7CBwMQc6itTKVetv1vH0DB77RLfOs+flvqASV1v1mhgBuxWIy
E0XzMcR1LtSPu9bdNxc/ClDGbFe5NfZU+dbUqTmpPZBgvfF0I/N/hw5RuDusS+hF
m0uvyRL0xIKIgTcNKgfU6pMe4gzVyPCqJ13kJVHfh7RFQ0MV7eQ3eowf8JDnrYZY
8DHJpnLxXKLfPeLY73iQFifFSFPjvpD5ObbDcXMZYToaC39d1n6MtUkh0o5aF8L4
sA9OGScTevQN9U4bO6AcaUXkqrHuQ9mIk+oP2w1e44O/Fwo9UoBNK0Quc7yA86KJ
tnDsTCZNW9HnwuZvXOuLaUEtWP0DYWDmsQmuIhT5VPAhGp7nv0s=
=2YGI
-----END PGP SIGNATURE-----

120
src/main.rs Normal file
View file

@ -0,0 +1,120 @@
#[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,
}
}
}