-
Notifications
You must be signed in to change notification settings - Fork 3
/
day_03.rs
104 lines (87 loc) · 2.25 KB
/
day_03.rs
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
use std::collections::HashMap;
use aoc_lib::regex;
use common::{solution, Answer};
use nd_vec::{vector, Vec2};
type Pos = Vec2<usize>;
solution!("Gear Ratios", 3);
fn part_a(input: &str) -> Answer {
parse(input)
.gears
.iter()
.filter(|x| x.part_number)
.map(|x| x.value)
.sum::<u32>()
.into()
}
fn part_b(input: &str) -> Answer {
parse(input)
.ratios
.iter()
.filter(|(_, vals)| vals.len() == 2)
.map(|(_, vals)| vals[0] * vals[1])
.sum::<u32>()
.into()
}
struct ParseResult {
gears: Vec<Gear>,
ratios: HashMap<Pos, Vec<u32>>,
}
fn parse(input: &str) -> ParseResult {
let mut symbols = HashMap::new();
for (y, line) in input.lines().enumerate() {
for (x, c) in line.char_indices() {
if !c.is_ascii_digit() && c != '.' {
symbols.insert(vector!(x, y), c);
}
}
}
let mut gears = Vec::new();
let mut ratios = HashMap::new();
for (y, line) in input.lines().enumerate() {
for m in regex!(r"\d+").find_iter(line) {
let value = m.as_str().parse().unwrap();
let mut part_number = false;
for nx in m.start().saturating_sub(1)..=m.end() {
for ny in y.saturating_sub(1)..=y + 1 {
let pos = vector!(nx, ny);
let symbol = symbols.get(&pos);
part_number |= symbol.is_some();
if symbol == Some(&'*') {
ratios.entry(pos).or_insert(Vec::new()).push(value);
}
}
}
gears.push(Gear { value, part_number });
}
}
ParseResult { gears, ratios }
}
#[derive(Debug)]
struct Gear {
value: u32,
part_number: bool,
}
#[cfg(test)]
mod test {
use indoc::indoc;
const CASE: &str = indoc! {"
467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..
"};
#[test]
fn part_a() {
assert_eq!(super::part_a(CASE), 4361.into());
}
#[test]
fn part_b() {
assert_eq!(super::part_b(CASE), 467835.into());
}
}