Skip to content

Commit 8cab816

Browse files
committed
AOC 2024 Day 05
1 parent f6d3efc commit 8cab816

File tree

4 files changed

+160
-3
lines changed

4 files changed

+160
-3
lines changed

aoc/2024/rust/Cargo.lock

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aoc/2024/rust/Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ test_lib = []
2424
# Template dependencies
2525
chrono = { version = "0.4.38", optional = true }
2626
dhat = { version = "0.3.3", optional = true }
27-
glam = "0.29.2"
28-
itertools = "0.13.0"
2927
pico-args = "0.5.0"
30-
regex = "1.11.1"
3128
tinyjson = "2.5.1"
3229

3330
# Solution dependencies
31+
glam = "0.29.2"
32+
itertools = "0.13.0"
33+
nom = "7.1.3"
34+
regex = "1.11.1"

aoc/2024/rust/data/examples/05.txt

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

aoc/2024/rust/src/bin/05.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
advent_of_code::solution!(5);
2+
3+
use nom::{
4+
bytes::complete::tag,
5+
character::complete::{digit1, line_ending},
6+
combinator::map_res,
7+
multi::separated_list1,
8+
sequence::separated_pair,
9+
IResult,
10+
};
11+
use std::{
12+
cmp::Ordering,
13+
collections::{HashMap, HashSet},
14+
};
15+
16+
fn parse_u32(input: &str) -> IResult<&str, u32> {
17+
map_res(digit1, str::parse::<u32>)(input)
18+
}
19+
20+
fn parse_ordering(input: &str) -> IResult<&str, Vec<(u32, u32)>> {
21+
separated_list1(line_ending, separated_pair(parse_u32, tag("|"), parse_u32))(input)
22+
}
23+
24+
fn parse_books(input: &str) -> IResult<&str, Vec<Vec<u32>>> {
25+
separated_list1(line_ending, separated_list1(tag(","), parse_u32))(input)
26+
}
27+
28+
fn parse(input: &str) -> IResult<&str, (Vec<(u32, u32)>, Vec<Vec<u32>>)> {
29+
separated_pair(parse_ordering, tag("\n\n"), parse_books)(input)
30+
}
31+
32+
fn is_sorted_book(rules: &HashMap<u32, HashSet<u32>>, book: &Vec<u32>) -> bool {
33+
let mut seen = HashSet::new();
34+
for page in book {
35+
if let Some(not_allowed_pages) = rules.get(&page) {
36+
if seen.intersection(not_allowed_pages).count() > 0 {
37+
return false;
38+
}
39+
}
40+
seen.insert(*page);
41+
}
42+
true
43+
}
44+
45+
/// Given a vector of tuples with values that need to be before | after each other, return a hashmap
46+
/// of u32 => HashSet<u32> where the hashsets contain values that cannot come before the key.
47+
fn get_rules(pairs: Vec<(u32, u32)>) -> HashMap<u32, HashSet<u32>> {
48+
let mut rules: HashMap<u32, HashSet<u32>> = HashMap::new();
49+
for (before, after) in pairs {
50+
rules
51+
.entry(before)
52+
.and_modify(|hm| {
53+
hm.insert(after);
54+
})
55+
.or_insert(HashSet::from([after]));
56+
}
57+
rules
58+
}
59+
60+
pub fn part_one(input: &str) -> Option<u32> {
61+
let (_, (pairs, books)) = parse(input).unwrap();
62+
let rules = get_rules(pairs);
63+
Some(
64+
books
65+
.into_iter()
66+
.filter(|book| is_sorted_book(&rules, &book))
67+
.map(|v| v[v.len() / 2])
68+
.sum(),
69+
)
70+
}
71+
72+
pub fn part_two(input: &str) -> Option<u32> {
73+
let (_, (pairs, books)) = parse(input).unwrap();
74+
let rules = get_rules(pairs);
75+
Some(
76+
books
77+
.into_iter()
78+
.filter(|book| !is_sorted_book(&rules, &book))
79+
.map(|mut book| {
80+
book.sort_by(|a, b| {
81+
if rules
82+
.get(a)
83+
.is_some_and(|not_before| not_before.contains(&b))
84+
{
85+
Ordering::Less
86+
} else {
87+
Ordering::Greater
88+
}
89+
});
90+
book[book.len() / 2]
91+
})
92+
.sum(),
93+
)
94+
}
95+
96+
#[cfg(test)]
97+
mod tests {
98+
use super::*;
99+
100+
#[test]
101+
fn test_part_one() {
102+
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
103+
assert_eq!(result, Some(143));
104+
}
105+
106+
#[test]
107+
fn test_part_two() {
108+
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
109+
assert_eq!(result, Some(123));
110+
}
111+
}

0 commit comments

Comments
 (0)