use std::collections::HashSet; use itertools::Itertools; fn main() { let mut data: Vec<_> = std::fs::read_to_string("input.txt") .unwrap() .lines() .map(Neighbors::parse) .collect(); part1(&data); let persons: HashSet<_> = data.iter().map(|p| p.persons.0.clone()).collect(); for p in &persons { data.push(Neighbors::new(("me".to_string(), p.to_string()), 0)); data.push(Neighbors::new((p.to_string(), "me".to_string()), 0)); } part1(&data); } fn part1(data: &[Neighbors]) { let persons: HashSet<_> = data.iter().map(|p| p.persons.0.clone()).collect(); let result = persons .iter() .permutations(persons.len()) .map(|order| calculate_happiness(&order, data)) .max() .unwrap(); println!("{result}"); } fn calculate_happiness(order: &[&String], neighbors: &[Neighbors]) -> i64 { let mut result = 0; let mut order_wrapped = order.to_vec(); order_wrapped.push(order[0]); for (a, b) in order_wrapped.iter().tuple_windows() { result += neighbors .iter() .filter(|n| { n.persons == (a.to_string(), b.to_string()) || n.persons == (b.to_string(), a.to_string()) }) .map(|p| p.happiness) .sum::(); } result } #[derive(Debug)] struct Neighbors { pub persons: (String, String), pub happiness: i64, } impl Neighbors { fn new(persons: (String, String), happiness: i64) -> Self { Self { persons, happiness } } fn parse(s: &str) -> Self { let mut parts = s.split_whitespace(); let a = parts.next().unwrap().to_string(); let mut b = parts.next_back().unwrap().to_string(); b = b.chars().take(b.len() - 1).collect(); let lose_gain = parts.nth(1).unwrap(); let sign = if lose_gain == "gain" { 1 } else { -1 }; let amount: i64 = parts.next().unwrap().parse().unwrap(); let happiness = amount * sign; Self::new((a, b), happiness) } }