diff --git a/src/bin/01.rs b/src/bin/01.rs index 41e6610..d2f7181 100644 --- a/src/bin/01.rs +++ b/src/bin/01.rs @@ -1,18 +1,16 @@ -use aoc::*; - -const INPUT: &str = include_str!("../../input/01"); - fn main() { - println!("Part 1: {}", part1(INPUT)); - println!("Part 2: {}", part2(INPUT)); + let input = include_str!("../../input/01"); + println!("Part 1: {}", part1(input)); + println!("Part 2: {}", part2(input)); } #[test] fn example() { - assert_example!(part1, "01-test", 3); + let input = include_str!("../../input/01-test"); + assert_eq!(part1(input), 3); assert_eq!(part2("R1000"), 10); assert_eq!(part2("R950"), 10); - assert_example!(part2, "01-test", 6); + assert_eq!(part2(input), 6); } fn part1(input: &str) -> usize { diff --git a/src/bin/02.rs b/src/bin/02.rs index 53742cb..57d4d50 100644 --- a/src/bin/02.rs +++ b/src/bin/02.rs @@ -1,16 +1,14 @@ -use aoc::*; - -const INPUT: &str = include_str!("../../input/02"); - fn main() { - println!("Part 1: {}", part1(INPUT)); - println!("Part 2: {}", part2(INPUT)); + let input = include_str!("../../input/02"); + println!("Part 1: {}", part1(input)); + println!("Part 2: {}", part2(input)); } #[test] fn example() { - assert_example!(part1, "02-test", 1227775554); - assert_example!(part2, "02-test", 4174379265); + let input = include_str!("../../input/02-test"); + assert_eq!(part1(input), 1227775554); + assert_eq!(part2(input), 4174379265); } fn part1(input: &str) -> usize { diff --git a/src/bin/03.rs b/src/bin/03.rs index 7ae9849..95045a6 100644 --- a/src/bin/03.rs +++ b/src/bin/03.rs @@ -1,16 +1,14 @@ -use aoc::*; - -const INPUT: &str = include_str!("../../input/03"); - fn main() { - println!("Part 1: {}", part1(INPUT)); - println!("Part 2: {}", part2(INPUT)); + let input = include_str!("../../input/03"); + println!("Part 1: {}", part1(input)); + println!("Part 2: {}", part2(input)); } #[test] fn example() { - assert_example!(part1, "03-test", 357); - assert_example!(part2, "03-test", 3121910778619); + let input = include_str!("../../input/03-test"); + assert_eq!(part1(input), 357); + assert_eq!(part2(input), 3121910778619); } fn part1(input: &str) -> i64 { diff --git a/src/bin/04.rs b/src/bin/04.rs index 3f0ce5a..b083385 100644 --- a/src/bin/04.rs +++ b/src/bin/04.rs @@ -2,17 +2,17 @@ use aoc::*; use glam::IVec2; use std::collections::HashSet; -const INPUT: &str = include_str!("../../input/04"); - fn main() { - println!("Part 1: {}", part1(INPUT)); - println!("Part 2: {}", part2(INPUT)); + let input = include_str!("../../input/04"); + println!("Part 1: {}", part1(input)); + println!("Part 2: {}", part2(input)); } #[test] fn example() { - assert_example!(part1, "04-test", 13); - assert_example!(part2, "04-test", 43); + let input = include_str!("../../input/04-test"); + assert_eq!(part1(input), 13); + assert_eq!(part2(input), 43); } fn part1(input: &str) -> usize { diff --git a/src/bin/05.rs b/src/bin/05.rs index f470db1..7eb7c02 100644 --- a/src/bin/05.rs +++ b/src/bin/05.rs @@ -1,17 +1,16 @@ -use aoc::*; use itertools::Itertools; -const INPUT: &str = include_str!("../../input/05"); - fn main() { - println!("Part 1: {}", part1(INPUT)); - println!("Part 2: {}", part2(INPUT)); + let input = include_str!("../../input/05"); + println!("Part 1: {}", part1(input)); + println!("Part 2: {}", part2(input)); } #[test] fn example() { - assert_example!(part1, "05-test", 3); - assert_example!(part2, "05-test", 14); + let input = include_str!("../../input/05-test"); + assert_eq!(part1(input), 3); + assert_eq!(part2(input), 14); assert_eq!(part2("1-10\n5-6\n\n"), 10); assert_eq!(part2("1-10\n8-20\n\n"), 20); assert_eq!(part2("1-1\n2-2\n3-3\n\n"), 3); diff --git a/src/bin/06.rs b/src/bin/06.rs index e133062..22c57bc 100644 --- a/src/bin/06.rs +++ b/src/bin/06.rs @@ -3,17 +3,17 @@ use aoc::*; use itertools::Itertools; use std::str::FromStr; -const INPUT: &str = include_str!("../../input/06"); - fn main() { - println!("Part 1: {}", part1(INPUT)); - println!("Part 2: {}", part2(INPUT)); + let input = include_str!("../../input/06"); + println!("Part 1: {}", part1(input)); + println!("Part 2: {}", part2(input)); } #[test] fn example() { - assert_example!(part1, "06-test", 4277556); - assert_example!(part2, "06-test", 3263827); + let input = include_str!("../../input/06-test"); + assert_eq!(part1(input), 4277556); + assert_eq!(part2(input), 3263827); } fn part1(input: &str) -> usize { diff --git a/src/bin/07.rs b/src/bin/07.rs index 8deddc1..5d50370 100644 --- a/src/bin/07.rs +++ b/src/bin/07.rs @@ -1,18 +1,17 @@ -use aoc::*; use cached::proc_macro::cached; use std::collections::HashSet; -const INPUT: &str = include_str!("../../input/07"); - fn main() { - println!("Part 1: {}", part1(INPUT)); - println!("Part 2: {}", part2(INPUT)); + let input = include_str!("../../input/07"); + println!("Part 1: {}", part1(input)); + println!("Part 2: {}", part2(input)); } #[test] fn example() { - assert_example!(part1, "07-test", 21); - assert_example!(part2, "07-test", 40); + let input = include_str!("../../input/07-test"); + assert_eq!(part1(input), 21); + assert_eq!(part2(input), 40); } fn part1(input: &str) -> usize { @@ -52,10 +51,7 @@ fn split_count(splitters: &HashSet, beams: HashSet) -> (usize, HashSet (count, result) } -#[cached( - key = "(i32, usize)", - convert = r#"{ (beam, depth) }"# -)] +#[cached(key = "(i32, usize)", convert = r#"{ (beam, depth) }"#)] fn timelines(beam: i32, depth: usize, splitters: &[HashSet]) -> usize { if depth >= splitters.len() { return 1; diff --git a/src/bin/08.rs b/src/bin/08.rs index 14c24ad..4b45989 100644 --- a/src/bin/08.rs +++ b/src/bin/08.rs @@ -1,19 +1,18 @@ -use aoc::*; use itertools::Itertools; use std::cmp::Reverse; use std::collections::HashSet; -const INPUT: &str = include_str!("../../input/08"); - fn main() { - println!("Part 1: {}", part1(INPUT, 1000)); - println!("Part 2: {}", part2(INPUT)); + let input = include_str!("../../input/08"); + println!("Part 1: {}", part1(input, 1000)); + println!("Part 2: {}", part2(input)); } #[test] fn example() { - assert_eq!(part1(include_str!("../../input/08-test"), 10), 40); - assert_example!(part2, "08-test", 25272); + let input = include_str!("../../input/08-test"); + assert_eq!(part1(input, 10), 40); + assert_eq!(part2(input), 25272); } fn part1(input: &str, n: usize) -> usize { diff --git a/src/bin/09.rs b/src/bin/09.rs index 6c20878..ef0c0fd 100644 --- a/src/bin/09.rs +++ b/src/bin/09.rs @@ -1,19 +1,16 @@ -use aoc::*; use glam::I64Vec2; use itertools::Itertools; use rayon::prelude::*; use std::collections::HashMap; -const INPUT: &str = include_str!("../../input/09"); - fn main() { - println!("Part 1: {}", part1(INPUT)); - println!("Part 2: {}", part2(INPUT)); + let input = include_str!("../../input/09"); + println!("Part 1: {}", part1(input)); + println!("Part 2: {}", part2(input)); } #[test] fn example() { - assert_example!(part1, "09-test", 50); assert!(Line(I64Vec2::new(0, 10), I64Vec2::ZERO).contains(I64Vec2::new(0, 0))); assert!(Line(I64Vec2::new(0, 10), I64Vec2::ZERO).contains(I64Vec2::new(0, 10))); assert!(Line(I64Vec2::new(0, 10), I64Vec2::ZERO).contains(I64Vec2::new(0, 5))); @@ -22,7 +19,10 @@ fn example() { assert!(!Line(I64Vec2::ONE, I64Vec2::ONE).contains(I64Vec2::new(1, 10))); assert!(Line(I64Vec2::ONE, I64Vec2::ONE).contains(I64Vec2::new(1, 1))); assert!(!Line(I64Vec2::ONE, I64Vec2::ONE).contains(I64Vec2::ZERO)); - assert_example!(part2, "09-test", 24); + + let input = include_str!("../../input/09-test"); + assert_eq!(part1(input), 50); + assert_eq!(part2(input), 24); } fn part1(input: &str) -> u64 { diff --git a/src/bin/10.rs b/src/bin/10.rs index d73376f..cb5d441 100644 --- a/src/bin/10.rs +++ b/src/bin/10.rs @@ -1,18 +1,17 @@ -use aoc::*; use microlp::{ComparisonOp, OptimizationDirection, Problem}; use std::collections::VecDeque; -const INPUT: &str = include_str!("../../input/10"); - fn main() { - println!("Part 1: {}", part1(INPUT)); - println!("Part 2: {}", part2(INPUT)); + let input = include_str!("../../input/10"); + println!("Part 1: {}", part1(input)); + println!("Part 2: {}", part2(input)); } #[test] fn example() { - assert_example!(part1, "10-test", 7); - assert_example!(part2, "10-test", 33); + let input = include_str!("../../input/10-test"); + assert_eq!(part1(input), 7); + assert_eq!(part2(input), 33); } fn part1(input: &str) -> usize { diff --git a/src/bin/12.rs b/src/bin/12.rs new file mode 100644 index 0000000..e0974d5 --- /dev/null +++ b/src/bin/12.rs @@ -0,0 +1,82 @@ +use aoc::*; +use glam::USizeVec2; +use itertools::Itertools; + +fn main() { + let input = include_str!("../../input/12"); + println!("Part 1: {}", part1(input)); +} + +fn part1(input: &str) -> usize { + let (presents, regions) = parse_input(input); + regions.into_iter().filter(|r| r.fits(&presents)).count() +} + +fn parse_input(input: &str) -> (Vec, Vec) { + let chunks = input.split("\n\n").collect_vec(); + let (presents, regions) = chunks.split_at(chunks.len() - 1); + let presents = presents.iter().map(|p| Present::parse(p)).collect(); + let regions = regions + .iter() + .flat_map(|chunk| chunk.lines()) + .map(Region::parse) + .collect(); + (presents, regions) +} + +#[derive(Copy, Clone)] +struct Present { + area: usize, +} + +impl Present { + fn parse(input: &str) -> Self { + let area = input + .lines() + .skip(1) + .flat_map(|line| line.chars()) + .filter(|&c| c == '#') + .count(); + Self { area } + } +} + +struct Region { + size: USizeVec2, + presents: Vec, +} + +impl Region { + fn fits(&self, presents: &[Present]) -> bool { + let total_present_area: usize = self + .pick_presents(presents) + .into_iter() + .map(|(n, present)| n * present.area) + .sum(); + total_present_area <= self.area() + } + + fn pick_presents(&self, presents: &[Present]) -> Vec<(usize, Present)> { + self.presents + .iter() + .copied() + .enumerate() + .map(|(i, n)| (n, presents[i])) + .collect() + } + + fn area(&self) -> usize { + self.size.x * self.size.y + } + + fn parse(line: &str) -> Self { + let (size, presents) = line.split_once(": ").unwrap(); + + let (x, y) = size.split_once('x').unwrap(); + let size = USizeVec2::new(x.parse().unwrap(), y.parse().unwrap()); + + let presents = parse_ws_separated(presents).collect(); + + Self { size, presents } + } +} diff --git a/src/lib.rs b/src/lib.rs index a35acb7..2335521 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,21 +93,6 @@ where a / gcd * b } -/// Given a function and a name of a file in the `input` directory, -/// assert that the function applied to the contents of the file returns the expected result. -#[macro_export] -macro_rules! assert_example { - ($solve:ident, $file:expr, $expected:expr) => { - assert_eq!( - $solve(include_str!(concat!("../../input/", $file))), - $expected, - "{}, {}", - stringify!($solve), - $file, - ) - }; -} - /// 4 directions. Start pointing right and go CCW. pub const DIRECTIONS4: [IVec2; 4] = [ IVec2::new(1, 0),