use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
pub enum Voucher {
Grabber,
NachoTong,
Wasteful,
Recyclomancy,
PaintBrush,
Palette,
Overstock,
OverstockPlus,
CrystalBall,
Antimatter,
RerollSurplus,
RerollGlut,
ClearanceSale,
Liquidation,
SeedMoney,
MoneyTree,
TarotMerchant,
TarotTycoon,
PlanetMerchant,
PlanetTycoon,
}
impl Voucher {
pub const ALL: [Self; 20] = [
Self::Grabber,
Self::NachoTong,
Self::Wasteful,
Self::Recyclomancy,
Self::PaintBrush,
Self::Palette,
Self::Overstock,
Self::OverstockPlus,
Self::CrystalBall,
Self::Antimatter,
Self::RerollSurplus,
Self::RerollGlut,
Self::ClearanceSale,
Self::Liquidation,
Self::SeedMoney,
Self::MoneyTree,
Self::TarotMerchant,
Self::TarotTycoon,
Self::PlanetMerchant,
Self::PlanetTycoon,
];
#[must_use]
pub fn requires(self) -> Option<Self> {
match self {
Self::NachoTong => Some(Self::Grabber),
Self::Recyclomancy => Some(Self::Wasteful),
Self::Palette => Some(Self::PaintBrush),
Self::OverstockPlus => Some(Self::Overstock),
Self::RerollGlut => Some(Self::RerollSurplus),
Self::Liquidation => Some(Self::ClearanceSale),
Self::MoneyTree => Some(Self::SeedMoney),
Self::TarotTycoon => Some(Self::TarotMerchant),
Self::PlanetTycoon => Some(Self::PlanetMerchant),
_ => None,
}
}
}
impl Display for Voucher {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let name = match self {
Self::Grabber => "Grabber",
Self::NachoTong => "Nacho Tong",
Self::Wasteful => "Wasteful",
Self::Recyclomancy => "Recyclomancy",
Self::PaintBrush => "Paint Brush",
Self::Palette => "Palette",
Self::Overstock => "Overstock",
Self::OverstockPlus => "Overstock Plus",
Self::CrystalBall => "Crystal Ball",
Self::Antimatter => "Antimatter",
Self::RerollSurplus => "Reroll Surplus",
Self::RerollGlut => "Reroll Glut",
Self::ClearanceSale => "Clearance Sale",
Self::Liquidation => "Liquidation",
Self::SeedMoney => "Seed Money",
Self::MoneyTree => "Money Tree",
Self::TarotMerchant => "Tarot Merchant",
Self::TarotTycoon => "Tarot Tycoon",
Self::PlanetMerchant => "Planet Merchant",
Self::PlanetTycoon => "Planet Tycoon",
};
write!(f, "{name}")
}
}
#[cfg(test)]
#[allow(non_snake_case)]
mod funky__types__voucher_tests {
use super::*;
#[test]
fn all__lists_every_variant_once() {
let mut seen = Voucher::ALL.to_vec();
seen.sort_unstable();
seen.dedup();
assert_eq!(seen.len(), Voucher::ALL.len(), "no duplicates in ALL");
assert_eq!(Voucher::ALL.len(), 20);
}
#[test]
fn requires__pairs_each_upgrade_with_its_base() {
assert_eq!(Voucher::NachoTong.requires(), Some(Voucher::Grabber));
assert_eq!(Voucher::MoneyTree.requires(), Some(Voucher::SeedMoney));
assert_eq!(
Voucher::PlanetTycoon.requires(),
Some(Voucher::PlanetMerchant)
);
assert_eq!(Voucher::Grabber.requires(), None);
assert_eq!(Voucher::CrystalBall.requires(), None);
assert_eq!(Voucher::Antimatter.requires(), None);
}
#[test]
fn requires__every_required_base_is_itself_a_base() {
for voucher in Voucher::ALL {
if let Some(base) = voucher.requires() {
assert_eq!(base.requires(), None, "{voucher}'s base {base} is a base");
}
}
}
#[test]
fn display__reads_as_the_wiki_name() {
assert_eq!(Voucher::NachoTong.to_string(), "Nacho Tong");
assert_eq!(Voucher::OverstockPlus.to_string(), "Overstock Plus");
assert_eq!(Voucher::CrystalBall.to_string(), "Crystal Ball");
}
}