diff --git a/2019/CMakeLists.txt b/2019/CMakeLists.txt index 1ee4f27..d92a766 100644 --- a/2019/CMakeLists.txt +++ b/2019/CMakeLists.txt @@ -5,7 +5,7 @@ project(aoc2019) find_package(GTest REQUIRED) file(GLOB DAYS_FILES src/day*.cpp) -add_library(AoCSolutions src/implementations.cpp "${DAYS_FILES}") +add_library(AoCSolutions src/implementations.cpp "${DAYS_FILES}" src/point.hpp src/utils.cpp src/utils.hpp) target_compile_features(AoCSolutions PUBLIC cxx_std_17) add_executable(runner src/runner.cpp) diff --git a/2019/src/day03.cpp b/2019/src/day03.cpp index dfc74de..e895b53 100644 --- a/2019/src/day03.cpp +++ b/2019/src/day03.cpp @@ -1,10 +1,69 @@ +#include +#include #include +#include +#include +#include +#include +#include #include "days.hpp" +#include "point.hpp" +#include "utils.hpp" + +namespace { + typedef aoc2019::Point point_t; + + const std::unordered_map DIRECTION_MAP = { + {'U', {0, -1}}, + {'D', {0, 1}}, + {'L', {-1, 0}}, + {'R', {1, 0}}, + }; + + std::unordered_set get_points(std::string_view line) { + std::unordered_set points{}; + point_t pos = {}; + + for (auto entry = aoc2019::strtok(line); !line.empty() || !entry.empty(); entry = aoc2019::strtok(line)) { + const auto dir = DIRECTION_MAP.at(entry[0]); + std::size_t amount = 0; + std::from_chars(entry.data() + 1, entry.data() + entry.size(), amount); + assert(amount > 0 && "Must have some valid direction"); + + for (std::size_t i = 0; i < amount; ++i) { + pos += dir; + points.insert(pos); + } + } + + return points; + } + + std::pair, std::unordered_set> read_input(std::istream& input) { + std::string buffer; + std::getline(input, buffer); + auto a = get_points(buffer); + std::getline(input, buffer); + auto b = get_points(buffer); + + return { std::move(a), std::move(b) }; + } +} void aoc2019::day03_part1(std::istream &input, std::ostream &output) { - output << "Not implemented\n"; + auto [a, b] = read_input(input); + + int best = std::numeric_limits::max(); + + for (const auto& point : a) { + if (b.count(point) && point.l1() < best) { + best = point.l1(); + } + } + + output << best << std::endl; } void aoc2019::day03_part2(std::istream &input, std::ostream &output) { - output << "Not implemented\n"; + output << "Not implemented\n"; } diff --git a/2019/src/point.hpp b/2019/src/point.hpp new file mode 100644 index 0000000..f82bbad --- /dev/null +++ b/2019/src/point.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include "utils.hpp" + +namespace aoc2019 { + template + class Point : public std::array { + public: + constexpr Point& operator +=(Point other) { + for (std::size_t i = 0; i < L; ++i) { + (*this)[i] += other[i]; + } + return *this; + } + + constexpr Point operator+(Point other) const { + auto result = *this; + result += other; + + return result; + } + + constexpr Point& operator -=(Point other) { + for (std::size_t i = 0; i < L; ++i) { + (*this)[i] -= other[i]; + } + + return *this; + } + + constexpr Point operator-(Point other) const { + auto result = *this; + result -= other; + + return result; + } + + constexpr T l1() const { + T result = 0; + for (auto e : *this) { + result += std::abs(e); + } + + return result; + } + }; +} + +namespace std { + // Make point usable with unordered collections. + template struct hash> { + size_t operator()(const aoc2019::Point &o) const { + size_t seed = 0; + for (auto i : o) { + aoc2019::combine_hash(seed, i); + } + return seed; + } + }; +} diff --git a/2019/src/utils.cpp b/2019/src/utils.cpp new file mode 100644 index 0000000..446e303 --- /dev/null +++ b/2019/src/utils.cpp @@ -0,0 +1,12 @@ +#include "utils.hpp" + +std::string_view aoc2019::strtok(std::string_view &str, char token) { + auto next_delim = str.find(token); + auto next = str.substr(0, next_delim); + if (next_delim == std::string_view::npos) { + str = {}; + } else { + str = str.substr(next_delim + 1); + } + return next; +} diff --git a/2019/src/utils.hpp b/2019/src/utils.hpp new file mode 100644 index 0000000..8bea634 --- /dev/null +++ b/2019/src/utils.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +namespace aoc2019 { + + template + void combine_hash(std::size_t& seed, const T& o) { + // Algorithm taken from boost::combine_hash. + std::hash hash{}; + seed ^= hash(o) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + + std::string_view strtok(std::string_view &str, char token = ','); +} diff --git a/2019/tests/samples/03-1-1.in b/2019/tests/samples/03-1-1.in new file mode 100644 index 0000000..620a05e --- /dev/null +++ b/2019/tests/samples/03-1-1.in @@ -0,0 +1,2 @@ +R75,D30,R83,U83,L12,D49,R71,U7,L72 +U62,R66,U55,R34,D71,R55,D58,R83 diff --git a/2019/tests/samples/03-1-1.out b/2019/tests/samples/03-1-1.out new file mode 100644 index 0000000..3f7d191 --- /dev/null +++ b/2019/tests/samples/03-1-1.out @@ -0,0 +1 @@ +159 diff --git a/2019/tests/samples/03-1-2.in b/2019/tests/samples/03-1-2.in new file mode 100644 index 0000000..4f3a2a4 --- /dev/null +++ b/2019/tests/samples/03-1-2.in @@ -0,0 +1,2 @@ +R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51 +U98,R91,D20,R16,D67,R40,U7,R15,U6,R7 diff --git a/2019/tests/samples/03-1-2.out b/2019/tests/samples/03-1-2.out new file mode 100644 index 0000000..c8b255f --- /dev/null +++ b/2019/tests/samples/03-1-2.out @@ -0,0 +1 @@ +135