Skip to content

Commit 11a0ab1

Browse files
committed
Started Day 9
1 parent 2294d26 commit 11a0ab1

File tree

10 files changed

+380
-6
lines changed

10 files changed

+380
-6
lines changed

include/advent_of_code/day_7.hxx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include <algorithm>
88
#include <sstream>
99
#include <exception>
10-
#include <string>
1110

1211
#include "spdlog/spdlog.h"
1312

include/advent_of_code/day_9.hxx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <fstream>
2+
#include <memory>
3+
#include <string>
4+
#include <filesystem>
5+
#include <sstream>
6+
#include <deque>
7+
#include <numeric>
8+
#include <optional>
9+
#include <exception>
10+
#include <ranges>
11+
#include <algorithm>
12+
13+
#include "spdlog/spdlog.h"
14+
15+
namespace AdventOfCode24::Day9 {
16+
typedef std::unordered_map<int, std::deque<int>> layout;
17+
class DiskMap {
18+
private:
19+
layout disk_map;
20+
const int size{-1};
21+
int last_block_id{-1};
22+
int last_block_index{-1};
23+
std::optional<int> get_first_empty(const int& size) const;
24+
public:
25+
DiskMap(
26+
const layout& disk_map,
27+
const int size,
28+
const int last_block_id,
29+
const int last_block_index
30+
) : disk_map(disk_map), size(size), last_block_id(last_block_id), last_block_index(last_block_index) {}
31+
DiskMap() {};
32+
void print() const;
33+
bool block_cleanup_iteration();
34+
std::optional<int> file_cleanup_iteration(const int& target_block_index);
35+
layout getMap() const {return disk_map;}
36+
long long checksum() const;
37+
};
38+
DiskMap get_disk_map(const std::string& entry);
39+
DiskMap cleanup_disk(const std::filesystem::path& input_fil, bool file_move, bool print_iterations=false);
40+
};

solutions/data/day_9.txt

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

solutions/day_8.cxx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
#include <filesystem>
2-
#include <iostream>
3-
#include <numeric>
42
#include <string>
5-
#include <set>
63
#include "spdlog/spdlog.h"
74

85
#include "advent_of_code/day_8.hxx"

solutions/day_9.cxx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include <filesystem>
2+
#include <string>
3+
#include "spdlog/spdlog.h"
4+
5+
#include "advent_of_code/day_9.hxx"
6+
7+
using namespace AdventOfCode24::Day9;
8+
9+
int main(int argc, char** argv) {
10+
if(argc != 2) {
11+
spdlog::error("Expected input data file!");
12+
return 1;
13+
}
14+
15+
spdlog::set_level(spdlog::level::info);
16+
17+
const std::filesystem::path input_file{argv[1]};
18+
if(!std::filesystem::exists(input_file)) {
19+
throw std::runtime_error("File " + input_file.string() + " does not exist!");
20+
}
21+
22+
//const DiskMap cleaned_disk{cleanup_disk(input_file, false)};
23+
//cleaned_disk.print();
24+
//const long long checksum{cleaned_disk.checksum()};
25+
const DiskMap cleaned_disk_file_move{cleanup_disk(input_file, true)};
26+
const long long checksum_file_move{cleaned_disk_file_move.checksum()};
27+
28+
//spdlog::info("For file '" + input_file.string() + "' the disk check sum is " + std::to_string(checksum));
29+
cleaned_disk_file_move.print();
30+
spdlog::info("For file '" + input_file.string() + "' the disk check sum using file move is " + std::to_string(checksum_file_move));
31+
32+
}

