-
Notifications
You must be signed in to change notification settings - Fork 0
/
03.rs
125 lines (112 loc) · 2.89 KB
/
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::collections::HashMap;
static INPUT_TXT: &str = include_str!("../../input/03.txt");
fn main() {
println!("Part 1: {}", part_1(INPUT_TXT));
println!("Part 2: {}", part_2(INPUT_TXT));
}
type Point = (usize, usize);
#[derive(Debug)]
struct Number {
value: u32,
x_range: (usize, usize),
y: usize,
}
impl Number {
fn new(num: &str, (x, y): Point) -> Self {
let value = num.parse::<u32>().expect("Invalid number");
let start_x = x + 1 - num.len();
Self {
value,
x_range: (start_x, x),
y,
}
}
fn is_adjacent(&self, (x, y): &Point) -> bool {
!(self.y.abs_diff(*y) > 1
|| *x < self.x_range.0.saturating_sub(1)
|| *x > self.x_range.1 + 1)
}
}
fn parse_input(input: &str) -> (Vec<Number>, HashMap<Point, char>) {
let mut numbers = Vec::new();
let mut symbols = HashMap::new();
for (pos_y, l) in input.trim().lines().enumerate() {
let mut num = String::new();
for (pos_x, c) in l.chars().enumerate() {
if c.is_ascii_digit() {
num.push(c);
} else {
if c != '.' {
symbols.insert((pos_x, pos_y), c);
}
if !num.is_empty() {
numbers.push(Number::new(&num, (pos_x - 1, pos_y)));
num.clear();
}
}
}
if !num.is_empty() {
numbers.push(Number::new(&num, (l.len() - 1, pos_y)));
}
}
(numbers, symbols)
}
fn part_1(input: &str) -> u32 {
let (numbers, symbols) = parse_input(input);
symbols
.keys()
.map(|pos| {
numbers
.iter()
.filter(|n| n.is_adjacent(pos))
.map(|n| n.value)
.sum::<u32>()
})
.sum()
}
fn part_2(input: &str) -> u32 {
let (numbers, symbols) = parse_input(input);
symbols
.iter()
.map(|(pos, c)| {
if *c == '*' {
let neighbours = numbers
.iter()
.filter(|n| n.is_adjacent(pos))
.map(|n| n.value)
.collect::<Vec<u32>>();
if neighbours.len() == 2 {
neighbours.into_iter().product()
} else {
0
}
} else {
0
}
})
.sum()
}
#[cfg(test)]
mod tests {
use super::*;
static INPUT: &str = "467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..";
#[test]
fn test_part_1() {
assert_eq!(part_1(INPUT), 4361);
assert_eq!(part_1(INPUT_TXT), 527_369);
}
#[test]
fn test_part_2() {
assert_eq!(part_2(INPUT), 467_835);
assert_eq!(part_2(INPUT_TXT), 73_074_886);
}
}