From 1fce9d9bffbb8eebb93c1c4555be5bce6c072761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 21 Sep 2023 22:25:43 +0100 Subject: [PATCH 1/5] defined AocSolution trait + laid the groundwork for the derive macro --- 2022/day01/Cargo.toml | 2 +- 2022/day01/benches/benchmarks.rs | 2 +- 2022/day01/src/lib.rs | 92 +++++++++++++++++++--- 2022/day01/src/main.rs | 12 +-- 2022/day01/src/solution.rs | 73 ----------------- 2022/day01/src/types.rs | 2 +- 2022/day02/Cargo.toml | 2 +- 2022/day02/benches/benchmarks.rs | 2 +- 2022/day02/src/lib.rs | 65 ++++++++++++++-- 2022/day02/src/main.rs | 12 +-- 2022/day02/src/solution.rs | 48 ------------ 2022/day02/src/types.rs | 4 +- 2022/day03/Cargo.toml | 2 +- 2022/day03/benches/benchmarks.rs | 2 +- 2022/day03/src/lib.rs | 76 +++++++++++++++--- 2022/day03/src/main.rs | 12 +-- 2022/day03/src/solution.rs | 58 -------------- 2022/day03/src/types.rs | 2 +- 2022/day04/Cargo.toml | 2 +- 2022/day04/benches/benchmarks.rs | 2 +- 2022/day04/src/lib.rs | 75 +++++++++++++++--- 2022/day04/src/main.rs | 12 +-- 2022/day04/src/solution.rs | 57 -------------- 2022/day04/src/types.rs | 3 +- 2022/day05/Cargo.toml | 2 +- 2022/day05/benches/benchmarks.rs | 2 +- 2022/day05/src/lib.rs | 75 +++++++++++++++--- 2022/day05/src/main.rs | 12 +-- 2022/day05/src/solution.rs | 57 -------------- 2022/day05/src/types.rs | 3 +- 2022/day06/Cargo.toml | 1 + 2022/day06/benches/benchmarks.rs | 2 +- 2022/day06/src/lib.rs | 86 +++++++++++++++++++-- 2022/day06/src/main.rs | 10 +-- 2022/day06/src/solution.rs | 60 +------------- 2022/day07/Cargo.toml | 2 +- 2022/day07/benches/benchmarks.rs | 2 +- 2022/day07/src/lib.rs | 87 ++++++++++++++++++--- 2022/day07/src/main.rs | 12 +-- 2022/day07/src/solution.rs | 69 ----------------- 2022/day07/src/types.rs | 2 +- 2022/day08/Cargo.toml | 2 +- 2022/day08/benches/benchmarks.rs | 2 +- 2022/day08/src/lib.rs | 68 ++++++++++++++-- 2022/day08/src/main.rs | 12 +-- 2022/day08/src/solution.rs | 51 ------------ 2022/day08/src/types.rs | 2 +- 2022/day11/Cargo.toml | 2 +- 2022/day11/benches/benchmarks.rs | 2 +- 2022/day11/src/lib.rs | 95 +++++++++++++++++++++-- 2022/day11/src/main.rs | 12 +-- 2022/day11/src/solution.rs | 78 ------------------- 2022/day11/src/types.rs | 2 +- Cargo.toml | 8 +- aoc-solution-derive/Cargo.toml | 14 ++++ aoc-solution-derive/src/lib.rs | 16 ++++ aoc-solution/Cargo.toml | 9 +++ aoc-solution/src/lib.rs | 129 +++++++++++++++++++++++++++++++ common/Cargo.toml | 3 +- common/src/benchmark.rs | 2 +- common/src/execution.rs | 2 +- common/src/input_read.rs | 2 +- common/src/lib.rs | 4 +- common/src/parsing.rs | 3 +- solution-runner/Cargo.toml | 2 + solution-runner/src/main.rs | 23 +++--- 66 files changed, 916 insertions(+), 732 deletions(-) delete mode 100644 2022/day01/src/solution.rs delete mode 100644 2022/day02/src/solution.rs delete mode 100644 2022/day03/src/solution.rs delete mode 100644 2022/day04/src/solution.rs delete mode 100644 2022/day05/src/solution.rs delete mode 100644 2022/day07/src/solution.rs delete mode 100644 2022/day08/src/solution.rs delete mode 100644 2022/day11/src/solution.rs create mode 100644 aoc-solution-derive/Cargo.toml create mode 100644 aoc-solution-derive/src/lib.rs create mode 100644 aoc-solution/Cargo.toml create mode 100644 aoc-solution/src/lib.rs diff --git a/2022/day01/Cargo.toml b/2022/day01/Cargo.toml index ec8c21e..8280567 100644 --- a/2022/day01/Cargo.toml +++ b/2022/day01/Cargo.toml @@ -11,7 +11,7 @@ path = "src/lib.rs" [dependencies] common = { path = "../../common" } -anyhow = "1" +anyhow = { workspace = true } [dev-dependencies] criterion = "0.4" diff --git a/2022/day01/benches/benchmarks.rs b/2022/day01/benches/benchmarks.rs index 3ad4ffd..a0eb20d 100644 --- a/2022/day01/benches/benchmarks.rs +++ b/2022/day01/benches/benchmarks.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day01/src/lib.rs b/2022/day01/src/lib.rs index 8700791..d6e089f 100644 --- a/2022/day01/src/lib.rs +++ b/2022/day01/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,16 +12,90 @@ // See the License for the specific language governing permissions and // limitations under the License. -use common::execution::execute; -use common::parsing::parse_groups; -use std::path::Path; +#![warn(clippy::unwrap_used)] +#![warn(clippy::expect_used)] -pub use crate::solution::{part1, part2}; -pub use types::Elf; +use crate::types::Elf; +use common::parsing::parse_groups; +use common::AocSolution; -mod solution; mod types; -pub fn solve>(input_file: P) { - execute(input_file, parse_groups, part1, part2) +pub struct Day01; + +impl AocSolution for Day01 { + type Input = Vec; + type Part1Output = usize; + type Part2Output = usize; + + fn parse_input>(raw: M) -> Result { + parse_groups(raw.as_ref()) + } + + fn part1(input: Self::Input) -> Result { + Ok(part1(input)) + } + + fn part2(input: Self::Input) -> Result { + Ok(part2(input)) + } +} + +pub fn part1(input: Vec) -> usize { + input + .iter() + .map(|elf| elf.total_calorie_count()) + .max() + .unwrap_or_default() +} + +pub fn part2(input: Vec) -> usize { + // sorting the input and getting 3 last values is O(nlogn), + // meanwhile keeping track of 3 maximum values requires single O(n) iteration + let mut max = usize::MIN; + let mut max2 = usize::MIN; + let mut max3 = usize::MIN; + + for total_count in input.iter().map(|elf| elf.total_calorie_count()) { + if total_count > max { + max3 = max2; + max2 = max; + max = total_count + } else if total_count > max2 { + max3 = max2; + max2 = total_count; + } else if total_count > max3 { + max3 = total_count + } + } + + max + max2 + max3 +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use super::*; + + fn sample_input() -> Vec { + vec![ + Elf::new(vec![1000, 2000, 3000]), + Elf::new(vec![4000]), + Elf::new(vec![5000, 6000]), + Elf::new(vec![7000, 8000, 9000]), + Elf::new(vec![10000]), + ] + } + + #[test] + fn part1_sample_input() { + let expected = 24000; + assert_eq!(expected, part1(sample_input())) + } + + #[test] + fn part2_sample_input() { + let expected = 45000; + assert_eq!(expected, part2(sample_input())) + } } diff --git a/2022/day01/src/main.rs b/2022/day01/src/main.rs index 21772f4..01460e6 100644 --- a/2022/day01/src/main.rs +++ b/2022/day01/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,14 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::solution::{part1, part2}; -use common::execution::execute; -use common::parsing::parse_groups; - -mod solution; -mod types; +use common::AocSolutionSolver; +use day01_2022::Day01; #[cfg(not(tarpaulin))] fn main() { - execute("input", parse_groups, part1, part2) + Day01::try_solve_from_file("input") } diff --git a/2022/day01/src/solution.rs b/2022/day01/src/solution.rs deleted file mode 100644 index 34d453b..0000000 --- a/2022/day01/src/solution.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2022 Jedrzej Stuczynski -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::types::Elf; - -pub fn part1(input: Vec) -> usize { - input - .iter() - .map(|elf| elf.total_calorie_count()) - .max() - .unwrap_or_default() -} - -pub fn part2(input: Vec) -> usize { - // sorting the input and getting 3 last values is O(nlogn), - // meanwhile keeping track of 3 maximum values requires single O(n) iteration - let mut max = usize::MIN; - let mut max2 = usize::MIN; - let mut max3 = usize::MIN; - - for total_count in input.iter().map(|elf| elf.total_calorie_count()) { - if total_count > max { - max3 = max2; - max2 = max; - max = total_count - } else if total_count > max2 { - max3 = max2; - max2 = total_count; - } else if total_count > max3 { - max3 = total_count - } - } - - max + max2 + max3 -} - -#[cfg(test)] -mod tests { - use super::*; - - fn sample_input() -> Vec { - vec![ - Elf::new(vec![1000, 2000, 3000]), - Elf::new(vec![4000]), - Elf::new(vec![5000, 6000]), - Elf::new(vec![7000, 8000, 9000]), - Elf::new(vec![10000]), - ] - } - - #[test] - fn part1_sample_input() { - let expected = 24000; - assert_eq!(expected, part1(sample_input())) - } - - #[test] - fn part2_sample_input() { - let expected = 45000; - assert_eq!(expected, part2(sample_input())) - } -} diff --git a/2022/day01/src/types.rs b/2022/day01/src/types.rs index 6943ce8..9d769eb 100644 --- a/2022/day01/src/types.rs +++ b/2022/day01/src/types.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day02/Cargo.toml b/2022/day02/Cargo.toml index eefd498..de34588 100644 --- a/2022/day02/Cargo.toml +++ b/2022/day02/Cargo.toml @@ -11,7 +11,7 @@ path = "src/lib.rs" [dependencies] common = { path = "../../common" } -anyhow = "1" +anyhow = { workspace = true } [dev-dependencies] criterion = "0.4" diff --git a/2022/day02/benches/benchmarks.rs b/2022/day02/benches/benchmarks.rs index 2a3cb2d..fcb9145 100644 --- a/2022/day02/benches/benchmarks.rs +++ b/2022/day02/benches/benchmarks.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day02/src/lib.rs b/2022/day02/src/lib.rs index 1a3aa0b..78d9749 100644 --- a/2022/day02/src/lib.rs +++ b/2022/day02/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,16 +12,71 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![warn(clippy::unwrap_used)] +#![warn(clippy::expect_used)] + +use crate::types::RPSGame; use common::execution::execute; use common::parsing::parse_input_lines; +use common::AocSolution; use std::path::Path; -pub use crate::solution::{part1, part2}; -pub use types::RPSGame; - -mod solution; mod types; +pub struct Day02; + +impl AocSolution for Day02 { + type Input = Vec; + type Part1Output = usize; + type Part2Output = usize; + + fn parse_input>(raw: M) -> Result { + parse_input_lines(raw.as_ref()) + } + + fn part1(input: Self::Input) -> Result { + Ok(part1(input)) + } + + fn part2(input: Self::Input) -> Result { + Ok(part2(input)) + } +} + +pub fn part1(input: Vec) -> usize { + input.into_iter().map(|p| p.play_as_shape()).sum() +} + +pub fn part2(input: Vec) -> usize { + input.into_iter().map(|p| p.play_as_result()).sum() +} + pub fn solve>(input_file: P) { execute(input_file, parse_input_lines, part1, part2) } + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use super::*; + + fn sample_input() -> Vec { + vec![ + "A Y".parse().unwrap(), + "B X".parse().unwrap(), + "C Z".parse().unwrap(), + ] + } + + #[test] + fn part1_sample_input() { + let expected = 15; + assert_eq!(expected, part1(sample_input())) + } + + #[test] + fn part2_sample_input() { + let expected = 12; + assert_eq!(expected, part2(sample_input())) + } +} diff --git a/2022/day02/src/main.rs b/2022/day02/src/main.rs index b2a30c2..9431a72 100644 --- a/2022/day02/src/main.rs +++ b/2022/day02/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,14 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::solution::{part1, part2}; -use common::execution::execute; -use common::parsing::parse_input_lines; - -mod solution; -mod types; +use common::AocSolutionSolver; +use day02_2022::Day02; #[cfg(not(tarpaulin))] fn main() { - execute("input", parse_input_lines, part1, part2) + Day02::try_solve_from_file("input") } diff --git a/2022/day02/src/solution.rs b/2022/day02/src/solution.rs deleted file mode 100644 index 111ead2..0000000 --- a/2022/day02/src/solution.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2022 Jedrzej Stuczynski -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::types::RPSGame; - -pub fn part1(input: Vec) -> usize { - input.into_iter().map(|p| p.play_as_shape()).sum() -} - -pub fn part2(input: Vec) -> usize { - input.into_iter().map(|p| p.play_as_result()).sum() -} - -#[cfg(test)] -mod tests { - use super::*; - - fn sample_input() -> Vec { - vec![ - "A Y".parse().unwrap(), - "B X".parse().unwrap(), - "C Z".parse().unwrap(), - ] - } - - #[test] - fn part1_sample_input() { - let expected = 15; - assert_eq!(expected, part1(sample_input())) - } - - #[test] - fn part2_sample_input() { - let expected = 12; - assert_eq!(expected, part2(sample_input())) - } -} diff --git a/2022/day02/src/types.rs b/2022/day02/src/types.rs index fefe49b..3b002f9 100644 --- a/2022/day02/src/types.rs +++ b/2022/day02/src/types.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ impl FromStr for RoundResult { s if s == "X" => Ok(RoundResult::Loss), s if s == "Y" => Ok(RoundResult::Draw), s if s == "Z" => Ok(RoundResult::Win), - s => Err(anyhow!("{s} is not a valid round result")), + s => bail!("{s} is not a valid round result"), } } } diff --git a/2022/day03/Cargo.toml b/2022/day03/Cargo.toml index b9f28a5..436cbb3 100644 --- a/2022/day03/Cargo.toml +++ b/2022/day03/Cargo.toml @@ -11,7 +11,7 @@ path = "src/lib.rs" [dependencies] common = { path = "../../common" } -anyhow = "1" +anyhow = { workspace = true } [dev-dependencies] criterion = "0.4" diff --git a/2022/day03/benches/benchmarks.rs b/2022/day03/benches/benchmarks.rs index da0fd70..72b3a0d 100644 --- a/2022/day03/benches/benchmarks.rs +++ b/2022/day03/benches/benchmarks.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day03/src/lib.rs b/2022/day03/src/lib.rs index 2dd0383..2b65d80 100644 --- a/2022/day03/src/lib.rs +++ b/2022/day03/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,16 +12,74 @@ // See the License for the specific language governing permissions and // limitations under the License. -use common::execution::execute; -use common::parsing::parse_input_lines; -use std::path::Path; +#![warn(clippy::unwrap_used)] +#![warn(clippy::expect_used)] -pub use crate::solution::{part1, part2}; -pub use types::Rucksack; +use crate::types::Rucksack; +use common::parsing::parse_input_lines; +use common::AocSolution; -mod solution; mod types; -pub fn solve>(input_file: P) { - execute(input_file, parse_input_lines, part1, part2) +pub struct Day03; + +impl AocSolution for Day03 { + type Input = Vec; + type Part1Output = usize; + type Part2Output = usize; + + fn parse_input>(raw: M) -> Result { + parse_input_lines(raw.as_ref()) + } + + fn part1(input: Self::Input) -> Result { + Ok(part1(input)) + } + + fn part2(input: Self::Input) -> Result { + Ok(part2(input)) + } +} + +pub fn part1(input: Vec) -> usize { + input + .into_iter() + .map(|rucksack| rucksack.duplicate_item().priority()) + .sum() +} + +pub fn part2(input: Vec) -> usize { + input + .chunks(3) + .map(|group| group[0].badge(&group[1], &group[2]).priority()) + .sum() +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use super::*; + + fn sample_input() -> Vec { + vec![ + "vJrwpWtwJgWrhcsFMMfFFhFp".parse().unwrap(), + "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL".parse().unwrap(), + "PmmdzqPrVvPwwTWBwg".parse().unwrap(), + "wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn".parse().unwrap(), + "ttgJtRGJQctTZtZT".parse().unwrap(), + "CrZsJsPPZsGzwwsLwLmpwMDw".parse().unwrap(), + ] + } + + #[test] + fn part1_sample_input() { + let expected = 157; + assert_eq!(expected, part1(sample_input())) + } + + #[test] + fn part2_sample_input() { + let expected = 70; + assert_eq!(expected, part2(sample_input())) + } } diff --git a/2022/day03/src/main.rs b/2022/day03/src/main.rs index b2a30c2..c1afaa8 100644 --- a/2022/day03/src/main.rs +++ b/2022/day03/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,14 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::solution::{part1, part2}; -use common::execution::execute; -use common::parsing::parse_input_lines; - -mod solution; -mod types; +use common::AocSolutionSolver; +use day03_2022::Day03; #[cfg(not(tarpaulin))] fn main() { - execute("input", parse_input_lines, part1, part2) + Day03::try_solve_from_file("input") } diff --git a/2022/day03/src/solution.rs b/2022/day03/src/solution.rs deleted file mode 100644 index 8c7927a..0000000 --- a/2022/day03/src/solution.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2022 Jedrzej Stuczynski -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::types::Rucksack; - -pub fn part1(input: Vec) -> usize { - input - .into_iter() - .map(|rucksack| rucksack.duplicate_item().priority()) - .sum() -} - -pub fn part2(input: Vec) -> usize { - input - .chunks(3) - .into_iter() - .map(|group| group[0].badge(&group[1], &group[2]).priority()) - .sum() -} - -#[cfg(test)] -mod tests { - use super::*; - - fn sample_input() -> Vec { - vec![ - "vJrwpWtwJgWrhcsFMMfFFhFp".parse().unwrap(), - "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL".parse().unwrap(), - "PmmdzqPrVvPwwTWBwg".parse().unwrap(), - "wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn".parse().unwrap(), - "ttgJtRGJQctTZtZT".parse().unwrap(), - "CrZsJsPPZsGzwwsLwLmpwMDw".parse().unwrap(), - ] - } - - #[test] - fn part1_sample_input() { - let expected = 157; - assert_eq!(expected, part1(sample_input())) - } - - #[test] - fn part2_sample_input() { - let expected = 70; - assert_eq!(expected, part2(sample_input())) - } -} diff --git a/2022/day03/src/types.rs b/2022/day03/src/types.rs index 2b6f671..e7af0d4 100644 --- a/2022/day03/src/types.rs +++ b/2022/day03/src/types.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day04/Cargo.toml b/2022/day04/Cargo.toml index ba3de81..587f567 100644 --- a/2022/day04/Cargo.toml +++ b/2022/day04/Cargo.toml @@ -11,7 +11,7 @@ path = "src/lib.rs" [dependencies] common = { path = "../../common" } -anyhow = "1" +anyhow = { workspace = true } [dev-dependencies] criterion = "0.4" diff --git a/2022/day04/benches/benchmarks.rs b/2022/day04/benches/benchmarks.rs index 2841480..a034d5f 100644 --- a/2022/day04/benches/benchmarks.rs +++ b/2022/day04/benches/benchmarks.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day04/src/lib.rs b/2022/day04/src/lib.rs index 3e5a24e..89689cc 100644 --- a/2022/day04/src/lib.rs +++ b/2022/day04/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,16 +12,73 @@ // See the License for the specific language governing permissions and // limitations under the License. -use common::execution::execute; -use common::parsing::parse_input_lines; -use std::path::Path; +#![warn(clippy::unwrap_used)] +#![warn(clippy::expect_used)] -pub use crate::solution::{part1, part2}; -pub use crate::types::AssignmentPair; +use crate::types::AssignmentPair; +use common::parsing::parse_input_lines; +use common::AocSolution; -mod solution; mod types; -pub fn solve>(input_file: P) { - execute(input_file, parse_input_lines, part1, part2) +pub struct Day04; + +impl AocSolution for Day04 { + type Input = Vec; + type Part1Output = usize; + type Part2Output = usize; + + fn parse_input>(raw: M) -> Result { + parse_input_lines(raw.as_ref()) + } + fn part1(input: Self::Input) -> Result { + Ok(part1(input)) + } + + fn part2(input: Self::Input) -> Result { + Ok(part2(input)) + } +} + +pub fn part1(input: Vec) -> usize { + input + .into_iter() + .filter(|pair| pair.has_full_overlap()) + .count() +} + +pub fn part2(input: Vec) -> usize { + input + .into_iter() + .filter(|pair| pair.has_any_overlap()) + .count() +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use super::*; + + fn sample_input() -> Vec { + vec![ + "2-4,6-8".parse().unwrap(), + "2-3,4-5".parse().unwrap(), + "5-7,7-9".parse().unwrap(), + "2-8,3-7".parse().unwrap(), + "6-6,4-6".parse().unwrap(), + "2-6,4-8".parse().unwrap(), + ] + } + + #[test] + fn part1_sample_input() { + let expected = 2; + assert_eq!(expected, part1(sample_input())) + } + + #[test] + fn part2_sample_input() { + let expected = 4; + assert_eq!(expected, part2(sample_input())) + } } diff --git a/2022/day04/src/main.rs b/2022/day04/src/main.rs index b2a30c2..42c575d 100644 --- a/2022/day04/src/main.rs +++ b/2022/day04/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,14 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::solution::{part1, part2}; -use common::execution::execute; -use common::parsing::parse_input_lines; - -mod solution; -mod types; +use common::AocSolutionSolver; +use day04_2022::Day04; #[cfg(not(tarpaulin))] fn main() { - execute("input", parse_input_lines, part1, part2) + Day04::try_solve_from_file("input") } diff --git a/2022/day04/src/solution.rs b/2022/day04/src/solution.rs deleted file mode 100644 index a15e56e..0000000 --- a/2022/day04/src/solution.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2022 Jedrzej Stuczynski -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::types::AssignmentPair; - -pub fn part1(input: Vec) -> usize { - input - .into_iter() - .filter(|pair| pair.has_full_overlap()) - .count() -} - -pub fn part2(input: Vec) -> usize { - input - .into_iter() - .filter(|pair| pair.has_any_overlap()) - .count() -} - -#[cfg(test)] -mod tests { - use super::*; - - fn sample_input() -> Vec { - vec![ - "2-4,6-8".parse().unwrap(), - "2-3,4-5".parse().unwrap(), - "5-7,7-9".parse().unwrap(), - "2-8,3-7".parse().unwrap(), - "6-6,4-6".parse().unwrap(), - "2-6,4-8".parse().unwrap(), - ] - } - - #[test] - fn part1_sample_input() { - let expected = 2; - assert_eq!(expected, part1(sample_input())) - } - - #[test] - fn part2_sample_input() { - let expected = 4; - assert_eq!(expected, part2(sample_input())) - } -} diff --git a/2022/day04/src/types.rs b/2022/day04/src/types.rs index cb177d0..156eef8 100644 --- a/2022/day04/src/types.rs +++ b/2022/day04/src/types.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -78,6 +78,7 @@ impl AssignmentPair { } #[cfg(test)] +#[allow(clippy::unwrap_used)] mod tests { use super::*; diff --git a/2022/day05/Cargo.toml b/2022/day05/Cargo.toml index a2a85f5..b8202f9 100644 --- a/2022/day05/Cargo.toml +++ b/2022/day05/Cargo.toml @@ -11,7 +11,7 @@ path = "src/lib.rs" [dependencies] common = { path = "../../common" } -anyhow = "1" +anyhow = { workspace = true } [dev-dependencies] criterion = "0.4" diff --git a/2022/day05/benches/benchmarks.rs b/2022/day05/benches/benchmarks.rs index 7e05a2c..7c5e1ee 100644 --- a/2022/day05/benches/benchmarks.rs +++ b/2022/day05/benches/benchmarks.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day05/src/lib.rs b/2022/day05/src/lib.rs index 02a5cae..7fd690c 100644 --- a/2022/day05/src/lib.rs +++ b/2022/day05/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,16 +12,73 @@ // See the License for the specific language governing permissions and // limitations under the License. -use common::execution::execute; -use std::path::Path; -use std::str::FromStr; +#![warn(clippy::unwrap_used)] +#![warn(clippy::expect_used)] -pub use crate::solution::{part1, part2}; -pub use types::Supplies; +use crate::types::Supplies; +use common::AocSolution; -mod solution; mod types; -pub fn solve>(input_file: P) { - execute(input_file, FromStr::from_str, part1, part2) +pub struct Day05; + +impl AocSolution for Day05 { + type Input = Supplies; + type Part1Output = String; + type Part2Output = String; + + fn parse_input>(raw: M) -> Result { + raw.as_ref().parse() + } + + fn part1(input: Self::Input) -> Result { + Ok(part1(input)) + } + + fn part2(input: Self::Input) -> Result { + Ok(part2(input)) + } +} + +pub fn part1(mut input: Supplies) -> String { + input.complete_rearrangement_procedure(false); + input.top_message() +} + +pub fn part2(mut input: Supplies) -> String { + input.complete_rearrangement_procedure(true); + input.top_message() +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use super::*; + + fn sample_input() -> Supplies { + r#" [D] +[N] [C] +[Z] [M] [P] + 1 2 3 + +move 1 from 2 to 1 +move 3 from 1 to 3 +move 2 from 2 to 1 +move 1 from 1 to 2 +"# + .parse() + .unwrap() + } + + #[test] + fn part1_sample_input() { + let expected = "CMZ"; + assert_eq!(expected, part1(sample_input())) + } + + #[test] + fn part2_sample_input() { + let expected = "MCD"; + assert_eq!(expected, part2(sample_input())) + } } diff --git a/2022/day05/src/main.rs b/2022/day05/src/main.rs index 4448594..5eb27c5 100644 --- a/2022/day05/src/main.rs +++ b/2022/day05/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,14 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::solution::{part1, part2}; -use common::execution::execute; -use std::str::FromStr; - -mod solution; -mod types; +use common::AocSolutionSolver; +use day05_2022::Day05; #[cfg(not(tarpaulin))] fn main() { - execute("input", FromStr::from_str, part1, part2) + Day05::try_solve_from_file("input") } diff --git a/2022/day05/src/solution.rs b/2022/day05/src/solution.rs deleted file mode 100644 index 54b2722..0000000 --- a/2022/day05/src/solution.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2022 Jedrzej Stuczynski -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::types::Supplies; - -pub fn part1(mut input: Supplies) -> String { - input.complete_rearrangement_procedure(false); - input.top_message() -} - -pub fn part2(mut input: Supplies) -> String { - input.complete_rearrangement_procedure(true); - input.top_message() -} - -#[cfg(test)] -mod tests { - use super::*; - - fn sample_input() -> Supplies { - r#" [D] -[N] [C] -[Z] [M] [P] - 1 2 3 - -move 1 from 2 to 1 -move 3 from 1 to 3 -move 2 from 2 to 1 -move 1 from 1 to 2 -"# - .parse() - .unwrap() - } - - #[test] - fn part1_sample_input() { - let expected = "CMZ"; - assert_eq!(expected, part1(sample_input())) - } - - #[test] - fn part2_sample_input() { - let expected = "MCD"; - assert_eq!(expected, part2(sample_input())) - } -} diff --git a/2022/day05/src/types.rs b/2022/day05/src/types.rs index b88d092..ac82349 100644 --- a/2022/day05/src/types.rs +++ b/2022/day05/src/types.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -223,6 +223,7 @@ impl FromStr for Supplies { } #[cfg(test)] +#[allow(clippy::unwrap_used)] mod tests { use super::*; diff --git a/2022/day06/Cargo.toml b/2022/day06/Cargo.toml index b15b998..ca45021 100644 --- a/2022/day06/Cargo.toml +++ b/2022/day06/Cargo.toml @@ -11,6 +11,7 @@ path = "src/lib.rs" [dependencies] common = { path = "../../common" } +anyhow = { workspace = true } [dev-dependencies] criterion = "0.4" diff --git a/2022/day06/benches/benchmarks.rs b/2022/day06/benches/benchmarks.rs index f0f9727..7bcb0f2 100644 --- a/2022/day06/benches/benchmarks.rs +++ b/2022/day06/benches/benchmarks.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day06/src/lib.rs b/2022/day06/src/lib.rs index c22d54d..bdbf2b1 100644 --- a/2022/day06/src/lib.rs +++ b/2022/day06/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,14 +12,86 @@ // See the License for the specific language governing permissions and // limitations under the License. -use common::execution::execute; +#![warn(clippy::unwrap_used)] +#![warn(clippy::expect_used)] + use common::parsing::as_char_vec; -use std::path::Path; +use common::AocSolution; + +pub struct Day06; + +impl AocSolution for Day06 { + type Input = Vec; + type Part1Output = usize; + type Part2Output = usize; + + fn parse_input>(raw: M) -> Result { + as_char_vec(raw.as_ref()) + } + + fn part1(input: Self::Input) -> Result { + Ok(part1(input)) + } + + fn part2(input: Self::Input) -> Result { + Ok(part2(input)) + } +} + +// since our window size is 4 and 14 for part1 and part2 respectively, +// it's more efficient to do full slice lookup as opposed to paying for the instantiation cost of a HashSet +fn solve(input: Vec, window_size: usize) -> usize { + input + .windows(window_size) + .enumerate() + .find(|(_, slice)| !(1..slice.len()).any(|i| slice[i..].contains(&slice[i - 1]))) + .unwrap_or_else(|| panic!("no solution exists for windows size {window_size}")) + .0 + + window_size +} + +pub fn part1(input: Vec) -> usize { + solve(input, 4) +} + +pub fn part2(input: Vec) -> usize { + solve(input, 14) +} -pub use crate::solution::{part1, part2}; +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use super::*; -mod solution; + #[test] + fn part1_sample_input() { + assert_eq!(5, part1("bvwbjplbgvbhsrlpgdmjqwftvncz".chars().collect())); + assert_eq!(6, part1("nppdvjthqldpwncqszvftbrmjlhg".chars().collect())); + assert_eq!( + 10, + part1("nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg".chars().collect()) + ); + assert_eq!( + 11, + part1("zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw".chars().collect()) + ); + } -pub fn solve>(input_file: P) { - execute(input_file, as_char_vec, part1, part2) + #[test] + fn part2_sample_input() { + assert_eq!( + 19, + part2("mjqjpqmgbljsphdztnvjfqwrcgsmlb".chars().collect()) + ); + assert_eq!(23, part2("bvwbjplbgvbhsrlpgdmjqwftvncz".chars().collect())); + assert_eq!(23, part2("nppdvjthqldpwncqszvftbrmjlhg".chars().collect())); + assert_eq!( + 29, + part2("nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg".chars().collect()) + ); + assert_eq!( + 26, + part2("zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw".chars().collect()) + ); + } } diff --git a/2022/day06/src/main.rs b/2022/day06/src/main.rs index 5de2a94..b888b80 100644 --- a/2022/day06/src/main.rs +++ b/2022/day06/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,12 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::solution::{part1, part2}; -use common::execution::execute; - -mod solution; +use common::AocSolutionSolver; +use day06_2022::Day06; #[cfg(not(tarpaulin))] fn main() { - execute("input", |raw| Ok(raw.chars().collect()), part1, part2) + Day06::try_solve_from_file("input") } diff --git a/2022/day06/src/solution.rs b/2022/day06/src/solution.rs index 3e1fa74..a21384e 100644 --- a/2022/day06/src/solution.rs +++ b/2022/day06/src/solution.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,61 +11,3 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - -// since our window size is 4 and 14 for part1 and part2 respectively, -// it's more efficient to do full slice lookup as opposed to paying for the instantiation cost of a HashSet -fn solve(input: Vec, window_size: usize) -> usize { - input - .windows(window_size) - .into_iter() - .enumerate() - .find(|(_, slice)| !(1..slice.len()).any(|i| slice[i..].contains(&slice[i - 1]))) - .unwrap_or_else(|| panic!("no solution exists for windows size {window_size}")) - .0 - + window_size -} - -pub fn part1(input: Vec) -> usize { - solve(input, 4) -} - -pub fn part2(input: Vec) -> usize { - solve(input, 14) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn part1_sample_input() { - assert_eq!(5, part1("bvwbjplbgvbhsrlpgdmjqwftvncz".chars().collect())); - assert_eq!(6, part1("nppdvjthqldpwncqszvftbrmjlhg".chars().collect())); - assert_eq!( - 10, - part1("nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg".chars().collect()) - ); - assert_eq!( - 11, - part1("zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw".chars().collect()) - ); - } - - #[test] - fn part2_sample_input() { - assert_eq!( - 19, - part2("mjqjpqmgbljsphdztnvjfqwrcgsmlb".chars().collect()) - ); - assert_eq!(23, part2("bvwbjplbgvbhsrlpgdmjqwftvncz".chars().collect())); - assert_eq!(23, part2("nppdvjthqldpwncqszvftbrmjlhg".chars().collect())); - assert_eq!( - 29, - part2("nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg".chars().collect()) - ); - assert_eq!( - 26, - part2("zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw".chars().collect()) - ); - } -} diff --git a/2022/day07/Cargo.toml b/2022/day07/Cargo.toml index 08a2dda..880d543 100644 --- a/2022/day07/Cargo.toml +++ b/2022/day07/Cargo.toml @@ -11,7 +11,7 @@ path = "src/lib.rs" [dependencies] common = { path = "../../common" } -anyhow = "1" +anyhow = { workspace = true } [dev-dependencies] criterion = "0.4" diff --git a/2022/day07/benches/benchmarks.rs b/2022/day07/benches/benchmarks.rs index e4a9a7b..46e06a2 100644 --- a/2022/day07/benches/benchmarks.rs +++ b/2022/day07/benches/benchmarks.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day07/src/lib.rs b/2022/day07/src/lib.rs index c6d367b..dc8f772 100644 --- a/2022/day07/src/lib.rs +++ b/2022/day07/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,16 +12,85 @@ // See the License for the specific language governing permissions and // limitations under the License. -use common::execution::execute; -use std::path::Path; -use std::str::FromStr; +#![warn(clippy::unwrap_used)] +#![warn(clippy::expect_used)] -pub use crate::solution::{part1, part2}; -pub use types::FileSystem; +use crate::types::FileSystem; +use common::AocSolution; -mod solution; mod types; -pub fn solve>(input_file: P) { - execute(input_file, FromStr::from_str, part1, part2) +pub struct Day07; + +impl AocSolution for Day07 { + type Input = FileSystem; + type Part1Output = usize; + type Part2Output = usize; + + fn parse_input>(raw: M) -> Result { + raw.as_ref().parse() + } + + fn part1(input: Self::Input) -> Result { + Ok(part1(input)) + } + + fn part2(input: Self::Input) -> Result { + Ok(part2(input)) + } +} + +pub fn part1(input: FileSystem) -> usize { + input.sum_dirs_with_max_size(100000) +} + +pub fn part2(input: FileSystem) -> usize { + input.delete_smallest_needed_dir(70000000, 30000000) +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use super::*; + use crate::types::FileSystem; + + fn sample_input() -> FileSystem { + r#"$ cd / +$ ls +dir a +14848514 b.txt +8504156 c.dat +dir d +$ cd a +$ ls +dir e +29116 f +2557 g +62596 h.lst +$ cd e +$ ls +584 i +$ cd .. +$ cd .. +$ cd d +$ ls +4060174 j +8033020 d.log +5626152 d.ext +7214296 k"# + .parse() + .unwrap() + } + + #[test] + fn part1_sample_input() { + let expected = 95437; + assert_eq!(expected, part1(sample_input())) + } + + #[test] + fn part2_sample_input() { + let expected = 24933642; + assert_eq!(expected, part2(sample_input())) + } } diff --git a/2022/day07/src/main.rs b/2022/day07/src/main.rs index 4448594..1fcbb8b 100644 --- a/2022/day07/src/main.rs +++ b/2022/day07/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,14 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::solution::{part1, part2}; -use common::execution::execute; -use std::str::FromStr; - -mod solution; -mod types; +use common::AocSolutionSolver; +use day07_2022::Day07; #[cfg(not(tarpaulin))] fn main() { - execute("input", FromStr::from_str, part1, part2) + Day07::try_solve_from_file("input") } diff --git a/2022/day07/src/solution.rs b/2022/day07/src/solution.rs deleted file mode 100644 index d0b01e0..0000000 --- a/2022/day07/src/solution.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2022 Jedrzej Stuczynski -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::types::FileSystem; - -pub fn part1(input: FileSystem) -> usize { - input.sum_dirs_with_max_size(100000) -} - -pub fn part2(input: FileSystem) -> usize { - input.delete_smallest_needed_dir(70000000, 30000000) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::types::FileSystem; - - fn sample_input() -> FileSystem { - r#"$ cd / -$ ls -dir a -14848514 b.txt -8504156 c.dat -dir d -$ cd a -$ ls -dir e -29116 f -2557 g -62596 h.lst -$ cd e -$ ls -584 i -$ cd .. -$ cd .. -$ cd d -$ ls -4060174 j -8033020 d.log -5626152 d.ext -7214296 k"# - .parse() - .unwrap() - } - - #[test] - fn part1_sample_input() { - let expected = 95437; - assert_eq!(expected, part1(sample_input())) - } - - #[test] - fn part2_sample_input() { - let expected = 24933642; - assert_eq!(expected, part2(sample_input())) - } -} diff --git a/2022/day07/src/types.rs b/2022/day07/src/types.rs index 863d3f3..f64ecf5 100644 --- a/2022/day07/src/types.rs +++ b/2022/day07/src/types.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day08/Cargo.toml b/2022/day08/Cargo.toml index 5067595..7614106 100644 --- a/2022/day08/Cargo.toml +++ b/2022/day08/Cargo.toml @@ -11,7 +11,7 @@ path = "src/lib.rs" [dependencies] common = { path = "../../common" } -anyhow = "1" +anyhow = { workspace = true } [dev-dependencies] criterion = "0.4" diff --git a/2022/day08/benches/benchmarks.rs b/2022/day08/benches/benchmarks.rs index 313a22f..228b863 100644 --- a/2022/day08/benches/benchmarks.rs +++ b/2022/day08/benches/benchmarks.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day08/src/lib.rs b/2022/day08/src/lib.rs index e38f425..8347814 100644 --- a/2022/day08/src/lib.rs +++ b/2022/day08/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,16 +12,74 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![warn(clippy::unwrap_used)] +#![warn(clippy::expect_used)] + +use crate::types::Forest; use common::execution::execute; +use common::AocSolution; use std::path::Path; use std::str::FromStr; -pub use crate::solution::{part1, part2}; -pub use crate::types::Forest; - -mod solution; mod types; +pub struct Day08; + +impl AocSolution for Day08 { + type Input = Forest; + type Part1Output = usize; + type Part2Output = usize; + + fn parse_input>(raw: M) -> Result { + raw.as_ref().parse() + } + + fn part1(input: Self::Input) -> Result { + Ok(part1(input)) + } + + fn part2(input: Self::Input) -> Result { + Ok(part2(input)) + } +} + pub fn solve>(input_file: P) { execute(input_file, FromStr::from_str, part1, part2) } + +pub fn part1(input: Forest) -> usize { + input.count_visible_trees() +} + +pub fn part2(input: Forest) -> usize { + input.highest_scenic_score() +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use super::*; + use crate::types::Forest; + + fn sample_input() -> Forest { + r#"30373 +25512 +65332 +33549 +35390"# + .parse() + .unwrap() + } + + #[test] + fn part1_sample_input() { + let expected = 21; + assert_eq!(expected, part1(sample_input())) + } + + #[test] + fn part2_sample_input() { + let expected = 8; + assert_eq!(expected, part2(sample_input())) + } +} diff --git a/2022/day08/src/main.rs b/2022/day08/src/main.rs index 4448594..40c2555 100644 --- a/2022/day08/src/main.rs +++ b/2022/day08/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,14 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::solution::{part1, part2}; -use common::execution::execute; -use std::str::FromStr; - -mod solution; -mod types; +use common::AocSolutionSolver; +use day08_2022::Day08; #[cfg(not(tarpaulin))] fn main() { - execute("input", FromStr::from_str, part1, part2) + Day08::try_solve_from_file("input") } diff --git a/2022/day08/src/solution.rs b/2022/day08/src/solution.rs deleted file mode 100644 index e812fef..0000000 --- a/2022/day08/src/solution.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2022 Jedrzej Stuczynski -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::types::Forest; - -pub fn part1(input: Forest) -> usize { - input.count_visible_trees() -} - -pub fn part2(input: Forest) -> usize { - input.highest_scenic_score() -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::types::Forest; - - fn sample_input() -> Forest { - r#"30373 -25512 -65332 -33549 -35390"# - .parse() - .unwrap() - } - - #[test] - fn part1_sample_input() { - let expected = 21; - assert_eq!(expected, part1(sample_input())) - } - - #[test] - fn part2_sample_input() { - let expected = 8; - assert_eq!(expected, part2(sample_input())) - } -} diff --git a/2022/day08/src/types.rs b/2022/day08/src/types.rs index 5bcbe61..b66ad19 100644 --- a/2022/day08/src/types.rs +++ b/2022/day08/src/types.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day11/Cargo.toml b/2022/day11/Cargo.toml index ee6220a..944cfb6 100644 --- a/2022/day11/Cargo.toml +++ b/2022/day11/Cargo.toml @@ -11,7 +11,7 @@ path = "src/lib.rs" [dependencies] common = { path = "../../common" } -anyhow = "1" +anyhow = { workspace = true } num = "0.4.0" [dev-dependencies] diff --git a/2022/day11/benches/benchmarks.rs b/2022/day11/benches/benchmarks.rs index 69f8e96..82ff840 100644 --- a/2022/day11/benches/benchmarks.rs +++ b/2022/day11/benches/benchmarks.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/2022/day11/src/lib.rs b/2022/day11/src/lib.rs index e4dc65e..5307f7e 100644 --- a/2022/day11/src/lib.rs +++ b/2022/day11/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,16 +12,101 @@ // See the License for the specific language governing permissions and // limitations under the License. +#![warn(clippy::unwrap_used)] +#![warn(clippy::expect_used)] + +use crate::types::{Monkey, State, WorryDecrease}; use common::execution::execute; use common::parsing::parse_groups; +use common::AocSolution; +use num::integer::lcm; use std::path::Path; -pub use crate::solution::{part1, part2}; -pub use crate::types::Monkey; - -mod solution; mod types; +pub struct Day11; + +impl AocSolution for Day11 { + type Input = Vec; + type Part1Output = usize; + type Part2Output = usize; + + fn parse_input>(raw: M) -> Result { + parse_groups(raw.as_ref()) + } + + fn part1(input: Self::Input) -> Result { + Ok(part1(input)) + } + + fn part2(input: Self::Input) -> Result { + Ok(part2(input)) + } +} + pub fn solve>(input_file: P) { execute(input_file, parse_groups, part1, part2) } + +pub fn part1(input: Vec) -> usize { + let mut state = State::new(input, WorryDecrease::DivByThree); + state.inspection_rounds(20) +} + +pub fn part2(input: Vec) -> usize { + let lcm = input.iter().map(|m| m.test_value()).fold(1, lcm); + let mut state = State::new(input, WorryDecrease::GlobalLCM(lcm)); + state.inspection_rounds(10000) +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use super::*; + use crate::types::Monkey; + use common::parsing::parse_groups; + + fn sample_input() -> Vec { + let raw = r#"Monkey 0: + Starting items: 79, 98 + Operation: new = old * 19 + Test: divisible by 23 + If true: throw to monkey 2 + If false: throw to monkey 3 + + Monkey 1: + Starting items: 54, 65, 75, 74 + Operation: new = old + 6 + Test: divisible by 19 + If true: throw to monkey 2 + If false: throw to monkey 0 + + Monkey 2: + Starting items: 79, 60, 97 + Operation: new = old * old + Test: divisible by 13 + If true: throw to monkey 1 + If false: throw to monkey 3 + + Monkey 3: + Starting items: 74 + Operation: new = old + 3 + Test: divisible by 17 + If true: throw to monkey 0 + If false: throw to monkey 1 +"#; + parse_groups(raw).unwrap() + } + + #[test] + fn part1_sample_input() { + let expected = 10605; + assert_eq!(expected, part1(sample_input())) + } + + #[test] + fn part2_sample_input() { + let expected = 2713310158; + assert_eq!(expected, part2(sample_input())) + } +} diff --git a/2022/day11/src/main.rs b/2022/day11/src/main.rs index 21772f4..91ce9e1 100644 --- a/2022/day11/src/main.rs +++ b/2022/day11/src/main.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,14 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::solution::{part1, part2}; -use common::execution::execute; -use common::parsing::parse_groups; - -mod solution; -mod types; +use common::AocSolutionSolver; +use day11_2022::Day11; #[cfg(not(tarpaulin))] fn main() { - execute("input", parse_groups, part1, part2) + Day11::try_solve_from_file("input") } diff --git a/2022/day11/src/solution.rs b/2022/day11/src/solution.rs deleted file mode 100644 index 3a2bc9d..0000000 --- a/2022/day11/src/solution.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2022 Jedrzej Stuczynski -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::types::{Monkey, State, WorryDecrease}; -use num::integer::lcm; - -pub fn part1(input: Vec) -> usize { - let mut state = State::new(input, WorryDecrease::DivByThree); - state.inspection_rounds(20) -} - -pub fn part2(input: Vec) -> usize { - let lcm = input.iter().map(|m| m.test_value()).fold(1, lcm); - let mut state = State::new(input, WorryDecrease::GlobalLCM(lcm)); - state.inspection_rounds(10000) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::types::Monkey; - use common::parsing::parse_groups; - - fn sample_input() -> Vec { - let raw = r#"Monkey 0: - Starting items: 79, 98 - Operation: new = old * 19 - Test: divisible by 23 - If true: throw to monkey 2 - If false: throw to monkey 3 - - Monkey 1: - Starting items: 54, 65, 75, 74 - Operation: new = old + 6 - Test: divisible by 19 - If true: throw to monkey 2 - If false: throw to monkey 0 - - Monkey 2: - Starting items: 79, 60, 97 - Operation: new = old * old - Test: divisible by 13 - If true: throw to monkey 1 - If false: throw to monkey 3 - - Monkey 3: - Starting items: 74 - Operation: new = old + 3 - Test: divisible by 17 - If true: throw to monkey 0 - If false: throw to monkey 1 -"#; - parse_groups(raw).unwrap() - } - - #[test] - fn part1_sample_input() { - let expected = 10605; - assert_eq!(expected, part1(sample_input())) - } - - #[test] - fn part2_sample_input() { - let expected = 2713310158; - assert_eq!(expected, part2(sample_input())) - } -} diff --git a/2022/day11/src/types.rs b/2022/day11/src/types.rs index 63345f0..98c2d9a 100644 --- a/2022/day11/src/types.rs +++ b/2022/day11/src/types.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/Cargo.toml b/Cargo.toml index e479140..c4e04ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,9 @@ [workspace] +resolver = "2" members = [ + "aoc-solution", + "aoc-solution-derive", "solution-runner", "2022/day01", "2022/day02", @@ -12,4 +15,7 @@ members = [ "2022/day08", "2022/day11", "common" -] \ No newline at end of file +] + +[workspace.dependencies] +anyhow = "1.0.75" \ No newline at end of file diff --git a/aoc-solution-derive/Cargo.toml b/aoc-solution-derive/Cargo.toml new file mode 100644 index 0000000..ff25e27 --- /dev/null +++ b/aoc-solution-derive/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "aoc-derive" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +proc-macro = true + +[dependencies] +common = { path = "../common" } +syn = "2.0" +quote = "1.0" diff --git a/aoc-solution-derive/src/lib.rs b/aoc-solution-derive/src/lib.rs new file mode 100644 index 0000000..4225688 --- /dev/null +++ b/aoc-solution-derive/src/lib.rs @@ -0,0 +1,16 @@ +use proc_macro::TokenStream; +// use quote::quote; +// use syn; + +// TODO: +// allow something like: +// #[derive(Aoc)] +// #[aoc(parser = xxx)] -> infer Input type from parser +// #[aoc(part1 = xxx)] -> if not defined, return Result<(), Error>; +// #[aoc(part2 = xxx)] -> ibid +// struct DayXX; + +#[proc_macro_derive(Aoc, attributes(aoc))] +pub fn derive_aoc_solution(input: TokenStream) -> TokenStream { + input +} diff --git a/aoc-solution/Cargo.toml b/aoc-solution/Cargo.toml new file mode 100644 index 0000000..3224f14 --- /dev/null +++ b/aoc-solution/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "aoc-solution" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = { workspace = true } \ No newline at end of file diff --git a/aoc-solution/src/lib.rs b/aoc-solution/src/lib.rs new file mode 100644 index 0000000..67a835f --- /dev/null +++ b/aoc-solution/src/lib.rs @@ -0,0 +1,129 @@ +// Copyright 2023 Jedrzej Stuczynski +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use anyhow::bail; +use std::any::type_name; +use std::fmt::{Display, Formatter}; +use std::path::Path; +use std::time::{Duration, Instant}; + +pub trait AocSolution { + type Input: Clone; + type Part1Output: Display; + type Part2Output: Display; + + fn parse_input>(_raw: M) -> Result { + bail!("unimplemented") + } + + fn part1(_input: Self::Input) -> Result { + bail!("unimplemented") + } + + fn part2(_input: Self::Input) -> Result { + bail!("unimplemented") + } +} + +pub trait AocSolutionSolver: AocSolution { + fn try_solve>(raw_input: M) { + match run::(raw_input) { + Ok(result) => println!("{result}"), + Err(err) => eprintln!("failed to solve aoc for '{}': {err}", type_name::()), + } + } + + fn try_solve_from_file

