use super::types::Outcome;
use rand::Rng;
#[derive(Debug, Clone, Default)]
pub struct FactionService;
impl FactionService {
pub fn new() -> Self {
Self
}
pub fn calculate_operation_cost(
base_cost: i64,
cost_multiplier: f32,
modifiers: &[f32],
) -> i64 {
let modifier_product: f32 = modifiers.iter().product();
let final_cost = base_cost as f32 * cost_multiplier * modifier_product;
final_cost.max(0.0).round() as i64
}
pub fn calculate_success_rate(faction_power: f32, difficulty: f32, modifiers: &[f32]) -> f32 {
if difficulty <= 0.0 {
return 1.0; }
let power_ratio = faction_power / difficulty;
let base_rate = power_ratio / 4.0;
let modifier_product: f32 = modifiers.iter().product();
let final_rate = base_rate * modifier_product;
final_rate.clamp(0.0, 1.0)
}
pub fn generate_outcome(
operation_id: impl Into<String>,
success_rate: f32,
rng: &mut impl Rng,
) -> Outcome {
let success = rng.gen_bool(success_rate.clamp(0.0, 1.0) as f64);
Outcome::new(operation_id, success)
}
pub fn generate_outcome_with_metrics(
operation_id: impl Into<String>,
success_rate: f32,
rng: &mut impl Rng,
success_metrics: std::collections::HashMap<String, f32>,
failure_metrics: std::collections::HashMap<String, f32>,
) -> Outcome {
let success = rng.gen_bool(success_rate.clamp(0.0, 1.0) as f64);
let mut outcome = Outcome::new(operation_id, success);
outcome.metrics = if success {
success_metrics
} else {
failure_metrics
};
outcome
}
pub fn calculate_relationship_change(
base_change: f32,
operation_success: bool,
success_multiplier: f32,
failure_multiplier: f32,
) -> f32 {
if operation_success {
base_change * success_multiplier
} else {
base_change * failure_multiplier
}
}
pub fn estimate_operation_effectiveness(
success_rate: f32,
success_value: f32,
failure_value: f32,
) -> f32 {
(success_rate * success_value) + ((1.0 - success_rate) * failure_value)
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::rngs::StdRng;
use rand::SeedableRng;
use std::collections::HashMap;
#[test]
fn test_calculate_operation_cost() {
let cost = FactionService::calculate_operation_cost(1000, 1.0, &[]);
assert_eq!(cost, 1000);
let cost = FactionService::calculate_operation_cost(1000, 1.2, &[]);
assert_eq!(cost, 1200);
let cost = FactionService::calculate_operation_cost(1000, 1.2, &[0.9, 0.8]);
assert_eq!(cost, 864);
let cost = FactionService::calculate_operation_cost(0, 1.2, &[0.9]);
assert_eq!(cost, 0);
let cost = FactionService::calculate_operation_cost(-100, 1.0, &[]);
assert_eq!(cost, 0);
}
#[test]
fn test_calculate_success_rate() {
let rate = FactionService::calculate_success_rate(100.0, 100.0, &[]);
assert_eq!(rate, 0.25);
let rate = FactionService::calculate_success_rate(200.0, 100.0, &[]);
assert_eq!(rate, 0.5);
let rate = FactionService::calculate_success_rate(200.0, 100.0, &[1.5]);
assert_eq!(rate, 0.75);
let rate = FactionService::calculate_success_rate(400.0, 100.0, &[1.5]);
assert_eq!(rate, 1.0);
let rate = FactionService::calculate_success_rate(100.0, 0.0, &[]);
assert_eq!(rate, 1.0);
let rate = FactionService::calculate_success_rate(10.0, 100.0, &[]);
assert_eq!(rate, 0.025); }
#[test]
fn test_generate_outcome() {
let mut rng = StdRng::seed_from_u64(42);
let outcome = FactionService::generate_outcome("op-001", 1.0, &mut rng);
assert!(outcome.success);
let outcome = FactionService::generate_outcome("op-002", 0.0, &mut rng);
assert!(!outcome.success);
let _outcome = FactionService::generate_outcome("op-003", 0.5, &mut rng);
}
#[test]
fn test_generate_outcome_with_metrics() {
let mut rng = StdRng::seed_from_u64(42);
let success_metrics =
HashMap::from([("territory_gained".into(), 1.0), ("casualties".into(), 5.0)]);
let failure_metrics =
HashMap::from([("casualties".into(), 15.0), ("morale_loss".into(), 10.0)]);
let outcome = FactionService::generate_outcome_with_metrics(
"op-001",
1.0,
&mut rng,
success_metrics.clone(),
failure_metrics.clone(),
);
assert!(outcome.success);
assert_eq!(outcome.metrics.get("territory_gained"), Some(&1.0));
assert_eq!(outcome.metrics.get("casualties"), Some(&5.0));
let outcome = FactionService::generate_outcome_with_metrics(
"op-002",
0.0,
&mut rng,
success_metrics,
failure_metrics,
);
assert!(!outcome.success);
assert_eq!(outcome.metrics.get("casualties"), Some(&15.0));
assert_eq!(outcome.metrics.get("morale_loss"), Some(&10.0));
}
#[test]
fn test_calculate_relationship_change() {
let change = FactionService::calculate_relationship_change(10.0, true, 1.5, 0.5);
assert_eq!(change, 15.0);
let change = FactionService::calculate_relationship_change(10.0, false, 1.5, 0.5);
assert_eq!(change, 5.0);
let change = FactionService::calculate_relationship_change(-10.0, false, 1.5, 0.5);
assert_eq!(change, -5.0); }
#[test]
fn test_estimate_operation_effectiveness() {
let effectiveness = FactionService::estimate_operation_effectiveness(0.7, 100.0, -30.0);
assert!((effectiveness - 61.0).abs() < 0.001);
let effectiveness = FactionService::estimate_operation_effectiveness(1.0, 100.0, -30.0);
assert_eq!(effectiveness, 100.0);
let effectiveness = FactionService::estimate_operation_effectiveness(0.0, 100.0, -30.0);
assert_eq!(effectiveness, -30.0);
let effectiveness = FactionService::estimate_operation_effectiveness(0.5, 100.0, -100.0);
assert_eq!(effectiveness, 0.0); }
}