src/day_9.cxx

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
#include "advent_of_code/day_9.hxx"
2+
#include "spdlog/spdlog.h"
3+
#include <algorithm>
4+
#include <deque>
5+
#include <exception>
6+
#include <iostream>
7+
#include <memory>
8+
#include <numeric>
9+
#include <optional>
10+
#include <stdexcept>
11+
#include <string>
12+
#include <unordered_map>
13+
14+
namespace AdventOfCode24::Day9 {
15+
DiskMap get_disk_map(const std::string& entry) {
16+
if(entry.empty()) {
17+
throw std::runtime_error("Cannot process empty string.");
18+
}
19+
std::istringstream isstr;
20+
isstr.str(entry);
21+
int number{-1};
22+
int line_pos{0};
23+
int block_index{0};
24+
int index{0};
25+
layout disk_map;
26+
27+
for (const char& number_str : entry) {
28+
try {
29+
number = std::stoi(std::string(1, number_str));
30+
} catch(std::exception& e) {
31+
throw std::runtime_error("Could not convert value " + std::string(1, number_str));
32+
}
33+
34+
if(line_pos % 2 == 1) {
35+
disk_map.emplace(-1, std::deque<int>());
36+
for(int n{0}; n < number; ++n) {
37+
disk_map.at(-1).push_back(index);
38+
index++;
39+
}
40+
} else {
41+
disk_map.emplace(block_index, std::deque<int>());
42+
for(int i{0}; i < number; ++i) {
43+
disk_map.at(block_index).push_back(index);
44+
index++;
45+
}
46+
block_index++;
47+
}
48+
49+
line_pos++;
50+
}
51+
52+
const int last_block_index{static_cast<int>(disk_map.at(block_index - 1).size()) - 1};
53+
54+
return DiskMap(disk_map, index, block_index - 1, last_block_index);
55+
}
56+
57+
void DiskMap::print() const{
58+
std::vector<std::string> output_vec(size, "X");
59+
60+
for(const auto& map_entry : disk_map) {
61+
for(const int& pos : map_entry.second) {
62+
if(pos >= size) {
63+
throw std::runtime_error(
64+
"Cannot print map, recorded position " + std::to_string(pos) +
65+
" is not within specified map size " + std::to_string(size));
66+
}
67+
output_vec[pos] = ((map_entry.first == -1) ? "." : std::to_string(map_entry.first));
68+
}
69+
}
70+
71+
for(const std::string& output : output_vec) {
72+
std::cout << output;
73+
}
74+
75+
std::cout << std::endl;
76+
}
77+
78+
bool DiskMap::block_cleanup_iteration() {
79+
layout disk_layout{disk_map};
80+
81+
if(disk_layout.at(-1).empty()) return {};
82+
83+
const int first_empty = disk_layout.at(-1)[0];
84+
const int current_pos = disk_layout.at(last_block_id)[last_block_index];
85+
86+
if(current_pos < first_empty) return false;
87+
88+
disk_layout.at(last_block_id)[last_block_index] = first_empty;
89+
disk_layout.at(-1).pop_front();
90+
disk_layout.at(-1).push_back(current_pos);
91+
92+
int new_last_block{-1};
93+
int new_last_index{-1};
94+
95+
if(last_block_index < 1) {
96+
new_last_block = last_block_id - 1;
97+
if(new_last_block < 0) return false;
98+
new_last_index = disk_layout.at(new_last_block).size() - 1;
99+
} else {
100+
new_last_block = last_block_id;
101+
new_last_index = last_block_index - 1;
102+
}
103+
104+
last_block_index = new_last_index;
105+
last_block_id = new_last_block;
106+
disk_map = disk_layout;
107+
108+
return true;
109+
}
110+
111+
std::optional<int> DiskMap::get_first_empty(const int& size) const {
112+
auto find_empties = disk_map.find(-1);
113+
114+
if(find_empties == disk_map.end() || disk_map.at(-1).empty()) {
115+
return {};
116+
}
117+
118+
for(int i{0}; i < disk_map.at(-1).size(); ++i) {
119+
int offset{0};
120+
while(disk_map.at(-1)[i + offset + 1] - disk_map.at(-1)[i + offset] == 1) {
121+
offset++;
122+
}
123+
if(offset + 1 >= size) return i;
124+
}
125+
126+
return {};
127+
}
128+
129+
std::optional<int> DiskMap::file_cleanup_iteration(const int& block_index) {
130+
if(block_index < 0) {
131+
spdlog::error("Block index < 0");
132+
return {};
133+
}
134+
if(disk_map.find(-1) == disk_map.end()) {
135+
spdlog::error("No blank space found!");
136+
return {};
137+
}
138+
139+
const size_t size{disk_map.at(block_index).size()};
140+
std::sort(disk_map.at(-1).begin(), disk_map.at(-1).end());
141+
142+
const std::optional<int> check_for_empty{get_first_empty(size)};
143+
144+
if(!check_for_empty.has_value()) {
145+
spdlog::warn("Could not find any empty space to accomodate file " + std::to_string(block_index) + " of size " + std::to_string(size));
146+
return block_index - 1;
147+
}
148+
149+
const int first_empty_index{disk_map.at(-1)[check_for_empty.value()]};
150+
151+
std::deque<int> block_positions{disk_map.at(block_index)};
152+
153+
if(block_positions.empty()) {
154+
spdlog::warn("Block " + std::to_string(block_index) + " is empty.");
155+
return block_index - 1;
156+
}
157+
158+
std::sort(block_positions.begin(), block_positions.end());
159+
160+
if(block_positions[0] <= first_empty_index) {
161+
spdlog::info("Block " + std::to_string(block_index) + " already at optimal position.");
162+
return block_index - 1;
163+
}
164+
165+
disk_map.at(block_index).clear();
166+
167+
for(int i{0}; i < size; ++i) {
168+
disk_map.at(block_index).push_back(first_empty_index + i);
169+
170+
disk_map.at(-1).erase(std::remove(disk_map.at(-1).begin(), disk_map.at(-1).end(), first_empty_index + i), disk_map.at(-1).end());
171+
}
172+
173+
for(const int& block_pos : block_positions) {
174+
disk_map.at(-1).push_back(block_pos);
175+
}
176+
177+
return block_index - 1;
178+
}
179+
180+
DiskMap cleanup_disk(const std::filesystem::path& input_file, bool file_move, bool print_iterations) {
181+
std::ifstream read_in(input_file, std::ios::in);
182+
std::string line;
183+
184+
std::getline(read_in, line);
185+
186+
DiskMap disk_map{get_disk_map(line)};
187+
188+
if(file_move) {
189+
auto max_block = std::max_element(disk_map.getMap().begin(), disk_map.getMap().end(), [](const auto& a, const auto& b){return a.first < b.first;});
190+
if(max_block == disk_map.getMap().end()) {
191+
throw std::runtime_error("Failed to get maximum block index");
192+
}
193+
194+
std::optional<int> block_index = {max_block->first};
195+
196+
while(block_index.has_value()) {
197+
block_index = disk_map.file_cleanup_iteration(block_index.value());
198+
if(print_iterations) disk_map.print();
199+
}
200+
201+
} else {
202+
while(!file_move && disk_map.block_cleanup_iteration()) {
203+
if(print_iterations) disk_map.print();
204+
}
205+
}
206+
207+
return disk_map;
208+
}
209+
210+
long long DiskMap::checksum() const {
211+
return std::accumulate(
212+
disk_map.begin(),
213+
disk_map.end(),
214+
0LL,
215+
[](const long long& total, const std::pair<int, std::deque<int>>& a) {
216+
// Do not include space which has index -1
217+
if(a.first < 0) return total;
218+
219+
return total + a.first * std::accumulate(
220+
a.second.begin(),
221+
a.second.end(),
222+
0LL
223+
);
224+
}
225+
);
226+
}
227+
};

tests/data/day_9_1.txt

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

tests/data/day_9_2.txt

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

tests/test_day_8.cxx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#include <gtest/gtest.h>
2-
#include <string>
32
#include <unordered_set>
43
#include "advent_of_code/day_8.hxx"
5-
#include "spdlog/common.h"
64
#include "spdlog/spdlog.h"
75

86
using namespace AdventOfCode24::Day8;

0 commit comments

Comments
 (0)