Skip to main content

nil_core/ranking/
mod.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4pub mod score;
5
6use crate::ruler::Ruler;
7use bon::Builder;
8use derive_more::Deref;
9use itertools::Itertools;
10use score::Score;
11use serde::{Deserialize, Serialize};
12
13#[derive(Clone, Debug, Deref, Deserialize, Serialize)]
14#[derive_const(Default)]
15#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
16pub struct Ranking(Vec<RankingEntry>);
17
18impl Ranking {
19  #[inline]
20  pub fn get(&self, ruler: &Ruler) -> Option<&RankingEntry> {
21    self
22      .0
23      .iter()
24      .find(|entry| &entry.ruler == ruler)
25  }
26
27  pub fn update<T>(&mut self, entries: T)
28  where
29    T: IntoIterator<Item = RankingEntry>,
30  {
31    self.0.clear();
32    let entries = entries
33      .into_iter()
34      .sorted_by_key(|it| it.score)
35      .rev()
36      .zip(1u32..)
37      .map(|(mut entry, rank)| {
38        entry.rank = Rank(rank);
39        entry
40      });
41
42    self.0.extend(entries);
43  }
44}
45
46#[derive(Builder, Clone, Debug, Deserialize, Serialize)]
47#[serde(rename_all = "camelCase")]
48#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
49pub struct RankingEntry {
50  #[builder(skip)]
51  rank: Rank,
52
53  #[builder(into)]
54  ruler: Ruler,
55
56  #[builder(into)]
57  score: Score,
58
59  #[builder(into)]
60  cities: u32,
61}
62
63#[derive(Copy, Debug, Deserialize, Serialize)]
64#[derive_const(Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
65#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
66pub struct Rank(u32);