advent_of_code/year2015/
day13.rs

1use crate::common::id_assigner::IdAssigner;
2use crate::common::permutation::all_permutations;
3use crate::input::Input;
4
5const MAX_ATTENDEES: usize = 10;
6
7pub fn solve(input: &Input) -> Result<i32, String> {
8    let mut id_assigner = IdAssigner::<MAX_ATTENDEES, str>::new("");
9
10    let mut happiness_changes = Vec::new();
11    for line in input.text.lines() {
12        // "Alice would lose 79 happiness units by sitting next to Carol."
13        let words = line.split(' ').collect::<Vec<_>>();
14        if words.len() != 11 {
15            return Err("Invalid line not consisting of 11 words".to_string());
16        }
17
18        let person_name = words[0];
19        let happiness_change = words[3]
20            .parse::<i32>()
21            .map_err(|_| "Invalid happiness change")?
22            * if words[2] == "gain" { 1 } else { -1 };
23        let other_name = &words[10]
24            .strip_suffix('.')
25            .ok_or_else(|| "Line not ending with a period".to_string())?;
26
27        let person_id = id_assigner.id_of(person_name)? as usize;
28        let other_id = id_assigner.id_of(other_name)? as usize;
29
30        while person_id >= happiness_changes.len() {
31            happiness_changes.push(Vec::new());
32        }
33
34        if other_id != happiness_changes[person_id].len() {
35            // This person
36            happiness_changes[person_id].push(0);
37        }
38
39        happiness_changes[person_id].push(happiness_change);
40    }
41
42    if input.is_part_two() {
43        // Last person was not added 0 for.
44        let last = happiness_changes.len() - 1;
45        happiness_changes[last].push(0);
46
47        let changes_for_me = vec![0; happiness_changes.len()];
48        happiness_changes.push(changes_for_me);
49        for change in happiness_changes.iter_mut() {
50            change.push(0);
51        }
52    }
53
54    let mut seating_arrangement = Vec::new();
55    for i in 0..happiness_changes.len() {
56        seating_arrangement.push(i);
57    }
58
59    let mut best_happiness = 0;
60    all_permutations(&mut seating_arrangement, &mut |arrangement| {
61        let mut this_happiness_change = 0;
62
63        for i in 0..arrangement.len() {
64            let this = arrangement[i];
65            let next = arrangement[(i + 1) % arrangement.len()];
66            this_happiness_change += happiness_changes[this][next] + happiness_changes[next][this];
67        }
68
69        best_happiness = std::cmp::max(best_happiness, this_happiness_change);
70        Ok(())
71    })?;
72
73    Ok(best_happiness)
74}
75
76#[test]
77pub fn tests() {
78    use crate::input::{test_part_one, test_part_two};
79
80    test_part_one!("Alice would gain 54 happiness units by sitting next to Bob.
81Alice would lose 79 happiness units by sitting next to Carol.
82Alice would lose 2 happiness units by sitting next to David.
83Bob would gain 83 happiness units by sitting next to Alice.
84Bob would lose 7 happiness units by sitting next to Carol.
85Bob would lose 63 happiness units by sitting next to David.
86Carol would lose 62 happiness units by sitting next to Alice.
87Carol would gain 60 happiness units by sitting next to Bob.
88Carol would gain 55 happiness units by sitting next to David.
89David would gain 46 happiness units by sitting next to Alice.
90David would lose 7 happiness units by sitting next to Bob.
91David would gain 41 happiness units by sitting next to Carol." => 330);
92
93    let real_input = include_str!("day13_input.txt");
94    test_part_one!(real_input => 664);
95    test_part_two!(real_input => 640);
96}