use std::cmp::Ordering::Equal; use std::collections::HashMap; enum GameResult { Win, Draw, Loss } struct TeamResult { wins: u32, draws: u32, losses: u32, } impl TeamResult { fn new() -> TeamResult { TeamResult { wins: 0, draws: 0, losses: 0 } } fn add_game_result(&mut self, result: GameResult) { match result { GameResult::Win => self.wins += 1, GameResult::Draw => self.draws += 1, GameResult::Loss => self.losses += 1, } } } pub fn tally(input: &str) -> String { let mut results: HashMap = HashMap::new(); for line in input.to_string().lines() { let parts: Vec<&str> = line.trim_right().split(';').collect(); if parts.len() != 3 { continue; } let team1 = parts[0]; let team2 = parts[1]; let outcome = parts[2]; match outcome { "win" => { add_game_result(&mut results, team1.to_string(), GameResult::Win); add_game_result(&mut results, team2.to_string(), GameResult::Loss); }, "draw" => { add_game_result(&mut results, team1.to_string(), GameResult::Draw); add_game_result(&mut results, team2.to_string(), GameResult::Draw); }, "loss" => { add_game_result(&mut results, team1.to_string(), GameResult::Loss); add_game_result(&mut results, team2.to_string(), GameResult::Win); }, _ => () // Ignore bad lines } } write_tally(&results) } fn write_tally(results: &HashMap) -> String { let mut v: Vec<_> = results.iter().map(|(team, r)| { let games = r.wins + r.draws + r.losses; let points = r.wins * 3 + r.draws; (team, games, r, points) }).collect(); // Sort by points, then games played, in reverse order. v.sort_by(|a, b| match a.3.cmp(&(b.3)).reverse() { Equal => a.1.cmp(&(b.1)).reverse(), other => other }); let header = format!("{:30} | MP | W | D | L | P\n", "Team"); let lines: Vec<_> = v.iter().map(|&(ref team, games, r, points)| { format!("{:30} | {:2} | {:2} | {:2} | {:2} | {:2}", team, games, r.wins, r.draws, r.losses, points) }).collect(); header + &lines.join("\n") } fn add_game_result(results: &mut HashMap, team: String, result: GameResult) { results.entry(team).or_insert(TeamResult::new()).add_game_result(result); }