Skip to content

Commit 871b938

Browse files
authored
feat: day09 (#12)
1 parent c0b3b04 commit 871b938

File tree

10 files changed

+219
-1
lines changed

10 files changed

+219
-1
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ members = [
99
"crates/day06",
1010
"crates/day07",
1111
"crates/day08",
12+
"crates/day09",
1213
"crates/helpers",
1314
]
1415

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ Ideally, the solution does not use external crates/dependencies.
1919
| 6 |||||||
2020
| 7 |||||||
2121
| 8 |||||||
22+
| 9 |||||||

crates/day08/.response

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Part One solution: 323
2+
Part Two solution: 1077

crates/day08/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ fn main() {
133133
let checker = Antenna::new(&message);
134134
println!("Part One solution: {:?}", checker.count_antennas(false));
135135
// --- Part Two ---
136-
println!("Part One solution: {:?}", checker.count_antennas(true));
136+
println!("Part Two solution: {:?}", checker.count_antennas(true));
137137
}
138138

139139
#[cfg(test)]

crates/day09/.response

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Part One solution: 6288707484810
2+
Part Two solution: 6311837662089

crates/day09/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "day09"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lints]
7+
workspace = true
8+
9+
[dependencies]
10+
helpers = { path = "../helpers"}

crates/day09/example_input.txt

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

crates/day09/input.txt

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

crates/day09/src/main.rs

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
use helpers::read_file;
2+
3+
#[derive(Clone, Copy, Debug)]
4+
enum File {
5+
Free,
6+
Taken(u32),
7+
}
8+
9+
struct FileSystem {
10+
files: Vec<File>,
11+
defragmented_files: Vec<File>,
12+
}
13+
14+
impl FileSystem {
15+
fn new(content: &str) -> Self {
16+
let mut files: Vec<File> = Vec::new();
17+
let mut id = 0;
18+
for line in content.lines() {
19+
for (i, c) in line.chars().enumerate() {
20+
if let Some(digit) = c.to_digit(10) {
21+
if i % 2 == 0 {
22+
files.extend(
23+
std::iter::repeat(File::Taken(id)).take(digit.try_into().unwrap()),
24+
);
25+
id += 1;
26+
} else {
27+
files.extend(std::iter::repeat(File::Free).take(digit.try_into().unwrap()));
28+
}
29+
}
30+
}
31+
}
32+
let defragmented_files = files.clone();
33+
Self {
34+
files,
35+
defragmented_files,
36+
}
37+
}
38+
39+
fn count_free_files(files: &[File], index: usize) -> usize {
40+
let mut count = 0;
41+
for i in index..files.len() {
42+
match files.get(i) {
43+
Some(File::Free) => {
44+
count += 1;
45+
}
46+
Some(File::Taken(_)) | None => {
47+
break;
48+
}
49+
}
50+
}
51+
52+
count
53+
}
54+
55+
fn detect_block(files: &[File], index_end: usize) -> Option<(usize, usize)> {
56+
let mut current_block: Option<(u32, usize)> = None;
57+
58+
for i in (0..index_end).rev() {
59+
match files.get(i) {
60+
Some(File::Free) => {
61+
if let Some(new_block) = current_block {
62+
return Some((i + 1, new_block.1));
63+
}
64+
current_block = None;
65+
}
66+
Some(File::Taken(digit)) => {
67+
if current_block.is_none() {
68+
current_block = Some((*digit, 1));
69+
} else if *digit != current_block.unwrap().0 {
70+
return Some((i + 1, current_block.unwrap().1));
71+
} else {
72+
current_block = Some((*digit, current_block.unwrap().1 + 1));
73+
}
74+
}
75+
None => {
76+
break;
77+
}
78+
}
79+
}
80+
81+
None
82+
}
83+
84+
fn fragment_files(&mut self) {
85+
for i in 0..self.defragmented_files.len() {
86+
match self.defragmented_files.get(i) {
87+
Some(File::Free) => {
88+
if let Some((index, _)) = self
89+
.defragmented_files
90+
.iter()
91+
.enumerate()
92+
.rfind(|&(j, file)| j > i && matches!(file, File::Taken(_)))
93+
{
94+
self.defragmented_files.swap(i, index);
95+
}
96+
}
97+
Some(File::Taken(_)) | None => {}
98+
}
99+
}
100+
}
101+
102+
fn fragment_files_block(&mut self) {
103+
let mut end_vec = self.files.len();
104+
while let Some((start_index, size)) = Self::detect_block(&self.files, end_vec) {
105+
let mut following_free_file = false;
106+
for (index, file) in self.files.iter().enumerate() {
107+
match file {
108+
File::Free => {
109+
if !following_free_file {
110+
following_free_file = true;
111+
let number_free_files = Self::count_free_files(&self.files, index);
112+
if number_free_files >= size && index < start_index {
113+
for j in 0..size {
114+
self.files.swap(index + j, start_index + j);
115+
}
116+
117+
break;
118+
}
119+
}
120+
}
121+
File::Taken(_) => following_free_file = false,
122+
}
123+
}
124+
end_vec = start_index;
125+
}
126+
}
127+
128+
fn calculate_checksum(files: &[File]) -> u64 {
129+
files
130+
.iter()
131+
.enumerate() // Get position (index) along with each file
132+
.filter_map(|(pos, file)| {
133+
if let File::Taken(id) = file {
134+
// println!("{pos} * {id} [{file:?}]");
135+
Some(pos as u64 * u64::from(*id))
136+
} else {
137+
None
138+
}
139+
})
140+
.sum()
141+
}
142+
}
143+
144+
fn main() {
145+
let message = read_file("crates/day09/input.txt").unwrap();
146+
147+
// --- Part One ---
148+
let mut checker = FileSystem::new(&message);
149+
checker.fragment_files();
150+
println!(
151+
"Part One solution: {:?}",
152+
FileSystem::calculate_checksum(&checker.defragmented_files)
153+
);
154+
// --- Part Two ---
155+
checker.fragment_files_block();
156+
println!(
157+
"Part Two solution: {:?}",
158+
FileSystem::calculate_checksum(&checker.files)
159+
);
160+
}
161+
162+
#[cfg(test)]
163+
mod tests {
164+
use super::*;
165+
166+
#[test]
167+
fn check_exemple() {
168+
let message = read_file("example_input.txt").unwrap();
169+
170+
let mut checker = FileSystem::new(&message);
171+
checker.fragment_files();
172+
checker.fragment_files_block();
173+
let response_part_1 = FileSystem::calculate_checksum(&checker.defragmented_files);
174+
let response_part_2 = FileSystem::calculate_checksum(&checker.files);
175+
176+
assert!(response_part_1 == 1928);
177+
assert!(response_part_2 == 2858);
178+
}
179+
180+
#[test]
181+
fn check_result() {
182+
let message = read_file("input.txt").unwrap();
183+
184+
let mut checker = FileSystem::new(&message);
185+
checker.fragment_files();
186+
checker.fragment_files_block();
187+
let response_part_1 = FileSystem::calculate_checksum(&checker.defragmented_files);
188+
let response_part_2 = FileSystem::calculate_checksum(&checker.files);
189+
190+
assert!(response_part_1 == 6288707484810);
191+
assert!(response_part_2 == 6311837662089);
192+
}
193+
}

0 commit comments

Comments
 (0)