Skip to content

Commit 080e4c9

Browse files
committed
2024 day 5
1 parent f4491b5 commit 080e4c9

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
47|53
2+
97|13
3+
97|61
4+
97|47
5+
75|29
6+
61|13
7+
75|53
8+
29|13
9+
97|29
10+
53|29
11+
61|53
12+
97|53
13+
61|29
14+
47|13
15+
75|47
16+
97|75
17+
47|61
18+
75|61
19+
47|29
20+
75|13
21+
53|13
22+
23+
75,47,61,53,29
24+
97,61,53,29,13
25+
75,29,13
26+
75,97,47,61,53
27+
61,13,29
28+
97,13,75,29,47

crates/year2024/src/day05.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
use utils::prelude::*;
2+
3+
/// Sorting lists using a partial order of constraints.
4+
#[derive(Clone, Debug)]
5+
pub struct Day05 {
6+
rules: Rules,
7+
sorted: Vec<Vec<u32>>,
8+
unsorted: Vec<Vec<u32>>,
9+
}
10+
11+
const MIN_NUM: usize = 10;
12+
const MAX_NUM: usize = 99;
13+
const RANGE: usize = MAX_NUM - MIN_NUM + 1;
14+
type Rules = [bool; RANGE * RANGE];
15+
16+
impl Day05 {
17+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
18+
let num = parser::number_range(MIN_NUM as u32..=MAX_NUM as u32);
19+
let rules_parser = num.then(num.with_prefix(b'|')).repeat(b'\n', 1);
20+
let updates_parser = num.repeat(b',', 1).repeat(b'\n', 1);
21+
22+
let (rules_list, updates) = rules_parser
23+
.then(updates_parser.with_prefix(b'\n'))
24+
.parse_complete(input)?;
25+
26+
let mut rules = [false; RANGE * RANGE];
27+
for (a, b) in rules_list {
28+
rules[(a as usize - MIN_NUM) * RANGE + b as usize] = true;
29+
}
30+
31+
let (sorted, unsorted) = updates.into_iter().partition(|update| {
32+
for (i, &page1) in update.iter().enumerate() {
33+
for &page2 in update.iter().skip(i + 1) {
34+
if Self::must_be_before(&rules, page2, page1) {
35+
return false;
36+
}
37+
}
38+
}
39+
true
40+
});
41+
42+
Ok(Self {
43+
rules,
44+
sorted,
45+
unsorted,
46+
})
47+
}
48+
49+
#[must_use]
50+
pub fn part1(&self) -> u32 {
51+
self.sorted
52+
.iter()
53+
.map(|update| update[update.len() / 2])
54+
.sum()
55+
}
56+
57+
#[must_use]
58+
pub fn part2(&self) -> u32 {
59+
let mut result = 0;
60+
let mut list = Vec::new();
61+
for original in &self.unsorted {
62+
original.clone_into(&mut list);
63+
64+
for _ in 0..(list.len() / 2) {
65+
let i = Self::find_first_index(&self.rules, &list);
66+
list.swap_remove(i);
67+
}
68+
69+
let i = Self::find_first_index(&self.rules, &list);
70+
result += list[i];
71+
}
72+
73+
result
74+
}
75+
76+
fn must_be_before(rules: &Rules, page1: u32, page2: u32) -> bool {
77+
rules[(page1 as usize - MIN_NUM) * RANGE + page2 as usize]
78+
}
79+
80+
fn find_first_index(rules: &Rules, list: &[u32]) -> usize {
81+
'outer: for (i, &page1) in list.iter().enumerate() {
82+
for (j, &page2) in list.iter().enumerate() {
83+
if i != j && Self::must_be_before(rules, page2, page1) {
84+
continue 'outer;
85+
}
86+
}
87+
88+
return i;
89+
}
90+
panic!("no solution found");
91+
}
92+
}
93+
94+
examples!(Day05 -> (u32, u32) [
95+
{file: "day05_example0.txt", part1: 143, part2: 123},
96+
]);

crates/year2024/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ utils::year!(2024 => year2024, ${
66
2 => day02::Day02,
77
3 => day03::Day03,
88
4 => day04::Day04,
9+
5 => day05::Day05,
910
});

0 commit comments

Comments
 (0)