From e18bd67711510dbdf9254f1811aa76d1cca3abbc Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Wed, 7 Dec 2022 18:41:51 -0600 Subject: feat!: impl Problem and Solution traits for all days --- src/day_1.rs | 49 ++++++++++++++++++-------------- src/day_2.rs | 80 ++++++++++++++++++++++++++-------------------------- src/day_3.rs | 91 ++++++++++++++++++++++++++++++------------------------------ src/day_4.rs | 36 ++++++++++++++---------- src/day_5.rs | 45 +++++++++++++++++------------- src/day_6.rs | 33 ++++++++++++---------- src/day_7.rs | 14 ++++++---- src/lib.rs | 18 ++++++------ src/main.rs | 17 +++++++----- 9 files changed, 207 insertions(+), 176 deletions(-) diff --git a/src/day_1.rs b/src/day_1.rs index b786999..8fcc6ce 100644 --- a/src/day_1.rs +++ b/src/day_1.rs @@ -1,29 +1,36 @@ -use anyhow::Result; +use anyhow::{Context, Result}; -pub fn solve() -> Result<()> { - let input = include_str!("../input/day_1.txt"); - println!("day 1"); - println!("part 1: {}", part_1(input)); - println!("part 2: {}", part_2(input)); +use crate::{Problem, Solution}; - Ok(()) -} +pub struct Day1; + +impl Problem for Day1 { + const DAY: u8 = 1; -pub fn part_1(input: &str) -> usize { - input - .split("\n\n") - .map(|e| e.split('\n').flat_map(|l| l.parse::()).sum()) - .max() - .unwrap() + const INPUT: &'static str = include_str!("../input/day_1.txt"); } -pub fn part_2(input: &str) -> usize { - let mut vec = input - .split("\n\n") - .map(|e| e.split('\n').flat_map(|l| l.parse::()).sum()) - .collect::>(); +impl Solution for Day1 { + type Answer1 = usize; + + type Answer2 = usize; + + fn part_1(input: &str) -> Result { + input + .split("\n\n") + .map(|e| e.split('\n').flat_map(|l| l.parse::()).sum()) + .max() + .context("Failed to find max") + } + + fn part_2(input: &str) -> Result { + let mut vec = input + .split("\n\n") + .map(|e| e.split('\n').flat_map(|l| l.parse::()).sum()) + .collect::>(); - vec.sort_unstable(); + vec.sort_unstable(); - vec.iter().rev().take(3).sum() + Ok(vec.iter().rev().take(3).sum()) + } } diff --git a/src/day_2.rs b/src/day_2.rs index 3222289..f9e207b 100644 --- a/src/day_2.rs +++ b/src/day_2.rs @@ -2,6 +2,8 @@ use std::str::FromStr; use anyhow::{anyhow, Result}; +use crate::{Problem, Solution}; + #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct Game { shapes: (Shape, Shape), @@ -104,65 +106,65 @@ impl FromStr for Shape { } } -pub fn solve() -> Result<()> { - let input = include_str!("../input/day_2.txt"); +pub struct Day2; - println!("day 2"); - println!("part 1: {}", part_1(input)?); - println!("part 2: {}", part_2(input)?); +impl Problem for Day2 { + const DAY: u8 = 3; - Ok(()) + const INPUT: &'static str = include_str!("../input/day_2.txt"); } -pub fn part_1(input: &str) -> Result { - input.lines().try_fold(0, |acc, l| { - let (a, b) = l - .split_once(' ') - .ok_or_else(|| anyhow!("Missing deliminator"))?; +impl Solution for Day2 { + type Answer1 = usize; - let a: Shape = a.parse()?; - let b: Shape = b.parse()?; - let game: Game = (a, b).into(); + type Answer2 = usize; - Ok(acc + game.score) - }) -} + fn part_1(input: &str) -> Result { + input.lines().try_fold(0, |acc, l| { + let (a, b) = l + .split_once(' ') + .ok_or_else(|| anyhow!("Missing deliminator"))?; + + let a: Shape = a.parse()?; + let b: Shape = b.parse()?; + let game: Game = (a, b).into(); + + Ok(acc + game.score) + }) + } -pub fn part_2(input: &str) -> Result { - input.lines().try_fold(0, |acc, l| { - let (a, outcome) = l - .split_once(' ') - .ok_or_else(|| anyhow!("Missing deliminator"))?; + fn part_2(input: &str) -> Result { + input.lines().try_fold(0, |acc, l| { + let (a, outcome) = l + .split_once(' ') + .ok_or_else(|| anyhow!("Missing deliminator"))?; - let a: Shape = a.parse()?; - let outcome: Outcome = outcome.parse()?; - let game: Game = (a, outcome).into(); + let a: Shape = a.parse()?; + let outcome: Outcome = outcome.parse()?; + let game: Game = (a, outcome).into(); - Ok(acc + game.score) - }) + Ok(acc + game.score) + }) + } } #[cfg(test)] mod tests { use super::*; + const INPUT: &str = indoc::indoc! {" + A Y + B X + C Z + "}; + #[test] fn test_part_1_example() -> Result<()> { - let input = "A Y -B X -C Z"; - - assert_eq!(15, part_1(input)?); - Ok(()) + Ok(assert_eq!(15, Day2::part_1(INPUT)?)) } #[test] fn test_part_2_example() -> Result<()> { - let input = "A Y -B X -C Z"; - - assert_eq!(12, part_2(input)?); - Ok(()) + Ok(assert_eq!(12, Day2::part_2(INPUT)?)) } } diff --git a/src/day_3.rs b/src/day_3.rs index a49839a..a549e52 100644 --- a/src/day_3.rs +++ b/src/day_3.rs @@ -2,15 +2,7 @@ use std::{ops::Deref, str::FromStr}; use anyhow::{anyhow, Context, Result}; -pub fn solve() -> Result<()> { - let input = include_str!("../input/day_3.txt"); - - println!("day 3"); - println!("part 1: {}", part_1(input)?); - println!("part 2: {}", part_2(input)?); - - Ok(()) -} +use crate::{Problem, Solution}; trait Priority { fn priority(self) -> Result; @@ -66,58 +58,65 @@ impl std::str::FromStr for Backpack { } } -pub fn part_1(input: &str) -> Result { - input - .lines() - .map(Backpack::from_str) - .try_collect::>()? - .into_iter() - .map(|b| b.get_local_union()) - .try_collect::>()? - .into_iter() - .try_fold(0, |sum, c| c.priority().map(|p| sum + p as usize)) +pub struct Day3; + +impl Problem for Day3 { + const DAY: u8 = 3; + + const INPUT: &'static str = include_str!("../input/day_3.txt"); } -pub fn part_2(input: &str) -> Result { - let lines: Vec<&str> = input.lines().collect(); - lines.as_slice().chunks(3).try_fold(0, |acc, g| { - let mut group = g - .iter() - .cloned() +impl Solution for Day3 { + type Answer1 = usize; + + type Answer2 = usize; + + fn part_1(input: &str) -> Result { + input + .lines() .map(Backpack::from_str) - .try_collect::>()?; + .try_collect::>()? + .into_iter() + .map(|b| b.get_local_union()) + .try_collect::>()? + .into_iter() + .try_fold(0, |sum, c| c.priority().map(|p| sum + p as usize)) + } - Ok(Backpack::get_group_union(&mut group)?.priority()? as usize + acc) - }) + fn part_2(input: &str) -> Result { + let lines: Vec<&str> = input.lines().collect(); + lines.as_slice().chunks(3).try_fold(0, |acc, g| { + let mut group = g + .iter() + .cloned() + .map(Backpack::from_str) + .try_collect::>()?; + + Ok(Backpack::get_group_union(&mut group)?.priority()? as usize + acc) + }) + } } #[cfg(test)] mod tests { use super::*; + const INPUT: &str = indoc::indoc! {r#" + vJrwpWtwJgWrhcsFMMfFFhFp + jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL + PmmdzqPrVvPwwTWBwg + wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn + ttgJtRGJQctTZtZT + CrZsJsPPZsGzwwsLwLmpwMDw + "#}; + #[test] fn test_part_1_example() -> Result<()> { - let test_input = r#"vJrwpWtwJgWrhcsFMMfFFhFp -jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL -PmmdzqPrVvPwwTWBwg -wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn -ttgJtRGJQctTZtZT -CrZsJsPPZsGzwwsLwLmpwMDw"#; - - assert_eq!(157, part_1(test_input)?); - Ok(()) + Ok(assert_eq!(157, Day3::part_1(INPUT)?)) } #[test] fn test_part_2_example() -> Result<()> { - let test_input = r#"vJrwpWtwJgWrhcsFMMfFFhFp -jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL -PmmdzqPrVvPwwTWBwg -wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn -ttgJtRGJQctTZtZT -CrZsJsPPZsGzwwsLwLmpwMDw"#; - - assert_eq!(70, part_2(test_input)?); - Ok(()) + Ok(assert_eq!(70, Day3::part_2(INPUT)?)) } } diff --git a/src/day_4.rs b/src/day_4.rs index c7ec637..690ccd1 100644 --- a/src/day_4.rs +++ b/src/day_4.rs @@ -2,6 +2,8 @@ use std::ops::Range; use anyhow::Result; +use crate::{Problem, Solution}; + pub fn parse_range(section: &str) -> Result> { let (start, end) = section.split_once('-').unwrap(); let start = start.parse::()?; @@ -23,24 +25,28 @@ fn range_is_union((a, b): &(Range, Range)) -> bool { (a.start <= b.start && a.end >= b.start) || (b.start <= a.start && b.end >= a.start) } -pub fn solve() -> Result<()> { - let input = include_str!("../input/day_4.txt"); +pub struct Day4; - println!("day 4"); - println!("part 1: {}", part_1(input)?); - println!("part 2: {}", part_2(input)?); +impl Problem for Day4 { + const DAY: u8 = 4; - Ok(()) + const INPUT: &'static str = include_str!("../input/day_4.txt"); } -pub fn part_1(input: &str) -> Result { - let ranges: Vec<_> = input.lines().map(parse_pair).collect::>()?; - Ok(ranges.into_iter().filter(range_is_subset).count()) -} +impl Solution for Day4 { + type Answer1 = usize; + + type Answer2 = usize; -pub fn part_2(input: &str) -> Result { - let ranges: Vec<_> = input.lines().map(parse_pair).collect::>()?; - Ok(ranges.into_iter().filter(range_is_union).count()) + fn part_1(input: &str) -> Result { + let ranges: Vec<_> = input.lines().map(parse_pair).collect::>()?; + Ok(ranges.into_iter().filter(range_is_subset).count()) + } + + fn part_2(input: &str) -> Result { + let ranges: Vec<_> = input.lines().map(parse_pair).collect::>()?; + Ok(ranges.into_iter().filter(range_is_union).count()) + } } #[cfg(test)] @@ -56,13 +62,13 @@ mod tests { #[test] fn test_part_1_example() -> Result<()> { - assert_eq!(2, part_1(TEST_INPUT)?); + assert_eq!(2, Day4::part_1(TEST_INPUT)?); Ok(()) } #[test] fn test_part_2_example() -> Result<()> { - assert_eq!(4, part_2(TEST_INPUT)?); + assert_eq!(4, Day4::part_2(TEST_INPUT)?); Ok(()) } } diff --git a/src/day_5.rs b/src/day_5.rs index 10eb2bc..006a59a 100644 --- a/src/day_5.rs +++ b/src/day_5.rs @@ -6,6 +6,8 @@ use std::{ use anyhow::{Context, Result}; +use crate::{Problem, Solution}; + #[derive(Debug)] struct Procedure(Vec); @@ -154,29 +156,32 @@ impl Display for Stacks { } } -const DAY: u8 = 5; -const INPUT: &str = include_str!("../input/day_5.txt"); +pub struct Day5; -pub fn solve() -> Result<()> { - println!("day {}", DAY); - println!("part 1: {}", part_1(INPUT)?); - println!("part 2: {}", part_2(INPUT)?); +impl Problem for Day5 { + const DAY: u8 = 5; - Ok(()) + const INPUT: &'static str = include_str!("../input/day_5.txt"); } -pub fn part_1(input: &str) -> Result { - let (stacks, procedure) = input.split_once("\n\n").unwrap(); - let stacks = Stacks::from_str(stacks)?; - let procedure = Procedure::from_str(procedure)?; - Ok(procedure.run(stacks, false)?.top()) -} +impl Solution for Day5 { + type Answer1 = String; + + type Answer2 = String; -pub fn part_2(input: &str) -> Result { - let (stacks, procedure) = input.split_once("\n\n").unwrap(); - let stacks = Stacks::from_str(stacks)?; - let procedure = Procedure::from_str(procedure)?; - Ok(procedure.run(stacks, true)?.top()) + fn part_1(input: &str) -> Result { + let (stacks, procedure) = input.split_once("\n\n").unwrap(); + let stacks = Stacks::from_str(stacks)?; + let procedure = Procedure::from_str(procedure)?; + Ok(procedure.run(stacks, false)?.top()) + } + + fn part_2(input: &str) -> Result { + let (stacks, procedure) = input.split_once("\n\n").unwrap(); + let stacks = Stacks::from_str(stacks)?; + let procedure = Procedure::from_str(procedure)?; + Ok(procedure.run(stacks, true)?.top()) + } } #[cfg(test)] @@ -197,11 +202,11 @@ mod tests { #[test] fn test_part_1_example() -> Result<()> { - Ok(assert_eq!("CMZ", part_1(TEST_INPUT)?)) + Ok(assert_eq!("CMZ", Day5::part_1(TEST_INPUT)?)) } #[test] fn test_part_2_example() -> Result<()> { - Ok(assert_eq!("MCD", part_2(TEST_INPUT)?)) + Ok(assert_eq!("MCD", Day5::part_2(TEST_INPUT)?)) } } diff --git a/src/day_6.rs b/src/day_6.rs index f8f624f..5983400 100644 --- a/src/day_6.rs +++ b/src/day_6.rs @@ -2,8 +2,7 @@ use std::collections::HashSet; use anyhow::Result; -const DAY: u8 = 6; -const INPUT: &str = include_str!("../input/day_6.txt"); +use crate::{Problem, Solution}; fn get_window_pos(input: &str, win_size: usize) -> Option { input @@ -21,20 +20,26 @@ fn get_window_pos(input: &str, win_size: usize) -> Option { .map(|i| i + win_size) } -pub fn solve() -> Result<()> { - println!("day {}", DAY); - println!("part 1: {}", part_1(INPUT)?); - println!("part 2: {}", part_2(INPUT)?); +pub struct Day6; - Ok(()) -} +impl Problem for Day6 { + const DAY: u8 = 6; -pub fn part_1(input: &str) -> Result { - get_window_pos(input, 4).ok_or_else(|| anyhow::anyhow!("Failed to find item")) + const INPUT: &'static str = include_str!("../input/day_6.txt"); } -pub fn part_2(input: &str) -> Result { - get_window_pos(input, 14).ok_or_else(|| anyhow::anyhow!("Failed to find item")) +impl Solution for Day6 { + type Answer1 = usize; + + type Answer2 = usize; + + fn part_1(input: &str) -> Result { + get_window_pos(input, 4).ok_or_else(|| anyhow::anyhow!("Failed to find item")) + } + + fn part_2(input: &str) -> Result { + get_window_pos(input, 14).ok_or_else(|| anyhow::anyhow!("Failed to find item")) + } } #[cfg(test)] @@ -51,7 +56,7 @@ mod tests { ("zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw", 11), ]; for test in tests { - assert_eq!(test.1, part_1(test.0)?); + assert_eq!(test.1, Day6::part_1(test.0)?); } Ok(()) @@ -67,7 +72,7 @@ mod tests { ("zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw", 26), ]; for test in tests { - assert_eq!(test.1, part_2(test.0)?); + assert_eq!(test.1, Day6::part_2(test.0)?); } Ok(()) diff --git a/src/day_7.rs b/src/day_7.rs index d49d026..70e5448 100644 --- a/src/day_7.rs +++ b/src/day_7.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, fmt::Display, ops::Deref, str::FromStr}; use anyhow::{anyhow, Context, Result}; -use crate::Solution; +use crate::{Problem, Solution}; enum Cmd { Root, @@ -145,14 +145,16 @@ impl Display for FileSystem { pub struct Day7; -impl<'a> Solution<'a> for Day7 { - type Answer1 = usize; +impl Problem for Day7 { + const DAY: u8 = 7; - type Answer2 = usize; + const INPUT: &'static str = include_str!("../input/day_7.txt"); +} - const DAY: u8 = 7; +impl Solution for Day7 { + type Answer1 = usize; - const INPUT: &'a str = include_str!("../input/day_7.txt"); + type Answer2 = usize; fn part_1(input: &str) -> Result { let fs: FileSystem = input.parse()?; diff --git a/src/lib.rs b/src/lib.rs index 655815d..04bbb85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,28 +2,30 @@ #![feature(iter_next_chunk)] #![feature(associated_type_defaults)] -pub trait Solution<'a> { +pub trait Solution: Problem { type Answer1: std::fmt::Display + Default = String; type Answer2: std::fmt::Display + Default = String; - const DAY: u8; - - const INPUT: &'a str; - fn part_1(input: &str) -> Result; fn part_2(input: &str) -> Result; fn solve() -> anyhow::Result<()> { - println!("day {}", Self::DAY); - println!("part 1: {}", Self::part_1(Self::INPUT)?); - println!("part 2: {}", Self::part_2(Self::INPUT)?); + println!("Day {}", Self::DAY); + println!("\tpart 1: {}", Self::part_1(Self::INPUT)?); + println!("\tpart 2: {}\n", Self::part_2(Self::INPUT)?); Ok(()) } } +pub trait Problem { + const DAY: u8; + + const INPUT: &'static str; +} + pub mod day_1; pub mod day_2; pub mod day_3; diff --git a/src/main.rs b/src/main.rs index 2ca05d5..b4bdb53 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,16 @@ -use advent_of_code_2022::{day_1, day_2, day_3, day_4, day_5, day_6, day_7::Day7, Solution}; +use advent_of_code_2022::{ + day_1::Day1, day_2::Day2, day_3::Day3, day_4::Day4, day_5::Day5, day_6::Day6, day_7::Day7, + Solution, +}; use anyhow::Result; fn main() -> Result<()> { - day_1::solve()?; - day_2::solve()?; - day_3::solve()?; - day_4::solve()?; - day_5::solve()?; - day_6::solve()?; + Day1::solve()?; + Day2::solve()?; + Day3::solve()?; + Day4::solve()?; + Day5::solve()?; + Day6::solve()?; Day7::solve()?; Ok(()) -- cgit v1.2.3-70-g09d2