Skip to content

Commit 0009c2a

Browse files
committed
Day09
1 parent a46140b commit 0009c2a

File tree

2 files changed

+162
-1
lines changed

2 files changed

+162
-1
lines changed

src/day09.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
use std::fs;
2+
3+
pub fn day09(input_path: String) {
4+
let content = fs::read_to_string(input_path).unwrap();
5+
let numbers = content
6+
.trim()
7+
.chars()
8+
.map(|c| c.to_digit(10).unwrap())
9+
.collect::<Vec<_>>();
10+
11+
let mut disk = make_explicit_disk_map(&numbers);
12+
compact_p1(&mut disk);
13+
14+
println!("{:?}", checksum(&disk));
15+
16+
let mut disk = make_explicit_disk_map(&numbers);
17+
compact_p2(&mut disk);
18+
println!("{:?}", checksum(&disk));
19+
}
20+
21+
type ExplicitDiskMap = Vec<Option<usize>>;
22+
23+
// 2333133121414131402 -> 00...111...2...333.44.5555.6666.777.888899
24+
// where empty = . = None
25+
fn make_explicit_disk_map(input: &[u32]) -> ExplicitDiskMap {
26+
let mut blocks = Vec::new();
27+
for (i, chunk) in input.chunks(2).enumerate() {
28+
match chunk {
29+
[file, free] => {
30+
blocks.extend(vec![Some(i); *file as usize]);
31+
blocks.extend(vec![None; *free as usize]);
32+
}
33+
[file] => {
34+
blocks.extend(vec![Some(i); *file as usize]);
35+
}
36+
_ => panic!(),
37+
};
38+
}
39+
blocks
40+
}
41+
42+
fn compact_p1(disk_map: &mut ExplicitDiskMap) {
43+
// C++ iterators would be really cool here
44+
let (mut front, mut back) = (0, disk_map.len() - 1);
45+
while front != back {
46+
match (disk_map[front], disk_map[back]) {
47+
(Some(_), _) => {
48+
front += 1;
49+
}
50+
(_, None) => {
51+
back -= 1;
52+
}
53+
(None, Some(_)) => {
54+
disk_map.swap(front, back);
55+
}
56+
}
57+
}
58+
}
59+
60+
fn compact_p2(disk_map: &mut ExplicitDiskMap) {
61+
// sadly O(n^2), see failed O(n logn) attempt below
62+
for i in (1..disk_map.len()).rev() {
63+
if disk_map[i].is_none() || disk_map[i] == disk_map[i - 1] {
64+
continue;
65+
}
66+
67+
let file_size = disk_map[i..]
68+
.iter()
69+
.take_while(|&c| *c == disk_map[i])
70+
.count();
71+
72+
let end_of_first_spot = disk_map
73+
.iter()
74+
// ok these scan semantics are surprising (read: ass)
75+
.scan(0, |run, c| match c {
76+
Some(_) => {
77+
*run = 0;
78+
Some(0)},
79+
None => {
80+
*run += 1;
81+
Some(*run)
82+
}
83+
})
84+
.enumerate()
85+
.skip_while(|(_, run)| *run < file_size)
86+
.skip_while(|(j, _)| *j > i)
87+
.map(|(j, _)| j)
88+
.next();
89+
90+
if let Some(last_empty) = end_of_first_spot {
91+
for k in 0..file_size {
92+
disk_map.swap(last_empty - k, i + k);
93+
}
94+
}
95+
}
96+
}
97+
98+
fn checksum(disk_map: &[Option<usize>]) -> usize {
99+
disk_map
100+
.iter()
101+
.enumerate()
102+
.filter_map(|(i, f)| f.map(|f| i * f))
103+
.sum()
104+
}
105+
106+
// fn compact_p2(disk_map: &mut ExplicitDiskMap) {
107+
// // mapping size to starts
108+
// let mut empties = BTreeMap::new();
109+
// let mut run = 0;
110+
// for (i, block) in disk_map.iter().enumerate() {
111+
// match block {
112+
// Some(_) => {
113+
// if run > 0 {
114+
// empties
115+
// .entry(run)
116+
// .or_insert(BinaryHeap::new())
117+
// .push(Reverse(i - run)); // Reverse the ordering
118+
// run = 0;
119+
// }
120+
// }
121+
// None => run += 1,
122+
// }
123+
// }
124+
125+
// let mut file_id = 0;
126+
// let mut file_size = 0;
127+
// for i in (0..disk_map.len()).rev() {
128+
// match disk_map[i] {
129+
// Some(f) => {
130+
// if f == file_id {
131+
// file_size += 1;
132+
// } else {
133+
// if file_size > 0 {
134+
// // move the file to the first spot large enough to hold it
135+
// let maybe_next = empties
136+
// .range_mut(file_size..)
137+
// .map_while(|(size, starts)| starts.pop().map(|start| (size, start)))
138+
// .next();
139+
140+
// if let Some((size, Reverse(start))) = maybe_next {
141+
// // move file
142+
// for j in 0..file_size {
143+
// disk_map.swap(start + j, i + j);
144+
// }
145+
// // update empties
146+
// empties
147+
// .entry(size - file_size)
148+
// .or_insert(BinaryHeap::new())
149+
// .push(Reverse(start + file_size));
150+
// }
151+
// }
152+
// file_id = f;
153+
// file_size = 1;
154+
// }
155+
// }
156+
// None => {}
157+
// }
158+
// }
159+
// }

src/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod day05;
1010
mod day06;
1111
mod day07;
1212
mod day08;
13+
mod day09;
1314

1415
#[derive(Parser)]
1516
struct Args {
@@ -30,6 +31,7 @@ fn main() {
3031
5 => day05::day05(args.input_path),
3132
6 => day06::day06(args.input_path),
3233
7 => day07::day07(args.input_path),
33-
_ => day08::day08(args.input_path),
34+
8 => day08::day08(args.input_path),
35+
_ => day09::day09(args.input_path),
3436
}
3537
}

0 commit comments

Comments
 (0)