-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday3.rs
121 lines (100 loc) · 2.91 KB
/
day3.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
//! [Day 3: Gear Ratios](https://adventofcode.com/2023/day/3)
use rustc_hash::FxHashMap;
struct Puzzle {
grid: aoc::Grid<char>,
sum_parts: u64,
gears: FxHashMap<[i32; 2], Vec<u64>>,
}
impl Puzzle {
fn new(data: &str) -> Self {
Self {
grid: aoc::Grid::<char>::parse(data, '.'),
sum_parts: 0,
gears: FxHashMap::default(),
}
}
/// Read the schematic to find part numbers and gears
fn parse(&mut self) {
for y in 0..self.grid.height() {
let mut x = 0;
while x < self.grid.width() {
let mut symbol = false;
let mut gear = [0, 0];
let mut n = 0;
while let Some(d) = self.grid[(x, y)].to_digit(10) {
n = n * 10 + u64::from(d);
for (ix, iy) in [
(-1, -1),
(-1, 0),
(-1, 1),
(0, -1),
(0, 1),
(1, -1),
(1, 0),
(1, 1),
] {
let c = self.grid[(x + ix, y + iy)];
if c != '.' && !c.is_ascii_digit() {
symbol = true;
if c == '*' {
// assert we have only one gear near a part number
assert!(!(gear != [0, 0] && gear != [x + ix, y + iy]),);
gear = [x + ix, y + iy];
}
}
}
x += 1;
}
if symbol {
self.sum_parts += n;
}
if gear != [0, 0] {
self.gears.entry(gear).or_default().push(n);
}
x += 1;
}
}
}
/// Solve part one.
const fn part1(&self) -> u64 {
self.sum_parts
}
/// Solve part two.
fn part2(&self) -> u64 {
let mut gear_ratios = 0;
for parts in self.gears.values() {
if parts.len() == 2 {
gear_ratios += parts[0] * parts[1];
}
}
gear_ratios
}
}
/// # Panics
#[must_use]
pub fn solve(data: &str) -> (u64, u64) {
let mut puzzle = Puzzle::new(data);
puzzle.parse();
(puzzle.part1(), puzzle.part2())
}
pub fn main() {
let args = aoc::parse_args();
args.run(solve);
}
#[cfg(test)]
mod test {
use super::*;
const TEST_INPUT: &str = include_str!("test.txt");
#[test]
fn test01() {
let mut puzzle = Puzzle::new(TEST_INPUT);
puzzle.parse();
assert_eq!(puzzle.part1(), 4361);
}
#[test]
fn test02() {
let mut puzzle = Puzzle::new(TEST_INPUT);
puzzle.parse();
assert_eq!(puzzle.part2(), 467835);
}
}