generated from fspoettel/advent-of-code-rust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
05.rs
100 lines (89 loc) · 3.26 KB
/
05.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use itertools::Itertools;
use std::collections::HashMap;
advent_of_code::solution!(5);
pub fn part_one(input: &str) -> Option<u32> {
let split_index = input.rfind('|').unwrap() + 3;
let ordering_rules = &input[..split_index];
let split_index = input.find(',').unwrap() - 2;
let pages = &input[split_index..];
Some(count_sorted_updates(pages, &parse_ordering_rules(ordering_rules)))
}
fn parse_ordering_rules(input: &str) -> HashMap<u32, Vec<u32>> {
let mut ordering_rules: HashMap<_, Vec<_>> = HashMap::new();
input.lines()
.map(|line| line.split_once('|').unwrap())
.map(|(x, y)| (x.parse().unwrap(), y.parse().unwrap()))
.for_each(|(x, y)| {
ordering_rules.entry(y).or_default().push(x);
});
ordering_rules
}
fn count_sorted_updates(input: &str, ordering_rules: &HashMap<u32, Vec<u32>>) -> u32 {
input.lines()
.map(|line| line.split(',')
.map(|page| page.parse::<u32>().unwrap())
.collect_vec())
.filter(|pages| is_update_sorted(pages, ordering_rules))
.map(|pages| pages[pages.len() / 2])
.sum()
}
fn is_update_sorted(pages: &[u32], ordering_rules: &HashMap<u32, Vec<u32>>) -> bool {
pages.iter().enumerate()
.map(|(index, page)| (index, ordering_rules.get(page)))
.filter(|(_, page)| page.is_some())
.map(|(index, page)| (index, page.unwrap()))
.all(|(index, ordering_rules)| pages.iter()
.skip(index + 1)
.all(|next_page| !ordering_rules.contains(next_page)))
}
pub fn part_two(input: &str) -> Option<u32> {
let split_index = input.rfind('|').unwrap() + 3;
let ordering_rules = &input[..split_index];
let split_index = input.find(',').unwrap() - 2;
let pages = &input[split_index..];
Some(count_unsorted_updates(pages, &parse_ordering_rules(ordering_rules)))
}
fn count_unsorted_updates(input: &str, ordering_rules: &HashMap<u32, Vec<u32>>) -> u32 {
input.lines()
.map(|line| line.split(',')
.map(|page| page.parse::<u32>().unwrap())
.collect_vec())
.filter_map(|pages| {
let sorted_pages = sort_update(&pages, ordering_rules);
if pages == sorted_pages {
None
} else {
Some(sorted_pages)
}
})
.map(|pages| pages[pages.len() / 2])
.sum()
}
fn sort_update(pages: &[u32], ordering_rules: &HashMap<u32, Vec<u32>>) -> Vec<u32> {
let mut sorted_pages = Vec::new();
let empty_vec = Vec::default();
for page in pages {
let preceding_pages = ordering_rules.get(page).unwrap_or(&empty_vec);
let index = sorted_pages.iter()
.enumerate()
.rfind(|(_, current_page)| preceding_pages.contains(current_page))
.map(|(index, _)| index + 1)
.unwrap_or(0);
sorted_pages.insert(index, *page);
}
sorted_pages
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(143));
}
#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(123));
}
}