diff options
| -rw-r--r-- | .idea/aoc2024.iml | 1 | ||||
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | aoc/src/lib.rs | 34 | ||||
| -rw-r--r-- | day3/Cargo.toml | 8 | ||||
| -rw-r--r-- | day3/src/main.rs | 79 |
5 files changed, 114 insertions, 10 deletions
diff --git a/.idea/aoc2024.iml b/.idea/aoc2024.iml index 784d79e..779b5d8 100644 --- a/.idea/aoc2024.iml +++ b/.idea/aoc2024.iml | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | <sourceFolder url="file://$MODULE_DIR$/day1/src" isTestSource="false" /> | 6 | <sourceFolder url="file://$MODULE_DIR$/day1/src" isTestSource="false" /> |
| 7 | <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> | 7 | <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> |
| 8 | <sourceFolder url="file://$MODULE_DIR$/day2/src" isTestSource="false" /> | 8 | <sourceFolder url="file://$MODULE_DIR$/day2/src" isTestSource="false" /> |
| 9 | <sourceFolder url="file://$MODULE_DIR$/day3/src" isTestSource="false" /> | ||
| 9 | <excludeFolder url="file://$MODULE_DIR$/aoc/target" /> | 10 | <excludeFolder url="file://$MODULE_DIR$/aoc/target" /> |
| 10 | <excludeFolder url="file://$MODULE_DIR$/target" /> | 11 | <excludeFolder url="file://$MODULE_DIR$/target" /> |
| 11 | </content> | 12 | </content> |
| @@ -1,3 +1,3 @@ | |||
| 1 | [workspace] | 1 | [workspace] |
| 2 | members = ["aoc", "day1", "day2"] | 2 | members = ["aoc", "day1", "day2", "day3"] |
| 3 | resolver = "2" | 3 | resolver = "2" |
diff --git a/aoc/src/lib.rs b/aoc/src/lib.rs index c4318e1..dcca651 100644 --- a/aoc/src/lib.rs +++ b/aoc/src/lib.rs | |||
| @@ -2,6 +2,7 @@ use clap::Parser; | |||
| 2 | use std::fs::File; | 2 | use std::fs::File; |
| 3 | use std::io; | 3 | use std::io; |
| 4 | use std::io::{BufRead, BufReader, Read}; | 4 | use std::io::{BufRead, BufReader, Read}; |
| 5 | use std::panic::catch_unwind; | ||
| 5 | use std::time::Instant; | 6 | use std::time::Instant; |
| 6 | 7 | ||
| 7 | #[derive(Parser, Debug)] | 8 | #[derive(Parser, Debug)] |
| @@ -16,6 +17,14 @@ struct Args { | |||
| 16 | 17 | ||
| 17 | pub trait Day { | 18 | pub trait Day { |
| 18 | fn example_input(&self) -> &'static str; | 19 | fn example_input(&self) -> &'static str; |
| 20 | fn example_input_part_1(&self) -> &'static str { | ||
| 21 | self.example_input() | ||
| 22 | } | ||
| 23 | |||
| 24 | fn example_input_part_2(&self) -> &'static str { | ||
| 25 | self.example_input() | ||
| 26 | } | ||
| 27 | |||
| 19 | fn example_result_part_1(&self) -> &'static str; | 28 | fn example_result_part_1(&self) -> &'static str; |
| 20 | fn example_result_part_2(&self) -> &'static str; | 29 | fn example_result_part_2(&self) -> &'static str; |
| 21 | 30 | ||
| @@ -61,19 +70,26 @@ pub fn main(day: &dyn Day) { | |||
| 61 | println!("Time to run: {}s", now.elapsed().as_secs_f64()); | 70 | println!("Time to run: {}s", now.elapsed().as_secs_f64()); |
| 62 | } | 71 | } |
| 63 | 72 | ||
| 64 | pub fn test_day<T: Day>(day: &T) { | 73 | pub fn test_day<T: Day + std::panic::RefUnwindSafe>(day: &T) { |
| 65 | use std::io::Cursor; | 74 | use std::io::Cursor; |
| 66 | use std::io::{BufReader, Read}; | 75 | use std::io::{BufReader, Read}; |
| 67 | 76 | ||
| 68 | let example_input = day.example_input(); | ||
| 69 | |||
| 70 | // Test Part 1 | 77 | // Test Part 1 |
| 71 | let input = BufReader::new(Box::new(Cursor::new(example_input)) as Box<dyn Read>); | 78 | let output = catch_unwind(|| { |
| 72 | let output = day.part_1(input); | 79 | let input = BufReader::new(Box::new(Cursor::new(day.example_input_part_1())) as Box<dyn Read>); |
| 73 | assert_eq!(output.trim(), day.example_result_part_1(), "Part 1 failed"); | 80 | day.part_1(input) |
| 81 | }); | ||
| 82 | if output.is_ok() { | ||
| 83 | assert_eq!(output.unwrap().trim(), day.example_result_part_1(), "Part 1 failed"); | ||
| 84 | } | ||
| 74 | 85 | ||
| 75 | // Test Part 2 | 86 | // Test Part 2 |
| 76 | let input = BufReader::new(Box::new(Cursor::new(example_input)) as Box<dyn Read>); | 87 | let output = catch_unwind(|| { |
| 77 | let output = day.part_2(input); | 88 | let input = BufReader::new(Box::new(Cursor::new(day.example_input_part_2())) as Box<dyn Read>); |
| 78 | assert_eq!(output.trim(), day.example_result_part_2(), "Part 2 failed"); | 89 | day.part_2(input) |
| 90 | }); | ||
| 91 | |||
| 92 | if output.is_ok() { | ||
| 93 | assert_eq!(output.unwrap().trim(), day.example_result_part_2(), "Part 2 failed"); | ||
| 94 | } | ||
| 79 | } \ No newline at end of file | 95 | } \ No newline at end of file |
diff --git a/day3/Cargo.toml b/day3/Cargo.toml new file mode 100644 index 0000000..cabf6e3 --- /dev/null +++ b/day3/Cargo.toml | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | [package] | ||
| 2 | name = "day3" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | |||
| 6 | [dependencies] | ||
| 7 | aoc = { path = "../aoc" } | ||
| 8 | regex = "1.11.1" \ No newline at end of file | ||
diff --git a/day3/src/main.rs b/day3/src/main.rs new file mode 100644 index 0000000..86ba39b --- /dev/null +++ b/day3/src/main.rs | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | |||
| 2 | use aoc; | ||
| 3 | use std::io::{BufReader, Read}; | ||
| 4 | use aoc::Day; | ||
| 5 | use regex::Regex; | ||
| 6 | |||
| 7 | struct Day3 {} | ||
| 8 | |||
| 9 | impl Day for Day3 { | ||
| 10 | fn example_input(&self) -> &'static str { | ||
| 11 | r#" | ||
| 12 | xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5)) | ||
| 13 | "#.trim() | ||
| 14 | } | ||
| 15 | |||
| 16 | fn example_input_part_2(&self) -> &'static str { | ||
| 17 | r#" | ||
| 18 | xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5)) | ||
| 19 | "#.trim() | ||
| 20 | } | ||
| 21 | |||
| 22 | fn example_result_part_1(&self) -> &'static str { | ||
| 23 | "161" | ||
| 24 | } | ||
| 25 | |||
| 26 | fn example_result_part_2(&self) -> &'static str { | ||
| 27 | "48" | ||
| 28 | } | ||
| 29 | |||
| 30 | fn part_1(&self, input: BufReader<Box<dyn Read>>) -> String { | ||
| 31 | let code = self.read_lines(input).iter().map(|l| l.trim()).collect::<Vec<&str>>().join(""); | ||
| 32 | let re = Regex::new(r"mul\((?P<a>\d+),(?P<b>\d+)\)").unwrap(); | ||
| 33 | re | ||
| 34 | .captures_iter(&code) | ||
| 35 | .map(|c| { | ||
| 36 | c.name("a").unwrap().as_str().parse::<u32>().unwrap() * c.name("b").unwrap().as_str().parse::<u32>().unwrap() | ||
| 37 | }) | ||
| 38 | .sum::<u32>() | ||
| 39 | .to_string() | ||
| 40 | } | ||
| 41 | |||
| 42 | fn part_2(&self, input: BufReader<Box<dyn Read>>) -> String { | ||
| 43 | let code = self.read_lines(input).iter().map(|l| l.trim()).collect::<Vec<&str>>().join(""); | ||
| 44 | println!("{}", code); | ||
| 45 | |||
| 46 | let mut mul = true; | ||
| 47 | let re = Regex::new(r"mul\((?P<a>\d+),(?P<b>\d+)\)|(?P<enable>do)\(\)|(?P<disable>don't)\(\)").unwrap(); | ||
| 48 | re | ||
| 49 | .captures_iter(&code) | ||
| 50 | .map(|c| { | ||
| 51 | |||
| 52 | if c.name("enable") != None { | ||
| 53 | mul = true; | ||
| 54 | } else if c.name("disable") != None { | ||
| 55 | mul = false; | ||
| 56 | } else if mul { | ||
| 57 | return c.name("a").unwrap().as_str().parse::<u32>().unwrap() * c.name("b").unwrap().as_str().parse::<u32>().unwrap(); | ||
| 58 | } | ||
| 59 | |||
| 60 | 0 | ||
| 61 | }) | ||
| 62 | .sum::<u32>() | ||
| 63 | .to_string() | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | fn main() { | ||
| 69 | aoc::main(&Day3 {}); | ||
| 70 | } | ||
| 71 | |||
| 72 | #[cfg(test)] | ||
| 73 | mod tests { | ||
| 74 | use super::*; | ||
| 75 | #[test] | ||
| 76 | fn test_day3() { | ||
| 77 | aoc::test_day(&Day3 {}); | ||
| 78 | } | ||
| 79 | } | ||
