use rand::{distributions::WeightedIndex, Rng};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, derive_more::Display)]
pub enum Color {
Divine,
Revelation,
Grace,
Growth,
Crusade,
Suffering,
Mundane,
}
impl Color {
pub const fn all() -> [Color; 7] {
use Color::*;
[
Mundane, Divine, Revelation, Grace, Growth, Crusade, Suffering,
]
}
pub const fn all_factions() -> [Color; 6] {
use Color::*;
[Divine, Revelation, Grace, Growth, Crusade, Suffering]
}
pub fn opposes(self) -> Self {
match self {
Self::Mundane => Self::Mundane,
faction => {
pub(crate) const ALL_FACTIONS: &[Color] = &Color::all_factions();
let faction_pos = ALL_FACTIONS.iter().position(|f| *f == faction).unwrap();
let opposing_index = (faction_pos + 3) % ALL_FACTIONS.len();
ALL_FACTIONS[opposing_index]
}
}
}
pub fn adjacent_to(self) -> [Self; 2] {
match self {
Self::Mundane => [Self::Mundane, Self::Mundane],
faction => {
pub(crate) const ALL_FACTIONS: &[Color] = &Color::all_factions();
let faction_pos = ALL_FACTIONS.iter().position(|f| *f == faction).unwrap();
let left_adjacent = (faction_pos + ALL_FACTIONS.len() - 1) % ALL_FACTIONS.len();
let right_adjacent = (faction_pos + 1) % ALL_FACTIONS.len();
[ALL_FACTIONS[left_adjacent], ALL_FACTIONS[right_adjacent]]
}
}
}
pub fn color(self) -> &'static str {
match self {
Color::Divine => "gold",
Color::Revelation => "blue",
Color::Grace => "white",
Color::Growth => "green",
Color::Crusade => "red",
Color::Suffering => "black",
Color::Mundane => "grey",
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ColorBalance {
pub mundane: usize,
pub divine: usize,
pub revelation: usize,
pub grace: usize,
pub growth: usize,
pub crusade: usize,
pub suffering: usize,
}
impl ColorBalance {
pub fn get(&self, color: Color) -> usize {
match color {
Color::Divine => self.divine,
Color::Revelation => self.revelation,
Color::Grace => self.grace,
Color::Growth => self.growth,
Color::Crusade => self.crusade,
Color::Suffering => self.suffering,
Color::Mundane => self.mundane,
}
}
pub fn gen_mana<'a, R: Rng + ?Sized>(
&self,
rng: &'a mut R,
) -> impl Iterator<Item = Color> + 'a {
let colors = Color::all();
let weights = [
self.mundane.saturating_add(1),
self.divine.saturating_add(1),
self.revelation.saturating_add(1),
self.grace.saturating_add(1),
self.growth.saturating_add(1),
self.crusade.saturating_add(1),
self.suffering.saturating_add(1),
];
let dist = WeightedIndex::new(weights).unwrap();
rng.sample_iter(dist).map(move |idx| colors[idx])
}
}
#[cfg(test)]
mod tests {
use super::Color;
#[test]
fn test_color_oppose_and_adjacent() {
let color = Color::Divine;
assert_eq!(Color::Growth, color.opposes());
assert_eq!([Color::Suffering, Color::Revelation], color.adjacent_to());
}
}