diff --git a/day12/day12.cpp b/day12/day12.cpp new file mode 100644 index 0000000..04e3842 --- /dev/null +++ b/day12/day12.cpp @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include +#include + +constexpr int NUM_DIRECTIONS = 4; +enum CardinalDirection { NORTH = 0, EAST = 1, SOUTH = 2, WEST = 3 }; + +class Ship { + public: + Ship(CardinalDirection direction, std::pair position) : direction(direction), position(position) { + } + + const std::pair &getPosition() const { + return this->position; + } + + CardinalDirection getDirection() const { + return direction; + } + + void setDirection(CardinalDirection direction) { + this->direction = direction; + } + + void move(int value) { + this->move(value, this->direction); + } + + void move(int value, CardinalDirection direction) { + int delta = (direction == SOUTH || direction == EAST) ? -value : value; + if (direction == NORTH || direction == SOUTH) { + this->position.second += delta; + } else { + this->position.first += delta; + } + } + + void turnLeft(int deg) { + this->addToDirection(3 * deg / 90); + } + + void turnRight(int deg) { + // Three lefts make a right - easier than dealing with negative mods + this->addToDirection(deg / 90); + } + + private: + void addToDirection(int delta) { + this->direction = static_cast((this->direction + delta) % NUM_DIRECTIONS); + } + + CardinalDirection direction; + std::pair position; +}; + +std::vector readInput(const std::string &filename) { + std::vector input; + std::string line; + std::ifstream file(filename); + while (std::getline(file, line)) { + input.push_back(line); + } + + return input; +} + +std::vector> parseInput(const std::vector &input) { + std::vector> parsedInput; + parsedInput.reserve(input.size()); + for (std::string_view line : input) { + char direction = line.at(0); + auto rawMagnitude = line.substr(1); + int magnitude; + auto parseResult = std::from_chars(rawMagnitude.data(), rawMagnitude.data() + rawMagnitude.size(), magnitude); + if (parseResult.ec == std::errc::invalid_argument) { + throw std::invalid_argument("Invalid input"); + } + + parsedInput.push_back(std::pair(direction, magnitude)); + } + + return parsedInput; +} + +void makeMove(Ship &ship, const std::pair &move) { + char directive = move.first; + int magnitude = move.second; + switch (directive) { + case 'L': + ship.turnLeft(magnitude); + break; + case 'R': + ship.turnRight(magnitude); + break; + case 'N': + ship.move(magnitude, NORTH); + break; + case 'S': + ship.move(magnitude, SOUTH); + break; + case 'E': + ship.move(magnitude, EAST); + break; + case 'W': + ship.move(magnitude, WEST); + break; + case 'F': + ship.move(magnitude); + break; + default: + throw std::invalid_argument("Invalid move direction"); + } +} + +int part1(const std::vector> &input) { + Ship ship(EAST, std::pair(0, 0)); + for (auto &move : input) { + makeMove(ship, move); + } + + return abs(ship.getPosition().first) + abs(ship.getPosition().second); +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + std::cerr << argv[0] << " " << std::endl; + return 1; + } + + auto input = readInput(argv[1]); + auto parsedInput = parseInput(input); + + std::cout << part1(parsedInput) << std::endl; +}