-
Notifications
You must be signed in to change notification settings - Fork 3
/
day_14.rs
125 lines (103 loc) Β· 2.69 KB
/
day_14.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, convert::identity, hash::Hash};
use aoc_lib::matrix::Grid;
use common::{solution, Answer};
use nd_vec::{vector, Vec2};
type Pos = Vec2<isize>;
solution!("Parabolic Reflector Dish", 14);
fn part_a(input: &str) -> Answer {
let mut dish = parse(input);
dish.tilt(vector!(0, -1));
dish.score().into()
}
fn part_b(input: &str) -> Answer {
let mut dish = parse(input);
const ITERS: usize = 1000000000;
let mut seen = HashMap::new();
for i in 0..ITERS {
if let Some(prev) = seen.get(&dish) {
if (ITERS - i) % (i - prev) == 0 {
return dish.score().into();
}
}
seen.insert(dish.clone(), i);
dish.spin();
}
dish.score().into()
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Dish {
tiles: Grid<char>,
}
fn parse(input: &str) -> Dish {
Dish {
tiles: Grid::parse(input, identity),
}
}
impl Dish {
fn tilt(&mut self, tilt: Pos) {
let tiles = &mut self.tiles;
loop {
let mut moved = false;
for y in 0..tiles.size.y() {
for x in 0..tiles.size.x() {
let pos = vector!(x as isize, y as isize);
if tiles[pos] != 'O' {
continue;
}
let new_pos = vector!(x, y).num_cast().unwrap() + tilt;
if !tiles.contains(new_pos) || tiles[new_pos] != '.' {
continue;
}
let tile = tiles[pos];
tiles.set(pos, '.');
tiles.set(new_pos, tile);
moved = true;
}
}
if !moved {
break;
}
}
}
fn spin(&mut self) {
for pos in [vector!(0, -1), vector!(-1, 0), vector!(0, 1), vector!(1, 0)] {
self.tilt(pos);
}
}
fn score(&self) -> usize {
let tiles = &self.tiles;
let mut acc = 0;
for y in 0..tiles.size.y() {
for x in 0..tiles.size.x() {
if tiles[[x, y]] == 'O' {
acc += tiles.size.y() - y;
}
}
}
acc
}
}
#[cfg(test)]
mod test {
use indoc::indoc;
const CASE: &str = indoc! {"
O....#....
O.OO#....#
.....##...
OO.#O....O
.O.....O#.
O.#..O.#.#
..O..#O..O
.......O..
#....###..
#OO..#....
"};
#[test]
fn part_a() {
assert_eq!(super::part_a(CASE), 136.into());
}
#[test]
fn part_b() {
assert_eq!(super::part_b(CASE), 64.into());
}
}