Untitled

 avatar
unknown
c_cpp
2 years ago
2.9 kB
10
Indexable
#include <cassert>
#include <fstream>
#include <iostream>
#include <numeric>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>

using namespace std;

class Decoder {
private:
  vector<string> encoded_strings;
  int rows, cols;
  unordered_map<int, vector<int>> gears;
  int f(int r, int c) { return c + r * cols; }

public:
  Decoder(fstream file) {
    if (file.is_open()) {
      string line;
      while (getline(file, line)) {
        encoded_strings.push_back(line);
      }
      file.close();
    }
    rows = encoded_strings.size();
    cols = encoded_strings.front().size();
  }

  Decoder(const string file_name) : Decoder(fstream(file_name, ios::in)) {}

  ~Decoder() {}

  vector<tuple<int, int, int>> get_num_metadata(string &s) {
    vector<tuple<int, int, int>> results;
    int current_num = 0, start_idx = -1;

    for (int idx = 0; idx <= s.size(); ++idx) {
      if (idx < s.size() && isdigit(s[idx])) {
        current_num = current_num * 10 + (s[idx] - '0');
        if (start_idx == -1)
          start_idx = idx;
      } else if (start_idx != -1) {
        results.emplace_back(current_num, start_idx, idx - start_idx);
        current_num = 0;
        start_idx = -1;
      }
    }
    return results;
  }

  bool within_bounds(int row, int col) {
    return 0 <= row and row < rows and 0 <= col and col < cols;
  }

  bool is_valid_symbol(int r, int c) {
    return within_bounds(r, c) ? encoded_strings[r][c] == '*' : false;
  }

  optional<int> is_valid(int row, int start_col, int end_col) {
    for (int r = row - 1; r <= row + 1; r++) {
      for (int c = start_col - 1; c <= end_col + 1; c++) {
        if ((r != row || c < start_col || c > end_col) &&
            is_valid_symbol(r, c)) {
          return f(r, c);
        }
      }
    }
    return nullopt;
  }

  int get_total() {
    vector<int> numbers;
    int row = 0;
    for (auto encoded_string : encoded_strings) {
      // on each line, get the numbers
      vector<tuple<int, int, int>> num_metadata =
          get_num_metadata(encoded_string);
      // check if a number is bordered by a symbol (i.e., not period nor digits)
      for (auto &[number, start_idx, length] : num_metadata) {
        auto loc = is_valid(row, start_idx, start_idx + length - 1);
        if (loc.has_value()) {
          gears[loc.value()].push_back(number);
        }
      }
      row++;
    }
    for (auto &[_, gear_list] : gears) {
      if (gear_list.size() == 2) {
        numbers.push_back(gear_list.front() * gear_list.back());
      }
    }
    return accumulate(numbers.begin(), numbers.end(), 0);
  }
};

int main(int argc, char *argv[]) {
  if (argc < 2) {
    cerr << "Usage: " << argv[0] << " <file_name>" << std::endl;
    return 1;
  }

  string file_name = argv[1];
  cout << Decoder(file_name).get_total() << endl;

  return 0;
}
Editor is loading...
Leave a Comment