(path: P) + where + P: AsRef, + { + match run_from_file::(path) { + Ok(result) => println!("{result}"), + Err(err) => eprintln!("failed to solve aoc for '{}': {err}", type_name::()), + } + } +} + +impl AocSolutionSolver for T where T: AocSolution {} + +pub struct DayResult { + parsing: Duration, + part1: TimedResult, + part2: TimedResult, +} + +impl Display for DayResult { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + writeln!(f, "# TIMING #")?; + writeln!(f, "PARSING:\t{:?}", self.parsing)?; + writeln!(f, "PART 1:\t\t{:?}", self.part1.taken)?; + writeln!(f, "PART 2:\t\t{:?}", self.part2.taken)?; + writeln!(f)?; + writeln!(f, "# RESULTS #")?; + writeln!(f, "PART 1:\t\t{}", self.part1.value)?; + writeln!(f, "PART 2:\t\t{}", self.part2.value) + } +} + +struct TimedResult { + taken: Duration, + value: T, +} + +impl TimedResult> { + pub fn transpose(self) -> Result, E> { + match self.value { + Ok(x) => Ok(TimedResult { + taken: self.taken, + value: x, + }), + Err(err) => Err(err), + } + } +} + +fn timed U>(f: F, input: T) -> TimedResult { + let start = Instant::now(); + let output = f(input); + let taken = start.elapsed(); + TimedResult { + taken, + value: output, + } +} + +pub fn run_from_file(path: P) -> Result, anyhow::Error> +where + P: AsRef, + T: AocSolution + ?Sized, +{ + run(std::fs::read_to_string(path)?) +} + +pub fn run(input: M) -> Result, anyhow::Error> +where + T: AocSolution + ?Sized, + M: AsRef, +{ + let parsed_input = timed(T::parse_input, input).transpose()?; + + let part1 = timed(T::part1, parsed_input.value.clone()).transpose()?; + let part2 = timed(T::part2, parsed_input.value).transpose()?; + + Ok(DayResult { + parsing: parsed_input.taken, + part1, + part2, + }) +} diff --git a/common/Cargo.toml b/common/Cargo.toml index 56f6f29..1af988d 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1" +anyhow = { workspace = true } +aoc-solution = { path = "../aoc-solution" } diff --git a/common/src/benchmark.rs b/common/src/benchmark.rs index 9385473..f12fe31 100644 --- a/common/src/benchmark.rs +++ b/common/src/benchmark.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/common/src/execution.rs b/common/src/execution.rs index 46246ee..060e54c 100644 --- a/common/src/execution.rs +++ b/common/src/execution.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/common/src/input_read.rs b/common/src/input_read.rs index 735732e..75dccd9 100644 --- a/common/src/input_read.rs +++ b/common/src/input_read.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/common/src/lib.rs b/common/src/lib.rs index b173e33..180e053 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,3 +16,5 @@ pub mod benchmark; pub mod execution; pub mod input_read; pub mod parsing; + +pub use aoc_solution::{AocSolution, AocSolutionSolver}; diff --git a/common/src/parsing.rs b/common/src/parsing.rs index 089f0d9..b060ff8 100644 --- a/common/src/parsing.rs +++ b/common/src/parsing.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Jedrzej Stuczynski +// Copyright 2022-2023 Jedrzej Stuczynski // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -53,7 +53,6 @@ where ::Err: Debug, { raw.lines() - .into_iter() .map(|line| line.parse::()) .collect::, _>>() .map_err(|err| { diff --git a/solution-runner/Cargo.toml b/solution-runner/Cargo.toml index aa45dce..095ed7a 100644 --- a/solution-runner/Cargo.toml +++ b/solution-runner/Cargo.toml @@ -8,6 +8,8 @@ edition = "2021" [dependencies] clap = { version = "4.0.29", features = ["derive"] } +common = { path = "../common" } + day01_2022 = { path = "../2022/day01" } day02_2022 = { path = "../2022/day02" } day03_2022 = { path = "../2022/day03" } diff --git a/solution-runner/src/main.rs b/solution-runner/src/main.rs index 07b7663..81a88f8 100644 --- a/solution-runner/src/main.rs +++ b/solution-runner/src/main.rs @@ -13,6 +13,7 @@ // limitations under the License. use clap::Parser; +use common::AocSolutionSolver; /// Simple solution runner for Advent of Code puzzles. #[derive(Parser, Debug)] @@ -35,9 +36,9 @@ struct Args { } macro_rules! define_solution { - ($args: ident, $year: literal, $day: literal, $input: literal, $solver: expr) => { + ($args: ident, $year: literal, $day: literal, $input: literal, $solver: ty) => { if $args.year == $year && $args.day == $day { - return $solver($input); + return <$solver as AocSolutionSolver>::try_solve_from_file($input); } }; } @@ -45,15 +46,15 @@ macro_rules! define_solution { fn main() { let args = Args::parse(); - define_solution!(args, 2022, 1, "2022/day01/input", day01_2022::solve); - define_solution!(args, 2022, 2, "2022/day02/input", day02_2022::solve); - define_solution!(args, 2022, 3, "2022/day03/input", day03_2022::solve); - define_solution!(args, 2022, 4, "2022/day04/input", day04_2022::solve); - define_solution!(args, 2022, 5, "2022/day05/input", day05_2022::solve); - define_solution!(args, 2022, 6, "2022/day06/input", day06_2022::solve); - define_solution!(args, 2022, 7, "2022/day07/input", day07_2022::solve); - define_solution!(args, 2022, 8, "2022/day08/input", day08_2022::solve); - define_solution!(args, 2022, 11, "2022/day11/input", day11_2022::solve); + define_solution!(args, 2022, 1, "2022/day01/input", day01_2022::Day01); + define_solution!(args, 2022, 2, "2022/day02/input", day02_2022::Day02); + define_solution!(args, 2022, 3, "2022/day03/input", day03_2022::Day03); + define_solution!(args, 2022, 4, "2022/day04/input", day04_2022::Day04); + define_solution!(args, 2022, 5, "2022/day05/input", day05_2022::Day05); + define_solution!(args, 2022, 6, "2022/day06/input", day06_2022::Day06); + define_solution!(args, 2022, 7, "2022/day07/input", day07_2022::Day07); + define_solution!(args, 2022, 8, "2022/day08/input", day08_2022::Day08); + define_solution!(args, 2022, 11, "2022/day11/input", day11_2022::Day11); println!("no solution found for year {}, day {}", args.year, args.day); } From 079236daaa09a043e1f79e6c420fc766badd09b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 21 Sep 2023 22:27:35 +0100 Subject: [PATCH 2/5] fixed build status badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e05c39e..da4a7f7 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Keeping track of solutions to various puzzles from https://adventofcode.com/ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge&logo=appveyo)](https://opensource.org/licenses/Apache-2.0) -[![Build Status](https://img.shields.io/github/workflow/status/jstuczyn/AdventOfCode/Continuous%20integration?style=for-the-badge)](https://github.com/jstuczyn/AdventOfCode/actions?query=branch%3Amaster) +[![Build Status](https://img.shields.io/github/actions/workflow/status/jstuczyn/AdventOfCode/build.yml?style=for-the-badge)](https://github.com/jstuczyn/AdventOfCode/actions?query=branch%3Amaster) [![Coverage](https://img.shields.io/codecov/c/github/jstuczyn/AdventOfCode2021?token=MB5EB16E2Y&style=for-the-badge&logo=codecov?token=EEAVX8J62K)](https://codecov.io/gh/jstuczyn/AdventOfCode2021) ## About From 012579e02762a1ab385d094eed9777fe84a3e3dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 21 Sep 2023 22:34:23 +0100 Subject: [PATCH 3/5] clippy --- 2022/day02/src/types.rs | 6 +++--- 2022/day03/src/types.rs | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/2022/day02/src/types.rs b/2022/day02/src/types.rs index 3b002f9..f0a711b 100644 --- a/2022/day02/src/types.rs +++ b/2022/day02/src/types.rs @@ -27,9 +27,9 @@ impl FromStr for RoundResult { fn from_str(s: &str) -> Result { match s { - s if s == "X" => Ok(RoundResult::Loss), - s if s == "Y" => Ok(RoundResult::Draw), - s if s == "Z" => Ok(RoundResult::Win), + "X" => Ok(RoundResult::Loss), + "Y" => Ok(RoundResult::Draw), + "Z" => Ok(RoundResult::Win), s => bail!("{s} is not a valid round result"), } } diff --git a/2022/day03/src/types.rs b/2022/day03/src/types.rs index e7af0d4..114bc48 100644 --- a/2022/day03/src/types.rs +++ b/2022/day03/src/types.rs @@ -72,7 +72,6 @@ impl FromStr for Rucksack { fn from_str(s: &str) -> Result { let items = s .chars() - .into_iter() .map(Item::try_from) .collect::, _>>()?; if items.len() % 2 != 0 { From bcf52551115b12b6254afa1ea0899d0bc6bb0489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 21 Sep 2023 22:49:22 +0100 Subject: [PATCH 4/5] fixed output format argument for cargo tarpaulin --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index f2ea256..3ca488b 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -22,7 +22,7 @@ jobs: - name: Generate code coverage run: | - cargo tarpaulin --verbose --all-features --workspace --timeout 120 --out Xml + cargo tarpaulin --verbose --all-features --workspace --timeout 120 --out xml - name: Upload to codecov.io uses: codecov/codecov-action@v2 From c7643a0839af194a1f4e9a0d2bb5090fed19660b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Fri, 22 Sep 2023 21:16:16 +0100 Subject: [PATCH 5/5] disable CI failure on coverage decrease --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 3ca488b..6997254 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -28,4 +28,4 @@ jobs: uses: codecov/codecov-action@v2 with: token: ${{secrets.CODECOV_TOKEN}} - fail_ci_if_error: true +# fail_ci_if_error: true