use std::env; use ballot::BallotType; use counter::Counter; use itertools::Itertools; pub mod candidate; pub mod ballot; pub mod header; pub mod party; mod counter; fn main() { let csv_path = { let args: Vec = env::args().collect(); if args.len() != 2 { eprintln!("Usage: {} ", args[0]); return; } args[1].clone() }; let csv = quick_csv::Csv::from_file(csv_path).unwrap().flexible(true); let counter = Counter::new(csv).unwrap(); eprintln!("Header: {:#?}", counter.header); eprintln!("Parties: {}", counter.header.parties.len()); eprintln!("Candidates: {}", counter.header.candidates.len()); let total = counter.ballots.len() as u32; let mut total_atl = 0u32; let mut total_btl = 0u32; for ballot in counter.ballots.iter() { *match ballot.ty { BallotType::Party => &mut total_atl, BallotType::Candidate => &mut total_btl, } += 1; } eprintln!("Above the line: {total_atl} {}%", f64::from(total_atl) / f64::from(total) * 100.0); eprintln!("Below the line: {total_btl} {}%", f64::from(total_btl) / f64::from(total) * 100.0); eprintln!("Total: {total}"); let ty = BallotType::Candidate; let winner_count = 6; let names = match ty { BallotType::Party => counter.header.parties.iter().map(|v| v.name.clone()).collect_vec(), BallotType::Candidate => counter.header.candidates.iter().map(|v| format!("{}: {}", v.name, v.party_id.map_or("IND", |id| &counter.header.parties[id].name), )).collect_vec(), }; let mut running = vec![true; names.len()]; let mut first = true; for name in names.iter() { if first { first = false; } else { print!(","); } print!("{name:?}"); } println!(); eprintln!("Running election rounds:"); let mut scores: Vec = Vec::new(); for index in 0..(running.len() - winner_count) { scores = counter.count_primaries(ty, &running); let (id_worst, score_worst) = match scores.iter().copied().enumerate().filter(|&(i,_)| running[i]).min_by(|a, b| u32::cmp(&a.1, &b.1)) { Some(v) => v, None => break }; let (id_best, score_best) = match scores.iter().copied().enumerate().filter(|&(i,_)| running[i]).min_by(|a, b| u32::cmp(&b.1, &a.1)) { Some(v) => v, None => break, }; let mut first = true; for (&score, &running) in scores.iter().zip(running.iter()) { if first { first = false; } else { print!(","); } if running { print!("{score}"); } } running[id_worst] = false; println!(); eprintln!(" - {index}:"); eprintln!(" Best: {} ({score_best})", names[id_best]); eprintln!(" Lost: {} ({score_worst})", names[id_worst]); } let winners = names.iter().enumerate().filter_map(|(index, name)| match running[index] { true => Some((name.as_str(), scores[index])), false => None, }).collect_vec(); eprintln!("Winners: {winners:#?}"); }