diff --git a/12/.gitignore b/12/.gitignore new file mode 100644 index 0000000..15f026f --- /dev/null +++ b/12/.gitignore @@ -0,0 +1 @@ +day12 diff --git a/12/README.md b/12/README.md new file mode 100644 index 0000000..f8ef181 --- /dev/null +++ b/12/README.md @@ -0,0 +1,9 @@ +# [Day 12](https://adventofcode.com/2022/day/12) +:gift::gift::gift::gift::gift::gift::gift::gift::gift::gift::gift::gift: + +Today's language: **C++** + +```shell +g++ -std=c++20 day12.cpp -o day12 +./day12 +``` diff --git a/12/day12.cpp b/12/day12.cpp new file mode 100644 index 0000000..3e2fafa --- /dev/null +++ b/12/day12.cpp @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include +#include +#include + + +constexpr char UP = (1 << 1); +constexpr char DOWN = (1 << 2); +constexpr char LEFT = (1 << 3); +constexpr char RIGHT = (1 << 4); + +using ssize = std::string::size_type; + +struct XY { + ssize x; + ssize y; + bool operator==(const XY& other) const { return this->x == other.x && this->y == other.y; }; + struct Hash { + size_t operator()(const XY& xy) const { + return (std::hash()(xy.x) << 1) ^ (std::hash()(xy.y)); + } + }; +}; + +class String2D { + public: + String2D(ssize w, std::string::size_type h, char c) : s((w + 1) * h, c), width(w), height(h) { + for (ssize i = width; i < s.size(); i += width + 1) { + s.at(i) = '\n'; + } + } + String2D(std::string&& str) : s(std::move(str)) { + width = s.find('\n'); + height = s.size() / (width + 1); + } + const char& at(ssize x, std::string::size_type y) const { + assert(x < width); + assert(y < height); + return s.at(x + y * (width + 1)); + } + char& at(ssize x, std::string::size_type y) { + assert(x < width); + assert(y < height); + return s.at(x + y * (width + 1)); + } + void set(ssize x, std::string::size_type y, char c) { + assert(x < width); + assert(y < height); + s.at(x + y * (width + 1)) = c; + } + XY find(char c) { + ssize i = s.find(c); + if (i != std::string::npos) { return indexToPos(i); } + return XY{std::string::npos, std::string::npos}; + } + XY indexToPos(ssize i) { return XY{.x = i % (width + 1), .y = i / (width + 1) }; } + inline const ssize& getWidth() const { return width; } + inline const ssize& getHeight() const { return height; } + const std::string& getString() const { return s; } + private: + std::string s; + ssize width, height; +}; + +bool isReachable(char c) { + return c <= 1; +} + +String2D createNodes(const String2D& hill) { + String2D dirs(hill.getWidth(), hill.getHeight(), 0); + for (size_t x = 0; x < hill.getWidth(); x++) { + for (size_t y = 0; y < hill.getHeight(); y++) { + char c = hill.at(x, y); + if (x > 0) { + if (isReachable(hill.at(x - 1, y) - c)) { dirs.at(x, y) |= LEFT; } + } + if (x < hill.getWidth() - 1) { + if (isReachable(hill.at(x + 1, y) - c)) { dirs.at(x, y) |= RIGHT; } + } + if (y > 0) { + if (isReachable(hill.at(x, y - 1) - c)) { dirs.at(x, y) |= UP; } + } + if (y < hill.getHeight() - 1) { + if (isReachable(hill.at(x, y + 1) - c)) { dirs.at(x, y) |= DOWN; } + } + } + } + return dirs; +} + +ssize shortestPath(const String2D& nodes, XY start, XY end) { + gz::Queue waitlists[2]; + unsigned currentWaitlist = 0; + unsigned otherWaitlist = 1; + std::unordered_set processed; + ssize length = 0; + auto queue = [&processed](gz::Queue& q, XY xy) { + if (!processed.contains(xy)) { + processed.insert(xy); + q.push_back(xy); + } + }; + queue(waitlists[currentWaitlist], start); + while (waitlists[0].hasElement() || waitlists[1].hasElement()) { + while (waitlists[currentWaitlist].hasElement()) { + XY& pos = waitlists[currentWaitlist].getRef(); + if (pos == end) { goto done; } + char c = nodes.at(pos.x, pos.y); + if (c & LEFT) { queue(waitlists[otherWaitlist], XY{pos.x - 1, pos.y}); } + if (c & RIGHT) { queue(waitlists[otherWaitlist], XY{pos.x + 1, pos.y}); } + if (c & UP) { queue(waitlists[otherWaitlist], XY{pos.x, pos.y - 1}); } + if (c & DOWN) { queue(waitlists[otherWaitlist], XY{pos.x, pos.y + 1}); } + } + otherWaitlist = currentWaitlist; + currentWaitlist = ++currentWaitlist % 2; + length++; + } + std::cerr << "Could not find path\n"; + return std::string::npos; +done: + return length; +} + + +int main(int argc, const char** argv) { + const char* filename; + if (argc != 2) { filename = "hill.txt"; } + else { filename = argv[1]; } + + std::ifstream file(filename); + if (!file.is_open()) { + std::cout << "Could not open file\n"; + return 1; + } + std::ostringstream ss; + ss << file.rdbuf(); + file.close(); + String2D hill2D(ss.str()); + XY start = hill2D.find('S'); + XY end = hill2D.find('E'); + hill2D.at(start.x, start.y) = 'a'; + hill2D.at(end.x, end.y) = 'z'; + /* printf("Start: (%lu, %lu), End: (%lu, %lu)\n", start.x, start.y, end.x, end.y); */ + auto nodes = createNodes(hill2D); + ssize length = shortestPath(nodes, start, end); + std::cout << "Shortest path has length: " << length << "\n"; + + // Task 2 + ssize minLength = std::string::npos; + ssize startAt = 0; + ssize aIndex = hill2D.getString().find('a', startAt); + while (aIndex != std::string::npos) { + XY pos = hill2D.indexToPos(aIndex); + ssize length_ = shortestPath(nodes, hill2D.indexToPos(aIndex), end); + /* printf("Path from (%lu, %lu) to end has length: %lu\n", pos.x, pos.y, length_); */ + if (length_ < minLength) { minLength = length_; } + startAt = aIndex + 1; + aIndex = hill2D.getString().find('a', startAt); + } + printf("Shortest path from any a has length %lu\n", minLength); +} diff --git a/12/hill.txt b/12/hill.txt new file mode 100644 index 0000000..50f04d9 --- /dev/null +++ b/12/hill.txt @@ -0,0 +1,41 @@ +abccccaaaaaaacccaaaaaaaccccccccccccccccccccccccccccccccccaaaa +abcccccaaaaaacccaaaaaaaaaaccccccccccccccccccccccccccccccaaaaa +abccaaaaaaaaccaaaaaaaaaaaaaccccccccccccccccccccccccccccaaaaaa +abccaaaaaaaaaaaaaaaaaaaaaaacccccccccaaaccccacccccccccccaaacaa +abaccaaaaaaaaaaaaaaaaaacacacccccccccaaacccaaaccccccccccccccaa +abaccccaaaaaaaaaaaaaaaacccccccccccccaaaaaaaaaccccccccccccccaa +abaccccaacccccccccaaaaaacccccccccccccaaaaaaaacccccccccccccccc +abcccccaaaacccccccaaaaaaccccccccijjjjjjaaaaaccccccaaccaaccccc +abccccccaaaaacccccaaaacccccccciiijjjjjjjjjkkkkkkccaaaaaaccccc +abcccccaaaaacccccccccccccccccciiiirrrjjjjjkkkkkkkkaaaaaaccccc +abcccccaaaaaccccccccccccccccciiiirrrrrrjjjkkkkkkkkkaaaaaccccc +abaaccacaaaaacccccccccccccccciiiqrrrrrrrrrrssssskkkkaaaaacccc +abaaaaacaaccccccccccccccccccciiiqqrtuurrrrrsssssskklaaaaacccc +abaaaaacccccccccccaaccccccccciiqqqttuuuurrssusssslllaaccccccc +abaaaaaccccccccaaaaccccccccciiiqqqttuuuuuuuuuuusslllaaccccccc +abaaaaaacccccccaaaaaaccccccciiiqqqttxxxuuuuuuuusslllccccccccc +abaaaaaaccccaaccaaaaacccccchhiiqqtttxxxxuyyyyvvsslllccccccccc +abaaacacccccaacaaaaaccccccchhhqqqqttxxxxxyyyyvvsslllccccccccc +abaaacccccccaaaaaaaacccccchhhqqqqtttxxxxxyyyvvssqlllccccccccc +abacccccaaaaaaaaaaccaaacchhhpqqqtttxxxxxyyyyvvqqqlllccccccccc +SbaaacaaaaaaaaaaaacaaaaahhhhppttttxxEzzzzyyvvvqqqqlllcccccccc +abaaaaaaacaaaaaacccaaaaahhhppptttxxxxxyyyyyyyvvqqqlllcccccccc +abaaaaaaccaaaaaaaccaaaaahhhppptttxxxxywyyyyyyvvvqqqmmcccccccc +abaaaaaaacaaaaaaacccaaaahhhpppsssxxwwwyyyyyyvvvvqqqmmmccccccc +abaaaaaaaaaaaaaaacccaacahhhpppssssssswyyywwvvvvvqqqmmmccccccc +abaaaaaaaacacaaaacccccccgggppppsssssswwywwwwvvvqqqqmmmccccccc +abcaaacaaaccccaaaccccccccgggppppppssswwwwwrrrrrqqqmmmmccccccc +abcaaacccccccccccccccccccgggggpppoosswwwwwrrrrrqqmmmmddcccccc +abccaacccccccccccccccccccccgggggoooosswwwrrrnnnmmmmmddddccccc +abccccccccccccccccccccccccccgggggooossrrrrrnnnnnmmmddddaccccc +abaccccaacccccccccccccccccccccgggfoossrrrrnnnnndddddddaaacccc +abaccaaaaaaccccccccccccccccccccgffooorrrrnnnneeddddddaaaacccc +abaccaaaaaacccccccccccccccccccccfffooooonnnneeeddddaaaacccccc +abacccaaaaaccccccccaaccaaaccccccffffoooonnneeeeccaaaaaacccccc +abcccaaaaacccccccccaaccaaaaccccccffffoooneeeeeaccccccaacccccc +abaccaaaaaccccccccaaaacaaaaccccccafffffeeeeeaaacccccccccccccc +abacccccccccccccccaaaacaaacccccccccffffeeeecccccccccccccccaac +abaaaacccccccaaaaaaaaaaaaaacccccccccfffeeeccccccccccccccccaaa +abaaaacccccccaaaaaaaaaaaaaaccccccccccccaacccccccccccccccccaaa +abaacccccccccaaaaaaaaaaaaaaccccccccccccaacccccccccccccccaaaaa +abaaaccccccccccaaaaaaaaccccccccccccccccccccccccccccccccaaaaaa diff --git a/README.md b/README.md index 2c6729f..1c7db1e 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Also, check out the repositories of my friends who do stuff in go, Visual Basic, - **Assembly, x86-64**: day 4 - **Bash**: day 1, 7 - **C**: day 3, 4 -- **C++**: day 2, 8, 14 +- **C++**: day 2, 8, 12, 14 - **HolyC:** day 13 - **Java**: day 10 - **Javascript**: day 6