summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToby Vincent <tobyv13@gmail.com>2022-12-07 18:41:51 -0600
committerToby Vincent <tobyv13@gmail.com>2022-12-07 18:41:51 -0600
commite18bd67711510dbdf9254f1811aa76d1cca3abbc (patch)
treed993b2fb30582f9b8d589cc39c66f1f4221e6858
parent6e5439b2aa1ac9707d41729f974b1f3e4d07fc8d (diff)
feat!: impl Problem and Solution traits for all days
-rw-r--r--src/day_1.rs49
-rw-r--r--src/day_2.rs80
-rw-r--r--src/day_3.rs91
-rw-r--r--src/day_4.rs36
-rw-r--r--src/day_5.rs45
-rw-r--r--src/day_6.rs33
-rw-r--r--src/day_7.rs14
-rw-r--r--src/lib.rs18
-rw-r--r--src/main.rs17
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::<usize>()).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::<usize>()).sum())
- .collect::<Vec<usize>>();
+impl Solution for Day1 {
+ type Answer1 = usize;
+
+ type Answer2 = usize;
+
+ fn part_1(input: &str) -> Result<Self::Answer1, anyhow::Error> {
+ input
+ .split("\n\n")
+ .map(|e| e.split('\n').flat_map(|l| l.parse::<usize>()).sum())
+ .max()
+ .context("Failed to find max")
+ }
+
+ fn part_2(input: &str) -> Result<Self::Answer2, anyhow::Error> {
+ let mut vec = input
+ .split("\n\n")
+ .map(|e| e.split('\n').flat_map(|l| l.parse::<usize>()).sum())
+ .collect::<Vec<usize>>();
- 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<usize> {
- 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<Self::Answer1, anyhow::Error> {
+ 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<usize> {
- 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<Self::Answer2, anyhow::Error> {
+ 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<u8>;
@@ -66,58 +58,65 @@ impl std::str::FromStr for Backpack {
}
}
-pub fn part_1(input: &str) -> Result<usize> {
- input
- .lines()
- .map(Backpack::from_str)
- .try_collect::<Vec<_>>()?
- .into_iter()
- .map(|b| b.get_local_union())
- .try_collect::<Vec<_>>()?
- .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<usize> {
- 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<Self::Answer1, anyhow::Error> {
+ input
+ .lines()
.map(Backpack::from_str)
- .try_collect::<Vec<_>>()?;
+ .try_collect::<Vec<_>>()?
+ .into_iter()
+ .map(|b| b.get_local_union())
+ .try_collect::<Vec<_>>()?
+ .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<Self::Answer2, anyhow::Error> {
+ 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::<Vec<_>>()?;
+
+ 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<Range<usize>> {
let (start, end) = section.split_once('-').unwrap();
let start = start.parse::<usize>()?;
@@ -23,24 +25,28 @@ fn range_is_union((a, b): &(Range<usize>, Range<usize>)) -> 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<usize> {
- let ranges: Vec<_> = input.lines().map(parse_pair).collect::<Result<_>>()?;
- 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<usize> {
- let ranges: Vec<_> = input.lines().map(parse_pair).collect::<Result<_>>()?;
- Ok(ranges.into_iter().filter(range_is_union).count())
+ fn part_1(input: &str) -> Result<Self::Answer1, anyhow::Error> {
+ let ranges: Vec<_> = input.lines().map(parse_pair).collect::<Result<_>>()?;
+ Ok(ranges.into_iter().filter(range_is_subset).count())
+ }
+
+ fn part_2(input: &str) -> Result<Self::Answer2, anyhow::Error> {
+ let ranges: Vec<_> = input.lines().map(parse_pair).collect::<Result<_>>()?;
+ 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<Step>);
@@ -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<String> {
- 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<String> {
- 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<Self::Answer1, anyhow::Error> {
+ 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<Self::Answer2, anyhow::Error> {
+ 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<usize> {
input
@@ -21,20 +20,26 @@ fn get_window_pos(input: &str, win_size: usize) -> Option<usize> {
.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<usize> {
- 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<usize> {
- 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<Self::Answer1, anyhow::Error> {
+ get_window_pos(input, 4).ok_or_else(|| anyhow::anyhow!("Failed to find item"))
+ }
+
+ fn part_2(input: &str) -> Result<Self::Answer2, anyhow::Error> {
+ 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<Self::Answer1> {
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<Self::Answer1, anyhow::Error>;
fn part_2(input: &str) -> Result<Self::Answer2, anyhow::Error>;
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(())