From c62c9dc3de67fa05f45fdd5851dcdda931df0854 Mon Sep 17 00:00:00 2001 From: Thraix Date: Thu, 3 Sep 2026 22:09:48 +0200 Subject: [PATCH] Add solution for 2016 Day 21 --- res/2016/day21/test_input.txt | 8 + src/2016/Day21.cpp | 214 +++++++++++++++++++- src/common/aoc.h | 1 + src/common/lib/CyclicVector.h | 354 ++++++++++++++++++++++++++++++++++ 4 files changed, 569 insertions(+), 8 deletions(-) create mode 100644 src/common/lib/CyclicVector.h diff --git a/res/2016/day21/test_input.txt b/res/2016/day21/test_input.txt index e69de29..c6621d3 100644 --- a/res/2016/day21/test_input.txt +++ b/res/2016/day21/test_input.txt @@ -0,0 +1,8 @@ +swap position 4 with position 0 +swap letter d with letter b +reverse positions 0 through 4 +rotate left 1 +move position 1 to position 4 +move position 3 to position 0 +rotate based on position of letter b +rotate based on position of letter d diff --git a/src/2016/Day21.cpp b/src/2016/Day21.cpp index 272d0c8..c4336ff 100644 --- a/src/2016/Day21.cpp +++ b/src/2016/Day21.cpp @@ -2,30 +2,228 @@ namespace y2016::day21 { - REGISTER_DAY(2016, Day21, std::vector, int); + enum class Operator + { + Swap, + SwapLetter, + Rotate, + RotatePos, + Reverse, + Move + }; - REGISTER_TEST_EXAMPLE(2016, Day21, ExampleInput, 1, 0); - REGISTER_TEST(2016, Day21, Input, 1, 0); - REGISTER_TEST_EXAMPLE(2016, Day21, ExampleInput, 2, 0); - REGISTER_TEST(2016, Day21, Input, 2, 0); + struct Instruction + { + Operator op; + int arg1; + int arg2; + }; + + REGISTER_DAY(2016, Day21, std::vector, std::string); + + REGISTER_TEST_EXAMPLE(2016, Day21, ExampleInput, 1, "decab"); + REGISTER_TEST(2016, Day21, Input, 1, "hcdefbag"); + REGISTER_TEST(2016, Day21, Input, 2, "fbhaegdc"); READ_INPUT(input) { - std::vector vec; + std::vector vec; std::string str; while (getline(input, str)) { + Instruction instruction; + std::stringstream ss{str}; + if (Helper::StartsWith(str, "swap position")) + { + instruction.op = Operator::Swap; + ss >> "swap position " >> instruction.arg1 >> "with position " >> instruction.arg2; + } + else if (Helper::StartsWith(str, "swap letter")) + { + instruction.op = Operator::SwapLetter; + char c1, c2; + ss >> "swap letter " >> c1 >> "with letter " >> c2; + instruction.arg1 = c1; + instruction.arg2 = c2; + } + else if (Helper::StartsWith(str, "rotate left")) + { + instruction.op = Operator::Rotate; + ss >> "rotate left" >> instruction.arg1; + instruction.arg1 = -instruction.arg1; + } + else if (Helper::StartsWith(str, "rotate right")) + { + instruction.op = Operator::Rotate; + ss >> "rotate right" >> instruction.arg1; + } + else if (Helper::StartsWith(str, "rotate based")) + { + instruction.op = Operator::RotatePos; + char c; + ss >> "rotate based on position of letter " >> c; + instruction.arg1 = c; + } + else if (str[0] == 'r') + { + instruction.op = Operator::Reverse; + ss >> "reverse positions " >> instruction.arg1 >> "through " >> instruction.arg2; + } + else + { + instruction.op = Operator::Move; + ss >> "move position " >> instruction.arg1 >> "to position " >> instruction.arg2; + } + vec.emplace_back(instruction); } return vec; } OUTPUT1(input) { - return 0; + CyclicVector data{isExample ? "abcde" : "abcdefgh"}; + for (const auto& instruction : input) + { + switch (instruction.op) + { + case Operator::Swap: + { + std::swap(data[instruction.arg1], data[instruction.arg2]); + break; + } + case Operator::SwapLetter: + { + size_t i1 = data.Find(instruction.arg1); + size_t i2 = data.Find(instruction.arg2); + std::swap(data[i1], data[i2]); + break; + } + case Operator::Rotate: + { + data.Rotate(instruction.arg1); + break; + } + case Operator::RotatePos: + { + size_t pos = data.Find(instruction.arg1); + int additional = pos >= 4 ? 1 : 0; + data.Rotate(pos + 1 + additional); + break; + } + case Operator::Reverse: + { + for (size_t i = 0; i < (instruction.arg2 - instruction.arg1 + 1) / 2; i++) + { + std::swap(data[instruction.arg1 + i], data[instruction.arg2 - i]); + } + break; + } + case Operator::Move: + { + if (instruction.arg1 < instruction.arg2) + { + char c = data[instruction.arg1]; + for (size_t i = instruction.arg1; i < instruction.arg2; i++) + { + data[i] = data[i + 1]; + } + data[instruction.arg2] = c; + } + else + { + char c = data[instruction.arg1]; + for (size_t i = instruction.arg1; i > instruction.arg2; i--) + { + data[i] = data[i - 1]; + } + data[instruction.arg2] = c; + } + break; + } + } + } + std::string str; + for (size_t i = 0; i < data.size(); i++) + { + str.push_back(data[i]); + } + return str; } OUTPUT2(input) { - return 0; + CyclicVector data{"fbgdceah"}; + std::map rotatePosMap; + for (int i = 0; i < data.size(); i++) + { + int result = (i + i + 1 + (i >= 4 ? 1 : 0)) % data.size(); + rotatePosMap.emplace(result, i - result); + } + for (int i = input.size() - 1; i >= 0; i--) + { + const auto& instruction = input[i]; + switch (instruction.op) + { + case Operator::Swap: + { + std::swap(data[instruction.arg1], data[instruction.arg2]); + break; + } + case Operator::SwapLetter: + { + size_t i1 = data.Find(instruction.arg1); + size_t i2 = data.Find(instruction.arg2); + std::swap(data[i1], data[i2]); + break; + } + case Operator::Rotate: + { + data.Rotate(-instruction.arg1); + break; + } + case Operator::RotatePos: + { + size_t pos = data.Find(instruction.arg1); + data.Rotate(rotatePosMap[pos]); + break; + } + case Operator::Reverse: + { + for (size_t i = 0; i < (instruction.arg2 - instruction.arg1 + 1) / 2; i++) + { + std::swap(data[instruction.arg1 + i], data[instruction.arg2 - i]); + } + break; + } + case Operator::Move: + { + if (instruction.arg2 < instruction.arg1) + { + char c = data[instruction.arg2]; + for (size_t i = instruction.arg2; i < instruction.arg1; i++) + { + data[i] = data[i + 1]; + } + data[instruction.arg1] = c; + } + else + { + char c = data[instruction.arg2]; + for (size_t i = instruction.arg2; i > instruction.arg1; i--) + { + data[i] = data[i - 1]; + } + data[instruction.arg1] = c; + } + break; + } + } + } + std::string str; + for (auto c : data) + { + str.push_back(c); + } + return str; } } diff --git a/src/common/aoc.h b/src/common/aoc.h index e0d7daa..df47c33 100644 --- a/src/common/aoc.h +++ b/src/common/aoc.h @@ -24,6 +24,7 @@ #include "common/lib/Array2D.h" #include "common/lib/Array3D.h" #include "common/lib/Array4D.h" +#include "common/lib/CyclicVector.h" #include "common/lib/Graph.h" #include "common/lib/Helper.h" #include "common/lib/Input.h" diff --git a/src/common/lib/CyclicVector.h b/src/common/lib/CyclicVector.h new file mode 100644 index 0000000..3fb312d --- /dev/null +++ b/src/common/lib/CyclicVector.h @@ -0,0 +1,354 @@ +#pragma once + +#include +#include +#include + +template +struct CyclicVector +{ + std::vector vector; + size_t offset{0}; + + CyclicVector(const std::initializer_list& vector) + : vector{vector} + { + } + + CyclicVector(const std::vector& vector) + : vector{vector} + { + } + + template >> + CyclicVector(const std::string& str) + : vector{str.begin(), str.end()} + { + } + + template >> + CyclicVector(const char (&str)[N]) + { + vector.resize(N - 1); // don't include \0 character + for (size_t i = 0; i < N - 1; i++) + { + vector[i] = str[i]; + } + } + + void Rotate(int i) + { + if (i < 0) + RotateLeft(-i); + else + RotateRight(i); + } + + void RotateRight(int i) + { + offset = (offset + vector.size() - (i % vector.size())) % vector.size(); + } + + void RotateLeft(size_t i) + { + offset = (offset + i) % vector.size(); + } + + T& operator[](size_t i) + { + return vector[(i + offset) % vector.size()]; + } + + const T& operator[](size_t i) const + { + return vector[(i + offset) % vector.size()]; + } + + size_t size() const + { + return vector.size(); + } + + bool empty() const + { + return vector.empty(); + } + + size_t Find(const T& t) const + { + return std::find(begin(), end(), t).GetPos(); + } + + struct iterator; + struct const_iterator; + + iterator begin() + { + return iterator{*this, 0}; + } + + iterator end() + { + return iterator{*this, vector.size()}; + } + + const_iterator begin() const + { + return const_iterator{*this, 0}; + } + + const_iterator end() const + { + return const_iterator{*this, vector.size()}; + } + + const_iterator cbegin() const + { + return const_iterator{*this, 0}; + } + + const_iterator cend() const + { + return const_iterator{*this, vector.size()}; + } + + friend std::ostream& operator<<(std::ostream& os, const CyclicVector& vector) + { + os << "["; + if (!vector.empty()) + os << vector[0]; + + for (auto it = vector.cbegin() + 1; it != vector.cend(); it++) + { + os << ", " << *it; + } + os << "]"; + return os; + } + + class iterator + { + private: + CyclicVector& data; + size_t pos; + + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = int; + using pointer = T*; + using reference = T&; + + iterator(CyclicVector& data, size_t pos) + : data{data}, + pos{pos} + { + } + + size_t GetPos() const + { + return pos; + } + + reference operator*() const + { + return data[pos]; + } + + pointer operator->() const + { + return &data[pos]; + } + + iterator& operator++() + { + ++pos; + return *this; + } + + iterator operator++(int) + { + iterator ret = *this; + ++(*this); + return ret; + } + + iterator& operator--() + { + --pos; + return *this; + } + + iterator operator--(int) + { + iterator ret = *this; + --(*this); + return ret; + } + + iterator& operator+=(size_t advance) + { + if (std::numeric_limits::max() - pos < advance) + { + pos = data.size(); + } + else + { + pos += advance; + if (pos >= data.size()) + pos = data.size(); + } + return *this; + } + + iterator& operator-=(size_t advance) + { + if (advance > pos) + { + pos = data.size(); + } + else + { + pos -= advance; + } + return *this; + } + + iterator operator+(size_t advance) const + { + iterator ret = *this; + ret += advance; + return ret; + } + + iterator operator-(size_t advance) const + { + iterator ret = *this; + ret -= advance; + return ret; + } + + bool operator==(const iterator& other) const + { + return pos == other.pos; + } + + bool operator!=(const iterator& other) const + { + return !(*this == other); + } + }; + + class const_iterator + { + private: + const CyclicVector& data; + size_t pos; + + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = int; + using pointer = const T*; + using reference = const T&; + + const_iterator(const CyclicVector& data, size_t pos) + : data{data}, + pos{pos} + { + } + + size_t GetPos() const + { + return pos; + } + + reference operator*() const + { + return data[pos]; + } + + pointer operator->() const + { + return &data[pos]; + } + + const_iterator& operator++() + { + ++pos; + return *this; + } + + const_iterator operator++(int) + { + const_iterator ret = *this; + ++(*this); + return ret; + } + + const_iterator& operator--() + { + --pos; + return *this; + } + + const_iterator operator--(int) + { + const_iterator ret = *this; + --(*this); + return ret; + } + + const_iterator& operator+=(size_t advance) + { + if (std::numeric_limits::max() - pos < advance) + { + pos = data.size(); + } + else + { + pos += advance; + if (pos >= data.size()) + pos = data.size(); + } + return *this; + } + + const_iterator& operator-=(size_t advance) + { + if (advance > pos) + { + pos = data.size(); + } + else + { + pos -= advance; + } + return *this; + } + + const_iterator operator+(size_t advance) const + { + const_iterator ret = *this; + ret += advance; + return ret; + } + + const_iterator operator-(size_t advance) const + { + const_iterator ret = *this; + ret -= advance; + return ret; + } + + bool operator==(const const_iterator& other) const + { + return pos == other.pos; + } + + bool operator!=(const const_iterator& other) const + { + return !(*this == other); + } + }; +};