-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathd14.rs
More file actions
130 lines (103 loc) · 3.8 KB
/
d14.rs
File metadata and controls
130 lines (103 loc) · 3.8 KB
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
126
127
128
129
130
use std::collections::{HashMap, hash_map::Entry};
use crate::{Day, y2023::Direction};
pub struct Day14 {}
impl Day for Day14 {
fn year(&self) -> u16 {
2023
}
fn day(&self) -> u8 {
14
}
fn part_one(&self) -> String {
let mut platform = self
.read_default_input()
.lines()
.map(|line| line.chars().collect::<Vec<char>>())
.collect::<Vec<Vec<char>>>();
apply_gravity(&mut platform, &Direction::North);
calculate_load(&platform).to_string()
}
fn part_two(&self) -> String {
let mut platform = self
.read_default_input()
.lines()
.map(|line| line.chars().collect::<Vec<char>>())
.collect::<Vec<Vec<char>>>();
let mut cache: HashMap<String, usize> = HashMap::new();
let mut cycle_load: HashMap<usize, usize> = HashMap::new();
for i in 1..=1_000_000_000 {
let serialized_platform = serialize(&platform);
match cache.entry(serialized_platform.clone()) {
Entry::Occupied(last_occurrence) => {
let last_occurrence = *last_occurrence.get();
let cycles_from_repeating = 1_000_000_000 - last_occurrence;
let repeating_size = i - last_occurrence;
let distance_to_target = cycles_from_repeating % repeating_size;
let target = last_occurrence + distance_to_target;
return cycle_load.get(&target).unwrap().to_string();
}
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(i);
}
}
cycle_platform(&mut platform);
cycle_load.insert(i, calculate_load(&platform));
}
unreachable!()
}
}
fn cycle_platform(platform: &mut [Vec<char>]) {
for direction in Direction::iter() {
apply_gravity(platform, &direction);
}
}
fn apply_gravity(platform: &mut [Vec<char>], direction: &Direction) {
let (x_mod, y_mod) = direction.modifier();
let x_iter = match direction {
Direction::East => (0..platform[0].len()).rev().collect::<Vec<_>>(),
_ => (0..platform[0].len()).collect::<Vec<_>>(),
};
let y_iter = match direction {
Direction::South => (0..platform.len()).rev().collect::<Vec<_>>(),
_ => (0..platform.len()).collect::<Vec<_>>(),
};
for y in y_iter {
for x in x_iter.clone() {
if platform[y][x] == 'O' {
let mut new_y = y;
let mut new_x = x;
let mut next_y = y as i32 + y_mod;
let mut next_x = x as i32 + x_mod;
while (next_y < platform.len() as i32 && next_y >= 0)
&& (next_x < platform[0].len() as i32 && next_x >= 0)
{
match platform[next_y as usize][next_x as usize] {
'.' => {
new_x = next_x as usize;
new_y = next_y as usize;
}
'O' | '#' => break,
_ => unreachable!(),
}
next_y += y_mod;
next_x += x_mod;
}
if new_x != x || new_y != y {
platform[y][x] = '.';
platform[new_y][new_x] = 'O';
}
}
}
}
}
fn calculate_load(platform: &[Vec<char>]) -> usize {
let mut total_load = 0;
for y in 0..platform.len() {
total_load +=
platform[y].iter().filter(|item| **item == 'O').count() * (platform.len() - y);
}
total_load
}
fn serialize(platform: &[Vec<char>]) -> String {
platform.iter().flatten().collect::<String>()
}