use std::fmt::{self, Display, Formatter}; use rand::prelude::ThreadRng; use rand::Rng; pub const NUM_STATS: usize = 7; pub const STATS: [&str; NUM_STATS] = [ "charisma", "constitution", "dexterity", "health", "intelligence", "strength", "wisdom", ]; #[derive(Clone, Debug, PartialEq, Eq)] pub struct Stats { values: [u8; NUM_STATS], } impl Stats { pub const fn from_values(values: [u8; NUM_STATS]) -> Self { Self { values } } fn roll_initial_value(rng: &mut ThreadRng) -> u8 { let mut v = 0; for _ in 0..3 { v += rng.gen_range(1..=6); } v } #[tarpaulin::skip] pub fn roll_initial() -> Self { let mut rng = rand::thread_rng(); let mut values = [0; NUM_STATS]; for v in &mut values { *v = Self::roll_initial_value(&mut rng); } Self { values } } pub fn swap(&mut self, val1: &str, val2: &str) -> bool { /* Find the positions of the two arguments */ match (STATS.binary_search(&val1), STATS.binary_search(&val2)) { (Ok(pos1), Ok(pos2)) => { /* Swap the two values without making the borrow checker mad. */ let tmp = self.values[pos1]; self.values[pos1] = self.values[pos2]; self.values[pos2] = tmp; true }, _ => false, } } pub fn get(&self, attribute: &str) -> Option { match STATS.binary_search(&attribute) { Ok(pos) => Some(self.values[pos]), Err(_) => None, } } pub fn get_mut(&mut self, attribute: &str) -> Option<&mut u8> { match STATS.binary_search(&attribute) { Ok(pos) => Some(self.values.get_mut(pos).unwrap()), Err(_) => None, } } } impl Display for Stats { fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> { writeln!(fmt, "[")?; for i in 0..NUM_STATS { writeln!(fmt, " {} = {}", STATS[i], self.values[i])?; } writeln!(fmt, "]")?; Ok(()) } } #[cfg(test)] mod tests { use super::*; fn test_stats() -> Stats { Stats::from_values([1, 2, 3, 4, 5, 6, 7]) } #[test] fn swap_same_argument() { let mut stats = test_stats(); assert_eq!(stats.get("intelligence"), Some(5)); assert!(stats.swap("intelligence", "intelligence")); assert_eq!(stats.get("intelligence"), Some(5)); assert_eq!(stats.get("wisdom"), Some(7)); assert!(stats.swap("wisdom", "wisdom")); assert_eq!(stats.get("wisdom"), Some(7)); } #[test] fn swap_invalid_argument() { let mut stats = test_stats(); assert!(!stats.swap("", "intelligence")); assert_eq!(stats, test_stats()); assert!(!stats.swap("intelligence", "")); assert_eq!(stats, test_stats()); assert!(!stats.swap("aoeu", "aoeu")); assert_eq!(stats, test_stats()); assert!(!stats.swap("", "")); assert_eq!(stats, test_stats()); } #[test] fn swap_two_arguments() { let mut stats = test_stats(); assert_eq!(stats.get("charisma"), Some(1)); assert_eq!(stats.get("strength"), Some(6)); assert!(stats.swap("strength", "charisma")); assert_eq!(stats.get("charisma"), Some(6)); assert_eq!(stats.get("strength"), Some(1)); } }