#include #include #include #include #include #include #include class Point : public std::pair { public: Point(uint64_t x, uint64_t y) : std::pair(x, y) {} int getHeight(const std::vector> &heights) const { return heights[first][second]; } uint64_t getX() const { return first; } uint64_t getY() const { return second; } }; std::vector> getHeights(const std::string &file_name) { std::vector> heights; std::ifstream file(file_name); std::string str; while (std::getline(file, str)) { heights.emplace_back(); for (auto &height : str) { heights.back().push_back(height - '0'); } } return heights; } std::vector getLowPoints(const std::vector> &heights) { std::vector low_points{}; for (size_t i = 1; i < heights.size() - 1; i++) { for (size_t j = 1; j < heights[i].size() - 1; j++) { auto &point = heights[i][j]; if (heights[i][j - 1] > point && heights[i][j + 1] > point && heights[i - 1][j] > point && heights[i + 1][j] > point) { low_points.emplace_back(i, j); } } } for (size_t i = 1; i < heights[0].size() - 1; i++) { if (heights[0][i - 1] > heights[0][i] && heights[0][i + 1] > heights[0][i] && heights[1][i] > heights[0][i]) { low_points.emplace_back(0, i); } if (heights[heights.size() - 1][i - 1] > heights[heights.size() - 1][i] && heights[heights.size() - 1][i + 1] > heights[heights.size() - 1][i] && heights[heights.size() - 2][i] > heights[heights.size() - 1][i]) { low_points.emplace_back(heights.size() - 1, i); } } for (size_t i = 1; i < heights.size() - 1; i++) { if (heights[i - 1][0] > heights[i][0] && heights[i + 1][0] > heights[i][0] && heights[i][1] > heights[i][0]) { low_points.emplace_back(i, 0); } if (heights[i - 1][heights[0].size() - 1] > heights[i][heights[0].size() - 1] && heights[i + 1][heights[0].size() - 1] > heights[i][heights[0].size() - 1] && heights[i][heights[0].size() - 2] > heights[i][heights[0].size() - 1]) { low_points.emplace_back(i, heights[0].size() - 1); } } if (heights[0][1] > heights[0][0] && heights[1][0] > heights[0][0]) { low_points.emplace_back(0, 0); } if (heights[heights.size() - 1][1] > heights[heights.size() - 1][0] && heights[heights.size() - 2][0] > heights[heights.size() - 1][0]) { low_points.emplace_back(heights.size() - 1, 0); } if (heights[0][heights[0].size() - 2] > heights[0][heights[0].size() - 1] && heights[1][heights[0].size() - 1] > heights[0][heights[0].size() - 1]) { low_points.emplace_back(0, heights[0].size() - 1); } if (heights[heights.size() - 1][heights[0].size() - 2] > heights[heights.size() - 1][heights[0].size() - 1] && heights[heights.size() - 2][heights[0].size() - 1] > heights[heights.size() - 1][heights[0].size() - 1]) { low_points.emplace_back(heights.size() - 1, heights[0].size() - 1); } return low_points; } std::vector> getBasins(const std::vector> &heights, const std::vector &low_points) { std::vector> result{}; for (auto &point : low_points) { std::set basin{}; std::deque basin_deque{}; basin_deque.push_back(point); while (basin_deque.size() != 0) { const auto &working_point = basin_deque.front(); basin.insert(working_point); for (int i = -1; i < 2; i += 1) { for (int j = -1; j < 2; j += 1) { if ((i != 0 && j != 0) || (i == 0 && j == 0)) { continue; } auto new_point = Point(working_point.getX() + i, working_point.getY() + j); if (new_point.getX() == (uint64_t)-1 || new_point.getX() >= heights.size()) { continue; } if (new_point.getY() == (uint64_t)-1 || new_point.getY() >= heights[0].size()) { continue; } if (basin.find(new_point) != basin.end()) { continue; } if (new_point.getHeight(heights) == 9) { continue; } basin_deque.push_back(new_point); } } basin_deque.pop_front(); } result.push_back(std::move(basin)); } return result; } uint64_t part1(const std::vector> &heights, const std::vector &low_points) { uint64_t score = 0; for (const auto &point : low_points) { score += point.getHeight(heights) + 1; } return score; } uint64_t part2(const std::vector> &heights, const std::vector &low_points) { auto basins = getBasins(heights, low_points); std::vector sizes{}; for (auto &basin : basins) { sizes.push_back(basin.size()); } std::sort(sizes.begin(), sizes.end()); std::reverse(sizes.begin(), sizes.end()); return sizes[0] * sizes[1] * sizes[2]; } int main(int argc, char **argv) { if (argc < 2) { std::cerr << "You must provide input file!" << std::endl; return 1; } auto heights = getHeights(argv[1]); auto low_points = getLowPoints(heights); std::cout << "There sum of low points risks is \033[91;1m" << part1(heights, low_points) << "\033[0m." << std::endl; std::cout << "There product of three largest basins is \033[91;1m" << part2(heights, low_points) << "\033[0m." << std::endl; return 0; }