use crate::game::Game;
use ordered_float::OrderedFloat;
use std::collections::{HashMap, HashSet};
pub type Payoff = OrderedFloat<f64>;
#[derive(Debug, Clone, Default)]
pub struct Payoffs<G: Game> {
payoffs: HashMap<G::Player, Payoff>,
}
impl<G: Game> Payoffs<G> {
pub fn from_players(players: HashSet<G::Player>) -> Self {
Self {
payoffs: players
.into_iter()
.map(|player| (player, OrderedFloat(0.0)))
.collect(),
}
}
pub fn from_map(payoffs: HashMap<G::Player, Payoff>) -> Self {
Self { payoffs }
}
pub fn from_slice(slice: &[(G::Player, Payoff)]) -> Self {
Self {
payoffs: HashMap::from_iter(slice.iter().cloned()),
}
}
pub fn payoff(&self, player: &G::Player) -> Option<&Payoff> {
self.payoffs.get(player)
}
pub fn iter(&self) -> impl Iterator<Item=(&G::Player, &Payoff)> {
let mut payoffs = self.payoffs.iter().collect::<Vec<_>>();
payoffs.sort_by(|(p1, _), (p2, _)| p1.cmp(p2));
payoffs.into_iter()
}
}
impl<G: Game> std::ops::Add for Payoffs<G> {
type Output = Payoffs<G>;
fn add(self, other: Self) -> Self {
let mut result = self.clone();
result += other;
result
}
}
impl<G: Game> std::ops::AddAssign for Payoffs<G> {
fn add_assign(&mut self, other: Self) {
self.add_assign(&other);
}
}
impl<G: Game> std::ops::AddAssign<&Payoffs<G>> for Payoffs<G> {
fn add_assign(&mut self, other: &Self) {
for (player, payoff) in other.payoffs.iter() {
self.payoffs
.entry(player.clone())
.and_modify(|e| *e += *payoff)
.or_insert(*payoff);
}
}
}