-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathday9.rs
More file actions
131 lines (120 loc) · 3.27 KB
/
Copy pathday9.rs
File metadata and controls
131 lines (120 loc) · 3.27 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
131
use aoc_runner_derive::aoc;
use itertools::Itertools;
#[aoc(day9, part1)]
#[must_use]
pub fn part1(input: &str) -> usize {
let mut memory = Vec::with_capacity(51200);
let input = input.bytes().enumerate();
let mut digits_rev = input
.clone()
.rev()
.skip_while(|&(_, b)| !b.is_ascii_digit());
let (mut i_rev, mut i_id_rev, mut b_rev, mut b_remaining_rev);
(i_rev, b_rev) = digits_rev.next().unwrap();
if i_rev % 2 == 1 {
(i_rev, b_rev) = digits_rev.next().unwrap();
}
i_id_rev = i_rev / 2;
b_remaining_rev = b_rev - b'0';
for (i, b) in input {
if i >= i_rev {
for _ in 0..b_remaining_rev {
memory.push(i_id_rev);
}
break;
}
if i % 2 == 0 {
let i_id = i / 2;
for _ in 0..(b - b'0') {
memory.push(i_id);
}
} else {
for _ in 0..(b - b'0') {
if b_remaining_rev == 0 {
_ = digits_rev.next().unwrap();
(i_rev, b_rev) = digits_rev.next().unwrap();
if i >= i_rev {
break;
}
i_id_rev = i_rev / 2;
b_remaining_rev = b_rev - b'0';
}
b_remaining_rev -= 1;
memory.push(i_id_rev);
}
}
}
memory.into_iter().enumerate().map(|(i, id)| i * id).sum()
}
#[aoc(day9, part2)]
#[must_use]
pub fn part2(input: &str) -> usize {
let mut files = Vec::with_capacity(10000);
input
.bytes()
.filter(|&b| b.is_ascii_digit())
.enumerate()
.fold(0, |mut start, (i, b)| {
let len = b - b'0';
if i % 2 == 0 {
files.push(File {
id: i / 2,
start,
len,
});
}
start += len as usize;
start
});
(0..=files.last().unwrap().id).rev().for_each(|id| {
let file_id = files.iter().position(|file| file.id == id).unwrap();
if let Some(new_pos) = files
.iter()
.tuple_windows()
.find_map(|(a, b)| {
let end = a.start + a.len as usize;
if end > files[file_id].start {
Some(None)
} else if b.start - end >= files[file_id].len as usize {
Some(Some(end))
} else {
None
}
})
.flatten()
{
files[file_id].start = new_pos;
}
files.sort_by_key(|file| file.start);
});
files
.into_iter()
.map(|file| {
(file.start..file.start + file.len as usize)
.map(|idx| idx * file.id)
.sum::<usize>()
})
.sum()
}
#[derive(Clone, Copy)]
struct File {
id: usize,
start: usize,
len: u8,
}
#[cfg(test)]
mod tests {
use super::*;
use indoc::indoc;
const SAMPLE: &str = indoc! {"
2333133121414131402
"};
#[test]
pub fn part1_example() {
assert_eq!(part1(SAMPLE), 1928);
}
#[test]
pub fn part2_example() {
assert_eq!(part2(SAMPLE), 2858);
}
}