kingmaker 0.1.0

A modular, performant, social choice framework for the simulation, computation, and analysis of strategic voting.
Documentation
use std::collections::HashMap;

use crate::core::{Candidate, Id, Method, Ordinal, Profile, SingleWinner};

/// A single-winner, ranked voting method. Each rank (in the ballot) is given a value corresponding to its order. With n candidates, 1st is `n-1`, 2nd is `n-2`, and so on, with last having a value of `0`. The candidate whose sum of ranks is highest is the winner.
#[derive(Debug, Clone, serde::Serialize)]
pub struct Borda;

impl Method for Borda {
    type Ballot = Ordinal;
    type Winner = SingleWinner;
    fn outcome(&self, candidates: &[Candidate], profile: Profile<Self::Ballot>) -> Self::Winner {
        let mut tally: HashMap<Id, usize> = HashMap::with_capacity(profile.len());
        (0..profile.len()).for_each(|i| {
            for (i, candidate) in profile[i].iter().enumerate() {
                *tally.entry(*candidate).or_insert(0) += profile[i].len() - i;
            }
        });
        let max_count = tally.values().max().unwrap();
        let winners: Vec<Id> = tally
            .iter()
            .filter(|(_, count)| count == &max_count)
            .map(|(id, _)| *id)
            .collect();
        match winners.len() {
            0 => SingleWinner::none(),
            1 => SingleWinner::win(candidates, winners[0]),
            _ => SingleWinner::tie(candidates, &winners),
        }
    }
}