Skip to content

Commit

Permalink
Day 5: Print Queue
Browse files Browse the repository at this point in the history
  • Loading branch information
ephemient committed Dec 5, 2024
1 parent 2e82aae commit f00b61e
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ Development occurs in language-specific directories:
|[Day2.hs](hs/src/Day2.hs)|[Day2.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day2.kt)|[day2.py](py/aoc2024/day2.py)|[day2.rs](rs/src/day2.rs)|
|[Day3.hs](hs/src/Day3.hs)|[Day3.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day3.kt)|[day3.py](py/aoc2024/day3.py)|[day3.rs](rs/src/day3.rs)|
|[Day4.hs](hs/src/Day4.hs)|[Day4.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day4.kt)|[day4.py](py/aoc2024/day4.py)|[day4.rs](rs/src/day4.rs)|
|[Day5.hs](hs/src/Day5.hs)|[Day5.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day5.kt)|[day5.py](py/aoc2024/day5.py)||
|[Day5.hs](hs/src/Day5.hs)|[Day5.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day5.kt)|[day5.py](py/aoc2024/day5.py)|[day5.rs](rs/src/day5.rs)|
28 changes: 28 additions & 0 deletions rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ name = "aoc2024"
path = "src/main.rs"

[dependencies]
array-util = "1.0.2"
anyhow = "1.0"
array-util = "1"
itertools = "0.13"
thiserror = "2"

[dev-dependencies]
criterion = "0.5.1"
Expand Down
8 changes: 7 additions & 1 deletion rs/benches/criterion.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use aoc2024::{day1, day2, day3, day4};
use aoc2024::{day1, day2, day3, day4, day5};
use criterion::{black_box, Criterion};
use std::env;
use std::fs;
Expand Down Expand Up @@ -38,6 +38,12 @@ fn aoc2024_bench(c: &mut Criterion) -> io::Result<()> {
g.bench_function("part 2", |b| b.iter(|| day4::part2(black_box(&data))));
g.finish();

let data = get_day_input(5)?;
let mut g = c.benchmark_group("day 5");
g.bench_function("part 1", |b| b.iter(|| day5::part1(black_box(&data))));
g.bench_function("part 2", |b| b.iter(|| day5::part2(black_box(&data))));
g.finish();

Ok(())
}

Expand Down
130 changes: 130 additions & 0 deletions rs/src/day5.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use std::collections::BTreeSet;
use std::mem::swap;
use std::num::ParseIntError;

#[derive(Debug, Eq, PartialEq, thiserror::Error)]
pub enum Error {
#[error("Format")]
Format,
#[error("Parse({0})")]
Parse(ParseIntError),
}

impl From<ParseIntError> for Error {
fn from(value: ParseIntError) -> Self {
Self::Parse(value)
}
}

type ParsedInput = (BTreeSet<(u32, u32)>, Vec<Vec<u32>>);

fn parse(data: &str) -> Result<ParsedInput, Error> {
let (deps, updates) = data.split_once("\n\n").ok_or(Error::Format)?;
let deps = deps
.lines()
.map(|line| {
let (x, y) = line.split_once('|').ok_or(Error::Format)?;
Ok((x.parse()?, y.parse()?))
})
.collect::<Result<_, Error>>()?;
let updates = updates
.lines()
.map(|line| line.split(',').map(|page| page.parse::<u32>()).collect())
.collect::<Result<Vec<_>, _>>()?;
Ok((deps, updates))
}

pub fn part1(data: &str) -> Result<u32, Error> {
let (deps, updates) = parse(data)?;
Ok(updates
.into_iter()
.filter_map(|pages| {
if pages
.iter()
.enumerate()
.all(|(i, x)| pages[i + 1..].iter().all(|y| !deps.contains(&(*y, *x))))
{
pages.get(pages.len() / 2).copied()
} else {
None
}
})
.sum())
}

pub fn part2(data: &str) -> Result<u32, Error> {
let (deps, updates) = parse(data)?;
Ok(updates
.into_iter()
.filter_map(|mut pages| {
let mut deranged = false;
for i in 0..pages.len() {
let pages = &mut pages[i..];
'scan: loop {
let (x, pages) = pages.split_first_mut().unwrap();
for y in pages.iter_mut() {
if deps.contains(&(*y, *x)) {
deranged = true;
swap(x, y);
continue 'scan;
}
}
break;
}
}
if deranged {
pages.get(pages.len() / 2).copied()
} else {
None
}
})
.sum())
}

#[cfg(test)]
mod tests {
use super::*;
use indoc::indoc;
use pretty_assertions::assert_eq;

static EXAMPLE: &str = indoc! {"
47|53
97|13
97|61
97|47
75|29
61|13
75|53
29|13
97|29
53|29
61|53
97|53
61|29
47|13
75|47
97|75
47|61
75|61
47|29
75|13
53|13
75,47,61,53,29
97,61,53,29,13
75,29,13
75,97,47,61,53
61,13,29
97,13,75,29,47
"};

#[test]
fn part1_examples() {
assert_eq!(Ok(143), part1(EXAMPLE));
}

#[test]
fn part2_examples() {
assert_eq!(Ok(123), part2(EXAMPLE));
}
}
1 change: 1 addition & 0 deletions rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ pub mod day1;
pub mod day2;
pub mod day3;
pub mod day4;
pub mod day5;
12 changes: 10 additions & 2 deletions rs/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use aoc2024::{day1, day2, day3, day4};
use aoc2024::{day1, day2, day3, day4, day5};
use std::collections::HashSet;
use std::env;
use std::fs;
Expand All @@ -13,7 +13,7 @@ fn get_day_input(day: u8) -> io::Result<String> {
fs::read_to_string(Path::new(&datadir).join(format!("day{}.txt", day)))
}

fn main() -> io::Result<()> {
fn main() -> anyhow::Result<()> {
let args = env::args().skip(1).collect::<HashSet<_>>();

if args.is_empty() || args.contains("1") {
Expand Down Expand Up @@ -48,5 +48,13 @@ fn main() -> io::Result<()> {
println!();
}

if args.is_empty() || args.contains("5") {
println!("Day 5");
let data = get_day_input(5)?;
println!("{:?}", day5::part1(&data)?);
println!("{:?}", day5::part2(&data)?);
println!();
}

Ok(())
}

0 comments on commit f00b61e

Please sign in to comment.