Skip to content

Commit 07487b7

Browse files
committed
Day 9
1 parent 9959fc4 commit 07487b7

File tree

3 files changed

+136
-2
lines changed

3 files changed

+136
-2
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
3131
| [Day 5](./src/bin/05.rs) | `344.6µs` | `323.6µs` |
3232
| [Day 6](./src/bin/06.rs) | `488.0µs` | `119.9ms` |
3333
| [Day 7](./src/bin/07.rs) | `80.3µs` | `113.7µs` |
34-
| [Day 8](./src/bin/08.rs) | `9.9µs` | `12.2µs` |
34+
| [Day 8](./src/bin/08.rs) | `10.2µs` | `12.4µs` |
35+
| [Day 9](./src/bin/09.rs) | `2.9ms` | `49.1ms` |
3536

36-
**Total: 123.92ms**
37+
**Total: 175.92ms**
3738
<!--- benchmarking table --->
3839

3940
---

data/examples/09.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2333133121414131402

src/bin/09.rs

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
use std::ops::Range;
2+
use itertools::Itertools;
3+
4+
advent_of_code::solution!(9);
5+
6+
#[derive(Debug)]
7+
struct DiskMap<T> {
8+
data: Vec<T>
9+
}
10+
11+
impl DiskMap<Option<usize>> {
12+
fn parse(input: &str) -> DiskMap<Option<usize>> {
13+
let data = (&input.chars().chunks(2)).into_iter()
14+
.enumerate()
15+
.flat_map(|(id_number, mut chunk)| {
16+
let Some(Some(file_size)) = chunk.next().map(|char| char.to_digit(10)) else { return Vec::new() };
17+
let mut file = vec![Some(id_number); file_size as usize];
18+
if let Some(Some(free_space)) = chunk.next().map(|char| char.to_digit(10)) {
19+
file.append(&mut vec![None; free_space as usize]);
20+
file
21+
} else {
22+
file
23+
}
24+
})
25+
.collect();
26+
DiskMap {
27+
data
28+
}
29+
}
30+
31+
fn checksum(&self) -> u64 {
32+
let len = self.data.len();
33+
let mut sum = 0;
34+
let (mut head, mut tail) = (1, len);
35+
while head < tail {
36+
let mut value = None;
37+
if let Some(val) = self.data[head] {
38+
value = Some(val);
39+
} else {
40+
while head < tail {
41+
tail -= 1;
42+
if let Some(val) = self.data[tail] {
43+
value = Some(val);
44+
break;
45+
};
46+
}
47+
}
48+
let Some(value) = value else { break };
49+
sum += head * value;
50+
head += 1;
51+
}
52+
sum as u64
53+
}
54+
}
55+
56+
#[derive(Default, Clone, Debug)]
57+
struct Interval {
58+
id: u64,
59+
interval: Range<u32>,
60+
}
61+
62+
impl DiskMap<Interval> {
63+
fn parse_intervals(input: &str) -> DiskMap<Interval> {
64+
let mut last_index = 0;
65+
let data = (&input.chars().chunks(2)).into_iter()
66+
.enumerate()
67+
.map(|(id_number, mut chunk)| {
68+
let Some(Some(file_size)) = chunk.next().map(|char| char.to_digit(10)) else { return Interval::default() };
69+
let file = Interval {
70+
id: id_number as u64,
71+
interval: last_index..(last_index + file_size)
72+
};
73+
last_index = file.interval.end;
74+
if let Some(Some(free_space)) = chunk.next().map(|char| char.to_digit(10)) {
75+
last_index += free_space;
76+
}
77+
file
78+
})
79+
.collect_vec();
80+
DiskMap {
81+
data
82+
}
83+
}
84+
85+
fn checksum(&self) -> u64 {
86+
let mut data = self.data.clone();
87+
for index in (1..data.len()).rev() {
88+
let interval = &self.data[index];
89+
let actual_index = data.iter().rposition(|x| x.id == interval.id).unwrap();
90+
let interval_size = interval.interval.end - interval.interval.start;
91+
let Some((new_index, start_index, _)) = (0..actual_index)
92+
.map(|index| (index, &data[index].interval, &data[index + 1].interval))
93+
.map(|(index, x, y)| (index, x.end, y.start - x.end))
94+
.find(|(_, _, size)| size >= &(interval_size)) else { continue };
95+
let interval = Interval {
96+
interval: start_index..(start_index + interval_size),
97+
..*interval
98+
};
99+
data.remove(actual_index);
100+
data.insert(new_index + 1, interval);
101+
}
102+
data.iter()
103+
.map(|Interval { id, interval }| interval.clone().map(|x| id * (x as u64)).sum::<u64>())
104+
.sum()
105+
}
106+
}
107+
108+
pub fn part_one(input: &str) -> Option<u64> {
109+
Some(DiskMap::parse(input).checksum())
110+
}
111+
112+
pub fn part_two(input: &str) -> Option<u64> {
113+
let disk_map = DiskMap::parse_intervals(input);
114+
Some(disk_map.checksum())
115+
}
116+
117+
#[cfg(test)]
118+
mod tests {
119+
use super::*;
120+
121+
#[test]
122+
fn test_part_one() {
123+
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
124+
assert_eq!(result, Some(1928));
125+
}
126+
127+
#[test]
128+
fn test_part_two() {
129+
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
130+
assert_eq!(result, Some(2858));
131+
}
132+
}

0 commit comments

Comments
 (0)