Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <array>
- #include <fstream>
- #include <functional>
- #include <iostream>
- #include <string>
- #include <vector>
- bool issymbol(char c)
- {
- return !std::isdigit(c) && c != '.';
- }
- bool isgear(char c)
- {
- return c == '*';
- }
- /**
- * Returns if row is in the interval [0, max_row) and col is in the
- * interval [0, max_col).
- */
- bool is_inbounds(int row, int col, int max_row, int max_col)
- {
- return row >= 0 && row < max_row
- && col >= 0 && col < max_col;
- }
- /**
- * Sets adjacent numbers in nums_field to the given bool value in set_to.
- *
- * Returns number of adjacent numbers (not digits) that were set.
- */
- int set_adjacents(const std::vector<std::string> &strs, std::vector<std::vector<bool>> &nums_field, bool set_to, int row, int col)
- {
- int nadjs_set = 0;
- /* Adding these to row/column will give all possible adjacent positions. */
- constexpr std::array<std::array<int, 2>, 8> adjacents { {
- { -1, -1 },
- { -1, 0 },
- { 0, -1 },
- { -1, 1 },
- { 1, -1 },
- { 1, 0 },
- { 0, 1 },
- { 1, 1 },
- } };
- for (const auto &a : adjacents) {
- int adj_row = row + a[0];
- int adj_col = col + a[1];
- int max_row = static_cast<int>(strs.size());
- int max_col = static_cast<int>(strs[row].size());
- if (is_inbounds(adj_row, adj_col, max_row, max_col)) {
- /* Check if the number has already been marked. */
- if (nums_field[adj_row][adj_col] == set_to) {
- continue;
- }
- if (std::isdigit(strs[adj_row][adj_col])) {
- nadjs_set++;
- /* Find the start of the first digit of the found number. */
- int first_digit_col = adj_col;
- while (is_inbounds(adj_row, first_digit_col - 1, max_row, max_col)
- && std::isdigit(strs[adj_row][first_digit_col - 1])) {
- first_digit_col--;
- }
- /* Mark all the digits in number as found. */
- for (int i = first_digit_col; i < max_col && std::isdigit(strs[adj_row][i]); i++) {
- nums_field[adj_row][i] = set_to;
- }
- }
- }
- }
- return nadjs_set;
- }
- /**
- * Returns the value of all numbers in strs inidicated by nums_field using the
- * calculation from the reducer function fn to get the result.
- */
- int reduce(const std::vector<std::string> &strs, const std::vector<std::vector<bool>> &nums_field, std::function<int(int, int)> fn, int initial_value)
- {
- int result = initial_value;
- for (size_t i = 0; i < nums_field.size(); i++) {
- size_t num_start = 0;
- size_t num_size = 0;
- for (size_t j = 0; j < nums_field[i].size(); j++) {
- if (nums_field[i][j]) {
- if (num_size == 0) {
- num_start = j;
- }
- num_size++;
- } else if (!nums_field[i][j] && num_size != 0) {
- result = fn(result, std::stoi(strs[i].substr(num_start, num_size)));
- num_start = 0;
- num_size = 0;
- } else {
- num_start = 0;
- num_size = 0;
- }
- }
- /* If the last column of a row is a digit it has not yet been added to
- * result, so do it now. */
- if (num_size != 0) {
- result = fn(result, std::stoi(strs[i].substr(num_start, num_size)));
- }
- }
- return result;
- }
- int main()
- {
- std::ifstream input("../input.txt");
- if (!input.is_open()) {
- perror("Error");
- exit(EXIT_FAILURE);
- }
- int result_p1 = 0; /* Part 1 answer. */
- int result_p2 = 0; /* Part 2 answer. */
- /* Indicates valid digit positions. */
- std::vector<std::vector<bool>> nums_field_p1 {};
- std::vector<std::vector<bool>> nums_field_p2 {};
- std::vector<std::string> lines {};
- std::string line("");
- while (std::getline(input, line)) {
- lines.push_back(line);
- nums_field_p1.push_back(std::vector<bool>(line.size(), false));
- nums_field_p2.push_back(std::vector<bool>(line.size(), false));
- }
- /* Find symbol/gear and mark all adjacent numbers as valid. */
- for (size_t i = 0; i < lines.size(); i++) {
- for (size_t j = 0; j < lines[i].size(); j++) {
- /* Part 1 */
- if (issymbol(lines[i][j])) {
- set_adjacents(lines, nums_field_p1, true, static_cast<int>(i), static_cast<int>(j));
- }
- /* Part 2 */
- int num_adjs = 0;
- if (isgear(lines[i][j])) {
- num_adjs = set_adjacents(lines, nums_field_p2, true, static_cast<int>(i), static_cast<int>(j));
- }
- if (num_adjs == 2) {
- result_p2 += reduce(
- lines, nums_field_p2, [](int a, int b) {
- return a * b;
- },
- 1);
- }
- /* Reset adjacent numbers for gears so they are not used in future
- * result calculations. */
- set_adjacents(lines, nums_field_p2, false, static_cast<int>(i), static_cast<int>(j));
- }
- }
- result_p1 = reduce(
- lines, nums_field_p1, [](int a, int b) {
- return a + b;
- },
- 0);
- std::cout << "Part 1: " << result_p1 << "\n";
- std::cout << "Part 2: " << result_p2 << "\n";
- return EXIT_SUCCESS;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement