advent_of_code_2021/15/main.cpp
2021-12-16 09:50:13 +01:00

157 lines
4.3 KiB
C++

#include <algorithm>
#include <deque>
#include <fstream>
#include <iostream>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using Point = std::pair<uint64_t, uint64_t>;
class Position {
public:
Position(uint64_t value) : _value(value) {}
bool updateDist(uint64_t from_dist) {
auto new_dist = from_dist + _value;
if (new_dist < _dist) {
_dist = new_dist;
return true;
}
return false;
}
uint64_t getDist() {
return _dist;
}
void setDist(uint64_t dist) {
_dist = dist;
}
uint64_t getValue() {
return _value;
}
private:
uint64_t _dist = -1;
uint64_t _value = 0;
};
std::vector<std::vector<Position>> getMap(const std::string &file_name,
bool growing = false) {
std::vector<std::vector<Position>> map;
std::ifstream file(file_name);
std::string str;
while (std::getline(file, str)) {
map.emplace_back();
for (auto &c : str) {
map.back().emplace_back(c - '0');
}
}
map[0][0].setDist(0);
auto original_height = map.size();
auto original_width = map[0].size();
if (growing) {
for (auto &line : map) {
for (int i = 1; i < 5; i++) {
for (size_t j = 0; j < original_width; j++) {
auto new_val = line[j].getValue() + i;
if (new_val > 9) {
new_val -= 9;
}
line.emplace_back(new_val);
}
}
}
for (int i = 1; i < 5; i++) {
for (size_t j = 0; j < original_height; j++) {
map.emplace_back();
for (auto &position : map[j]) {
auto new_val = position.getValue() + i;
if (new_val > 9) {
new_val -= 9;
}
map.back().emplace_back(new_val);
}
}
}
}
return map;
}
std::vector<Point> getPointsNoDiag(const Point &point, size_t max_x,
size_t max_y) {
std::vector<Point> result{};
if (point.first > 0) {
result.emplace_back(point.first - 1, point.second);
}
if (point.first < max_x) {
result.emplace_back(point.first + 1, point.second);
}
if (point.second > 0) {
result.emplace_back(point.first, point.second - 1);
}
if (point.second < max_y) {
result.emplace_back(point.first, point.second + 1);
}
return result;
}
Position &pointToMap(std::vector<std::vector<Position>> &map,
const Point &point) {
return map[point.second][point.first];
}
uint64_t findSafestPath(std::vector<std::vector<Position>> &map) {
std::deque<Point> to_process = { { 0, 0 } };
while (!to_process.empty()) {
auto point = to_process.front();
auto &map_entry = pointToMap(map, point);
auto new_points =
getPointsNoDiag(point, map[0].size() - 1, map.size() - 1);
for (auto &new_point : new_points) {
auto &new_map = pointToMap(map, new_point);
if (new_map.updateDist(map_entry.getDist())) {
to_process.push_back(new_point);
}
}
to_process.pop_front();
}
return map.back().back().getDist();
}
uint64_t part1(const std::string &map_path) {
auto map = getMap(map_path);
return findSafestPath(map);
}
uint64_t part2(const std::string &map_path) {
auto map = getMap(map_path, true);
return findSafestPath(map);
}
void printMap(std::vector<std::vector<Position>> &map) {
for (auto &line : map) {
for (auto &pos : line) {
std::cout << pos.getValue();
}
std::cout << std::endl;
}
std::cout << std::endl;
}
int main(int argc, char **argv) {
if (argc < 2) {
std::cerr << "You must provide input file!" << std::endl;
return 1;
}
std::cout << "The least risky path has a risk of \033[91;1m"
<< part1(argv[1]) << "\033[0m." << std::endl;
std::cout
<< "The least risky path in the entire cove has a risk of \033[91;1m"
<< part2(argv[1]) << "\033[0m." << std::endl;
return 0;
}