advent_of_code_2021/05/main.cpp
2021-12-05 10:20:45 +01:00

194 lines
4.4 KiB
C++

#include <array>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
class Point {
public:
Point(int x, int y) {
_x = x;
_y = y;
}
~Point() = default;
int getX() const {
return _x;
}
int getY() const {
return _y;
}
void addPoint(const Point &other) {
_x += other.getX();
_y += other.getY();
}
bool operator==(const Point &other) {
return _x == other.getX() && _y == other.getY();
}
bool operator!=(const Point &other) {
return !(*this == other);
}
private:
int _x;
int _y;
};
class Line {
public:
Line(Point a, Point b) : _a(a), _b(b) {}
const Point &getStart() const {
return _a;
}
const Point &getEnd() const {
return _b;
}
bool isHorizontalOrVertical() const {
return _a.getX() == _b.getX() || _a.getY() == _b.getY();
}
Point getDirection() const {
auto x = _b.getX() - _a.getX();
auto y = _b.getY() - _a.getY();
if (abs(x) > abs(y)) {
x /= abs(x);
y /= abs(x);
} else {
x /= abs(y);
y /= abs(y);
}
return Point(x, y);
}
private:
int abs(int x) const {
if (x < 0) {
return -x;
}
return x;
}
Point _a;
Point _b;
};
class OceanFloor {
public:
OceanFloor(int maxX, int maxY, const std::vector<Line> &lines)
: _x(maxX), _y(maxY), _lines(lines) {
floor.resize(_y + 1);
for (int i = 0; i <= _y; i++) {
floor[i].resize(_x + 1);
}
}
~OceanFloor() = default;
void findLines(bool horizontal_or_vertical_only) {
clearFloor();
for (auto &line : _lines) {
if (horizontal_or_vertical_only && !line.isHorizontalOrVertical()) {
continue;
}
auto direction = line.getDirection();
Point start(line.getStart());
while (start != line.getEnd()) {
floor[start.getY()][start.getX()] += 1;
start.addPoint(direction);
}
floor[start.getY()][start.getX()] += 1;
}
}
int findCrossings(int minimum_crossing) {
int result = 0;
for (int i = 0; i <= _y; i++) {
for (int j = 0; j <= _x; j++) {
if (floor[i][j] >= minimum_crossing) {
result++;
}
}
}
return result;
}
private:
void clearFloor() {
for (int i = 0; i <= _y; i++) {
for (int j = 0; j <= _x; j++) {
floor[i][j] = 0;
}
}
}
int _x;
int _y;
const std::vector<Line> &_lines;
std::vector<std::vector<int>> floor;
};
std::pair<std::pair<int, int>, std::vector<Line>>
getLines(const std::string &file_name) {
int maxY = 0;
int maxX = 0;
std::vector<Line> lines{};
std::ifstream file(file_name);
int tmp_x{};
int tmp_y{};
char tmp_char{};
std::string str;
while (std::getline(file, str)) {
std::stringstream ss(str);
ss >> tmp_x;
ss >> tmp_char;
ss >> tmp_y;
Point a(tmp_x, tmp_y);
if (tmp_x > maxX) {
maxX = tmp_x;
}
if (tmp_y > maxY) {
maxY = tmp_y;
}
ss >> tmp_char;
ss >> tmp_char;
ss >> tmp_x;
ss >> tmp_char;
ss >> tmp_y;
Point b(tmp_x, tmp_y);
if (tmp_x > maxX) {
maxX = tmp_x;
}
if (tmp_y > maxY) {
maxY = tmp_y;
}
lines.emplace_back(a, b);
}
return { { maxX, maxY }, lines };
}
int part1(OceanFloor &floor) {
floor.findLines(true);
return floor.findCrossings(2);
}
int part2(OceanFloor &floor) {
floor.findLines(false);
return floor.findCrossings(2);
}
int main(int argc, char **argv) {
if (argc < 2) {
std::cerr << "You must provide input file!" << std::endl;
return 1;
}
auto input = getLines(argv[1]);
OceanFloor floor(input.first.first, input.first.second, input.second);
std::cout
<< "The number of overlapping points without diagonals is \033[91;1m"
<< part1(floor) << "\033[0m." << std::endl;
std::cout << "The number of overlapping points with diagonals is \033[91;1m"
<< part2(floor) << "\033[0m." << std::endl;
return 0;
}