1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
use std::{ops::Deref, str::FromStr};
use anyhow::{anyhow, Context, Result};
use crate::{Problem, Solution};
trait Priority {
fn priority(self) -> Result<u8>;
}
impl Priority for char {
fn priority(self) -> Result<u8> {
match self as u8 {
c @ 65..=90 => Ok(c - 65 + 27),
c @ 97..=122 => Ok(c - 97 + 1),
c => Err(anyhow!("failed to get priority of {}", c as char)),
}
}
}
#[derive(Debug, Clone)]
struct Backpack(Vec<char>);
impl Backpack {
fn get_local_union(self) -> Result<char> {
let (left, right) = self.split_at(self.len() / 2);
left.iter()
.cloned()
.find(|&item| right.contains(&item))
.context(format!("Failed to find union in {:?}", &self))
}
fn get_group_union(group: &mut Vec<Backpack>) -> Result<char> {
group
.split_first_mut()
.and_then(|(first, others)| {
first
.iter()
.cloned()
.find(|item| others.iter_mut().all(|b| b.contains(item)))
})
.context(format!("Failed to find union in {:?}", group))
}
}
impl Deref for Backpack {
type Target = Vec<char>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::str::FromStr for Backpack {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
Ok(Backpack(s.as_bytes().iter().map(|c| *c as char).collect()))
}
}
pub struct Day03;
impl Problem for Day03 {
const DAY: u8 = 3;
const INPUT: &'static str = include_str!("../input/day_3.txt");
}
impl Solution for Day03 {
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<_>>()?
.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))
}
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<()> {
Ok(assert_eq!(157, Day03::part_1(INPUT)?))
}
#[test]
fn test_part_2_example() -> Result<()> {
Ok(assert_eq!(70, Day03::part_2(INPUT)?))
}
}
|