use super::types::*;
use crate::state::State;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TerritoryState {
control: HashMap<TerritoryId, f32>,
development: HashMap<TerritoryId, u32>,
effects: HashMap<TerritoryId, TerritoryEffects>,
}
impl State for TerritoryState {}
impl TerritoryState {
pub fn new() -> Self {
Self {
control: HashMap::new(),
development: HashMap::new(),
effects: HashMap::new(),
}
}
pub fn initialize(&mut self, id: &TerritoryId) {
self.control.insert(id.clone(), 0.0);
self.development.insert(id.clone(), 0);
self.effects.insert(id.clone(), TerritoryEffects::default());
}
pub fn contains(&self, id: &TerritoryId) -> bool {
self.control.contains_key(id)
}
pub fn get_control(&self, id: &TerritoryId) -> Option<f32> {
self.control.get(id).copied()
}
pub fn set_control(&mut self, id: &TerritoryId, control: f32) -> Option<ControlChanged> {
let old_control = *self.control.get(id)?;
let new_control = control.clamp(0.0, 1.0);
self.control.insert(id.clone(), new_control);
Some(ControlChanged {
id: id.clone(),
old_control,
new_control,
delta: new_control - old_control,
})
}
pub fn adjust_control(&mut self, id: &TerritoryId, delta: f32) -> Option<ControlChanged> {
let old_control = *self.control.get(id)?;
let (new_control, actual_delta) =
super::service::TerritoryService::calculate_control_change(old_control, delta);
self.control.insert(id.clone(), new_control);
Some(ControlChanged {
id: id.clone(),
old_control,
new_control,
delta: actual_delta,
})
}
pub fn get_development(&self, id: &TerritoryId) -> Option<u32> {
self.development.get(id).copied()
}
pub fn set_development(&mut self, id: &TerritoryId, level: u32) -> Option<Developed> {
let old_level = *self.development.get(id)?;
self.development.insert(id.clone(), level);
Some(Developed {
id: id.clone(),
old_level,
new_level: level,
})
}
pub fn develop(&mut self, id: &TerritoryId) -> Option<Developed> {
let old_level = *self.development.get(id)?;
let new_level = old_level + 1;
self.development.insert(id.clone(), new_level);
Some(Developed {
id: id.clone(),
old_level,
new_level,
})
}
pub fn get_effects(&self, id: &TerritoryId) -> Option<&TerritoryEffects> {
self.effects.get(id)
}
pub fn set_effects(&mut self, id: &TerritoryId, effects: TerritoryEffects) -> bool {
if !self.effects.contains_key(id) {
return false;
}
self.effects.insert(id.clone(), effects);
true
}
pub fn territory_ids(&self) -> impl Iterator<Item = &TerritoryId> {
self.control.keys()
}
pub fn controlled_territories(&self, threshold: f32) -> Vec<TerritoryId> {
self.control
.iter()
.filter(|(_, &control)| control >= threshold)
.map(|(id, _)| id.clone())
.collect()
}
pub fn developed_territories(&self, min_level: u32) -> Vec<TerritoryId> {
self.development
.iter()
.filter(|(_, &level)| level >= min_level)
.map(|(id, _)| id.clone())
.collect()
}
}
impl Default for TerritoryState {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_state_new() {
let state = TerritoryState::new();
assert!(!state.contains(&TerritoryId::new("nova")));
}
#[test]
fn test_initialize() {
let mut state = TerritoryState::new();
state.initialize(&TerritoryId::new("nova"));
assert!(state.contains(&TerritoryId::new("nova")));
assert_eq!(state.get_control(&TerritoryId::new("nova")), Some(0.0));
assert_eq!(state.get_development(&TerritoryId::new("nova")), Some(0));
}
#[test]
fn test_set_control() {
let mut state = TerritoryState::new();
state.initialize(&TerritoryId::new("nova"));
let change = state.set_control(&TerritoryId::new("nova"), 0.5);
assert!(change.is_some());
let change = change.unwrap();
assert_eq!(change.old_control, 0.0);
assert_eq!(change.new_control, 0.5);
assert_eq!(change.delta, 0.5);
assert_eq!(state.get_control(&TerritoryId::new("nova")), Some(0.5));
}
#[test]
fn test_set_control_clamping() {
let mut state = TerritoryState::new();
state.initialize(&TerritoryId::new("nova"));
state.set_control(&TerritoryId::new("nova"), 1.5);
assert_eq!(state.get_control(&TerritoryId::new("nova")), Some(1.0));
state.set_control(&TerritoryId::new("nova"), -0.5);
assert_eq!(state.get_control(&TerritoryId::new("nova")), Some(0.0));
}
#[test]
fn test_adjust_control() {
let mut state = TerritoryState::new();
state.initialize(&TerritoryId::new("nova"));
state.set_control(&TerritoryId::new("nova"), 0.5);
let change = state.adjust_control(&TerritoryId::new("nova"), 0.2);
assert!(change.is_some());
let change = change.unwrap();
assert_eq!(change.old_control, 0.5);
assert!((change.new_control - 0.7).abs() < 0.001);
assert!((change.delta - 0.2).abs() < 0.001);
let change = state.adjust_control(&TerritoryId::new("nova"), 0.5);
assert!(change.is_some());
let change = change.unwrap();
assert_eq!(change.new_control, 1.0);
assert!((change.delta - 0.3).abs() < 0.001); }
#[test]
fn test_develop() {
let mut state = TerritoryState::new();
state.initialize(&TerritoryId::new("nova"));
let dev = state.develop(&TerritoryId::new("nova"));
assert!(dev.is_some());
let dev = dev.unwrap();
assert_eq!(dev.old_level, 0);
assert_eq!(dev.new_level, 1);
assert_eq!(state.get_development(&TerritoryId::new("nova")), Some(1));
}
#[test]
fn test_set_effects() {
let mut state = TerritoryState::new();
state.initialize(&TerritoryId::new("nova"));
let effects = TerritoryEffects::default()
.with_income_multiplier(1.5)
.with_cost_multiplier(0.8);
assert!(state.set_effects(&TerritoryId::new("nova"), effects.clone()));
let retrieved = state.get_effects(&TerritoryId::new("nova"));
assert!(retrieved.is_some());
assert_eq!(retrieved.unwrap().income_multiplier, 1.5);
assert_eq!(retrieved.unwrap().cost_multiplier, 0.8);
}
#[test]
fn test_controlled_territories() {
let mut state = TerritoryState::new();
state.initialize(&TerritoryId::new("nova"));
state.initialize(&TerritoryId::new("rust"));
state.initialize(&TerritoryId::new("vapor"));
state.set_control(&TerritoryId::new("nova"), 0.8);
state.set_control(&TerritoryId::new("rust"), 0.3);
state.set_control(&TerritoryId::new("vapor"), 1.0);
let controlled = state.controlled_territories(0.5);
assert_eq!(controlled.len(), 2);
}
#[test]
fn test_developed_territories() {
let mut state = TerritoryState::new();
state.initialize(&TerritoryId::new("nova"));
state.initialize(&TerritoryId::new("rust"));
state.set_development(&TerritoryId::new("nova"), 5);
state.set_development(&TerritoryId::new("rust"), 2);
let developed = state.developed_territories(3);
assert_eq!(developed.len(), 1);
assert_eq!(developed[0].as_str(), "nova");
}
}