Skip to content

Commit 2830333

Browse files
committed
9th day
1 parent b221b54 commit 2830333

File tree

3 files changed

+129
-0
lines changed

3 files changed

+129
-0
lines changed

data/examples/09.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2333133121414131402

src/bin/09.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
advent_of_code::solution!(9);
2+
3+
use advent_of_code::majcn::math::*;
4+
5+
struct FileBlock {
6+
id: usize,
7+
size: usize,
8+
position: usize,
9+
}
10+
11+
struct FreeBlock {
12+
size: usize,
13+
position: usize,
14+
}
15+
16+
fn parse_data(input: &str) -> (Vec<FileBlock>, Vec<FreeBlock>) {
17+
let mut file_list = vec![];
18+
let mut free_list = vec![];
19+
20+
let mut position = 0;
21+
22+
for (i, x) in input.bytes().enumerate() {
23+
let size = (x - b'0') as usize;
24+
25+
if i % 2 == 0 {
26+
file_list.push(FileBlock {
27+
id: i / 2,
28+
size,
29+
position,
30+
});
31+
} else if x != 0 {
32+
free_list.push(FreeBlock { size, position });
33+
}
34+
35+
position += size;
36+
}
37+
38+
(file_list, free_list)
39+
}
40+
41+
pub fn part_one(input: &str) -> Option<u64> {
42+
let (file_list, free_list) = parse_data(input);
43+
44+
let mut result = 0;
45+
46+
let mut free_index = 0;
47+
let mut free_offset = 0;
48+
49+
for file in file_list.into_iter().rev() {
50+
let mut file_free_swap = 0;
51+
for file_offset in 0..file.size {
52+
while free_list[free_index].size <= free_offset {
53+
free_index += 1;
54+
free_offset = 0;
55+
}
56+
57+
let free_position = free_list[free_index].position + free_offset;
58+
let position = if free_position < file.position {
59+
free_offset += 1;
60+
file_free_swap += 1;
61+
free_position
62+
} else {
63+
file.position + file_offset - file_free_swap
64+
};
65+
66+
result += file.id * position;
67+
}
68+
}
69+
70+
let result = result as u64;
71+
72+
Some(result)
73+
}
74+
75+
pub fn part_two(input: &str) -> Option<u64> {
76+
let (file_list, mut free_list) = parse_data(input);
77+
78+
let mut result = 0;
79+
80+
for mut file in file_list.into_iter().rev() {
81+
let free_option = free_list
82+
.iter_mut()
83+
.take_while(|x| x.position < file.position)
84+
.find(|x| x.size >= file.size);
85+
86+
if let Some(free) = free_option {
87+
file.position = free.position;
88+
free.position += file.size;
89+
free.size -= file.size;
90+
}
91+
92+
result += file.id * (file.size * file.position + (file.size - 1).sum_of_natural_numbers());
93+
}
94+
95+
let result = result as u64;
96+
97+
Some(result)
98+
}
99+
100+
#[cfg(test)]
101+
mod tests {
102+
use super::*;
103+
104+
#[test]
105+
fn test_part_one() {
106+
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
107+
assert_eq!(result, Some(1928));
108+
}
109+
110+
#[test]
111+
fn test_part_two() {
112+
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
113+
assert_eq!(result, Some(2858));
114+
}
115+
}

src/majcn/math.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1+
pub trait SumOfNaturalNumbers<T> {
2+
fn sum_of_natural_numbers(self) -> T;
3+
}
4+
5+
impl SumOfNaturalNumbers<usize> for usize {
6+
#[inline]
7+
fn sum_of_natural_numbers(self) -> usize {
8+
self * (self + 1) / 2
9+
}
10+
}
11+
112
pub trait DigitCounter {
213
fn count_digits(self) -> usize;
314
}
415

516
impl DigitCounter for u32 {
17+
#[inline]
618
fn count_digits(self) -> usize {
719
match self {
820
0..10 => 1,
@@ -19,6 +31,7 @@ impl DigitCounter for u32 {
1931
}
2032

2133
impl DigitCounter for u64 {
34+
#[inline]
2235
fn count_digits(self) -> usize {
2336
match self {
2437
0..10 => 1,

0 commit comments

Comments
 (0)