Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e280de99e |
@@ -0,0 +1,115 @@
|
||||
use crate::models::card::CardDefinition;
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
pub struct ChemistryResult {
|
||||
/// Sum of all player chemistry values, max 33 (11 × 3).
|
||||
pub total: u8,
|
||||
/// Per-player chemistry in the same order as the input slice (1–3 each).
|
||||
pub per_player: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
enum LinkStrength {
|
||||
/// Same club AND same nationality.
|
||||
Full,
|
||||
/// Same league OR same nationality (but not Full).
|
||||
Half,
|
||||
None,
|
||||
}
|
||||
|
||||
fn link_strength(a: &CardDefinition, b: &CardDefinition) -> LinkStrength {
|
||||
if a.club == b.club && a.nation == b.nation {
|
||||
return LinkStrength::Full;
|
||||
}
|
||||
if a.league == b.league || a.nation == b.nation {
|
||||
return LinkStrength::Half;
|
||||
}
|
||||
LinkStrength::None
|
||||
}
|
||||
|
||||
/// Compute team chemistry for a squad given the resolved `CardDefinition`s.
|
||||
///
|
||||
/// Each player starts at 1 chemistry. Full links add 2 to both players;
|
||||
/// half links add 1. Each player is clamped to [1, 3].
|
||||
/// Squad chemistry is the sum of all player chemistry values (max 33).
|
||||
pub fn calculate_chemistry(cards: &[CardDefinition]) -> ChemistryResult {
|
||||
let n = cards.len();
|
||||
let mut per_player: Vec<i16> = vec![1; n];
|
||||
|
||||
for i in 0..n {
|
||||
for j in (i + 1)..n {
|
||||
let bonus = match link_strength(&cards[i], &cards[j]) {
|
||||
LinkStrength::Full => 2,
|
||||
LinkStrength::Half => 1,
|
||||
LinkStrength::None => 0,
|
||||
};
|
||||
if bonus > 0 {
|
||||
per_player[i] += bonus;
|
||||
per_player[j] += bonus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let per_player: Vec<u8> = per_player
|
||||
.into_iter()
|
||||
.map(|c| c.clamp(1, 3) as u8)
|
||||
.collect();
|
||||
|
||||
let total = per_player.iter().map(|&c| c as u16).sum::<u16>() as u8;
|
||||
ChemistryResult { total, per_player }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::models::card::Rarity;
|
||||
|
||||
fn card(club: &str, league: &str, nation: &str) -> CardDefinition {
|
||||
CardDefinition {
|
||||
id: "x".into(),
|
||||
name: "Player".into(),
|
||||
overall: 75,
|
||||
position: "CM".into(),
|
||||
nation: nation.into(),
|
||||
league: league.into(),
|
||||
club: club.into(),
|
||||
pace: 75,
|
||||
shooting: 75,
|
||||
passing: 75,
|
||||
dribbling: 75,
|
||||
defending: 75,
|
||||
physical: 75,
|
||||
rarity: Rarity::Gold,
|
||||
image_path: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_same_club_and_nationality_max_chem() {
|
||||
let cards: Vec<_> = (0..11).map(|_| card("FC Test", "LaLiga", "ESP")).collect();
|
||||
let result = calculate_chemistry(&cards);
|
||||
assert_eq!(result.total, 33);
|
||||
assert!(result.per_player.iter().all(|&c| c == 3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_different_attributes_min_chem() {
|
||||
let cards: Vec<_> = (0..11)
|
||||
.map(|i| card(&format!("Club{i}"), &format!("League{i}"), &format!("N{i}")))
|
||||
.collect();
|
||||
let result = calculate_chemistry(&cards);
|
||||
assert_eq!(result.total, 11);
|
||||
assert!(result.per_player.iter().all(|&c| c == 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_league_gives_half_links() {
|
||||
// All same league but different club and nation → half links only.
|
||||
let cards: Vec<_> = (0..11)
|
||||
.map(|i| card(&format!("Club{i}"), "PremierLeague", &format!("N{i}")))
|
||||
.collect();
|
||||
let result = calculate_chemistry(&cards);
|
||||
// Each player has half links to all 10 others → +10, clamped to 3.
|
||||
assert!(result.per_player.iter().all(|&c| c == 3));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user