diff --git a/18/CMakeLists.txt b/18/CMakeLists.txt new file mode 100644 index 0000000..837598b --- /dev/null +++ b/18/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.10) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +enable_language(CXX) + +project(AoC18) + +if(APPLE) + include_directories(/usr/local/include) + link_directories(/usr/local/lib) +endif() + +if(WIN32) + add_executable(${CMAKE_PROJECT_NAME} WIN32) +else() + add_executable(${CMAKE_PROJECT_NAME}) +endif() + +target_sources(${CMAKE_PROJECT_NAME} + PRIVATE main.cpp + ) diff --git a/18/input b/18/input new file mode 100644 index 0000000..92861c6 --- /dev/null +++ b/18/input @@ -0,0 +1,100 @@ +[1,[[9,[5,8]],[[2,0],0]]] +[[[6,4],6],[[1,[7,3]],[[0,1],[4,9]]]] +[[[7,3],[8,6]],[[4,[1,2]],7]] +[[[2,[4,5]],[[7,1],2]],1] +[[[[4,4],[4,6]],9],[[4,2],6]] +[[[9,8],[[4,0],0]],[[2,[5,1]],[[9,6],[9,2]]]] +[[[6,[9,0]],0],[6,[[5,8],3]]] +[[[[7,3],[5,4]],0],[3,[[0,6],3]]] +[5,[[0,0],[[4,8],[8,6]]]] +[[[3,[9,2]],9],[5,[0,6]]] +[[[[6,3],[3,2]],[5,9]],2] +[[[0,4],7],[8,[8,[4,2]]]] +[[[8,[8,0]],9],[[1,[6,3]],[4,2]]] +[[[[5,4],[1,5]],[1,3]],[[[9,0],[7,4]],9]] +[[[5,[4,2]],[[9,2],3]],[[[6,2],[6,8]],[[2,4],[9,4]]]] +[[9,6],[0,[[1,1],9]]] +[[[8,[5,9]],[2,9]],[0,[[7,6],[7,6]]]] +[[[5,[4,8]],[[7,7],[2,2]]],[[[2,6],[5,7]],[0,[6,2]]]] +[[[[9,3],5],3],[[[1,5],2],[3,3]]] +[[[2,[1,1]],[[5,8],[7,1]]],[[9,7],5]] +[[9,9],3] +[[[5,[6,1]],9],[1,[9,3]]] +[[[[1,2],7],[[6,8],[4,1]]],[[2,3],[6,3]]] +[[[[9,3],[7,9]],2],[[9,[3,4]],[[2,6],[7,0]]]] +[[8,[4,9]],[[2,[5,6]],6]] +[3,[[[9,7],7],[[2,6],4]]] +[[[[3,4],[0,8]],[[6,4],[2,6]]],[[[1,4],[5,4]],8]] +[8,[[0,[5,5]],[[1,2],1]]] +[[[5,[8,1]],[[1,8],[4,0]]],[8,8]] +[[[9,5],3],[[7,9],[1,6]]] +[[[[1,1],1],[[2,0],[2,5]]],5] +[[3,[[5,4],[7,4]]],[[4,4],[1,9]]] +[[0,[[7,4],[7,2]]],[[8,0],[5,9]]] +[0,[[[1,2],4],[[1,0],[6,4]]]] +[[[[6,6],[9,8]],3],[[[5,5],[1,6]],[8,[5,3]]]] +[[7,[[5,6],0]],[5,[[9,2],4]]] +[[[4,[4,5]],[7,[4,5]]],[[[9,8],8],[[8,2],[3,0]]]] +[[[8,[0,5]],[[0,4],[8,9]]],[8,[4,6]]] +[[[4,[9,7]],[[7,4],[7,1]]],[[[8,4],0],[[6,9],[9,0]]]] +[[3,6],[[3,[4,6]],[[6,0],0]]] +[3,[1,[[4,0],1]]] +[[[9,9],[0,[6,3]]],[3,2]] +[7,4] +[2,6] +[[[3,[7,8]],7],[[0,[2,5]],[1,1]]] +[0,5] +[8,[8,[[2,4],5]]] +[[[[8,2],1],[9,0]],[[[0,8],[3,0]],9]] +[[[[7,0],1],[[0,1],[6,7]]],[[[3,1],[8,3]],7]] +[8,0] +[[[7,[1,3]],[7,[7,2]]],[[9,0],4]] +[[[[0,3],5],[[1,0],8]],[[0,2],9]] +[[5,[[7,6],[7,2]]],5] +[[[[2,8],[5,4]],[1,6]],[[8,8],[[5,2],4]]] +[[[[1,5],[1,8]],1],[[6,[2,4]],5]] +[[[[9,7],[6,3]],2],[[3,[4,4]],[3,4]]] +[[[9,2],[2,9]],[[[0,7],[0,8]],[[0,2],[6,7]]]] +[[[[1,1],3],[[1,4],[8,9]]],[[8,[8,6]],[7,7]]] +[5,[[1,[8,8]],[6,3]]] +[[[1,4],3],7] +[[[[0,1],[2,0]],2],[[8,8],7]] +[[[[2,8],[4,4]],[[5,6],8]],[[[5,3],1],7]] +[[9,[0,[8,3]]],[5,6]] +[[[0,[8,9]],[6,[8,1]]],[[[2,3],8],[[4,0],8]]] +[[2,[5,4]],[[7,4],[[5,0],3]]] +[[[[1,1],2],[[3,0],[7,7]]],[[1,[3,8]],2]] +[[[1,4],[6,[2,4]]],[[5,5],0]] +[[[[4,4],8],[[4,3],[3,5]]],[[7,1],2]] +[[[4,[0,8]],9],[[[6,9],2],8]] +[[[[0,0],1],[1,1]],[2,[[0,0],[7,7]]]] +[[2,[5,5]],9] +[[[[5,8],[7,7]],[[9,8],5]],[[3,5],[8,8]]] +[[5,[3,[3,9]]],[3,[9,8]]] +[[8,[4,6]],[[5,0],[9,2]]] +[[[3,[1,8]],[4,5]],[[0,[5,9]],6]] +[9,[[1,1],0]] +[[[[6,1],[9,2]],4],[5,3]] +[[[[3,0],[0,5]],[1,[5,2]]],[[[2,0],[0,2]],[[6,4],4]]] +[[[[1,1],[4,6]],[[3,8],[3,2]]],[[[4,3],7],[2,[7,8]]]] +[4,[[1,5],5]] +[8,[[1,1],0]] +[[[[8,4],[9,9]],[3,[6,6]]],[[[7,9],[9,7]],7]] +[[2,5],[8,[3,8]]] +[[[6,1],[7,[3,5]]],9] +[[1,[[3,6],[1,0]]],[[[2,8],8],[4,[2,7]]]] +[[[3,[6,9]],[[9,6],[0,8]]],[[5,[6,4]],[[3,4],1]]] +[[[[7,7],1],[5,[2,5]]],[[3,7],[[4,7],3]]] +[[4,[3,[7,2]]],[[[8,8],[5,8]],8]] +[[3,[[9,9],6]],6] +[[6,7],[2,9]] +[[[9,7],[1,[4,0]]],[[[3,4],0],[1,2]]] +[9,[[8,[8,4]],3]] +[[[4,[4,1]],[[4,7],[2,3]]],[8,[5,[1,5]]]] +[7,[2,[4,1]]] +[[[[1,5],7],[5,9]],8] +[[[[1,5],[0,4]],8],[[[7,0],6],[8,3]]] +[[[7,[3,5]],0],[8,[9,[5,6]]]] +[[1,[[5,1],5]],[[5,1],[9,[3,0]]]] +[3,[[[8,5],[7,5]],[9,4]]] +[[[3,3],[2,[5,9]]],7] diff --git a/18/main.cpp b/18/main.cpp new file mode 100644 index 0000000..c5cccb7 --- /dev/null +++ b/18/main.cpp @@ -0,0 +1,299 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SnailFishNumber { +public: + SnailFishNumber() {} + + void setParent(std::shared_ptr &parent) { + _parent = parent; + } + + void setValue(uint64_t value) { + _simple = true; + _simple_value = value; + } + + void setLeft(std::shared_ptr &left) { + _simple = false; + _left = left; + } + + void setRight(std::shared_ptr &right) { + _simple = false; + _right = right; + } + + void printNumber() { + if (_simple) { + std::cout << _simple_value; + } else { + std::cout << "["; + _left->printNumber(); + std::cout << ","; + _right->printNumber(); + std::cout << "]"; + } + } + + void addValue(uint64_t val) { + _simple_value += val; + } + + uint64_t getValue() { + return _simple_value; + } + + void fixNumber() { + // we rely on lazy execution + while (explodeNumber() || splitNumber()) { + } + } + + std::shared_ptr findLeftNeighbour() { + auto child = this; + auto parent = _parent.get(); + while (parent != nullptr && parent->isLeftChild(child)) { + child = parent; + parent = parent->getParent().get(); + } + if (parent == nullptr) { + return nullptr; + } + auto left_neighbour = parent->getLeftChild(); + while (!left_neighbour->isSimple()) { + left_neighbour = left_neighbour->getRightChild(); + } + return left_neighbour; + } + + std::shared_ptr findRightNeighbour() { + auto child = this; + auto parent = _parent.get(); + while (parent != nullptr && parent->isRightChild(child)) { + child = parent; + parent = parent->getParent().get(); + } + if (parent == nullptr) { + return nullptr; + } + auto right_neighbour = parent->getRightChild(); + while (!right_neighbour->isSimple()) { + right_neighbour = right_neighbour->getLeftChild(); + } + return right_neighbour; + } + + std::shared_ptr getParent() { + return _parent; + } + + std::shared_ptr getLeftChild() { + return _left; + } + + std::shared_ptr getRightChild() { + return _right; + } + + bool isSimple() { + return _simple; + } + + bool isLeftChild(SnailFishNumber *ptr) { + return ptr == _left.get(); + } + + bool isRightChild(SnailFishNumber *ptr) { + return ptr == _right.get(); + } + + uint64_t getMagnitude() { + if (_simple) { + return _simple_value; + } + return 3 * _left->getMagnitude() + 2 * _right->getMagnitude(); + } + + std::shared_ptr copySelf() const { + auto res = std::make_shared(); + if (_simple) { + res->setValue(_simple_value); + } else { + auto left_copy = _left->copySelf(); + auto right_copy = _right->copySelf(); + left_copy->setParent(res); + right_copy->setParent(res); + res->setLeft(left_copy); + res->setRight(right_copy); + } + return res; + } + +private: + bool explodeNumber(int depth = 0) { + if (_simple) { + return false; + ; + } + if (depth >= 4) { + auto left_neighbour = findLeftNeighbour(); + auto right_neighbour = findRightNeighbour(); + if (left_neighbour != nullptr) { + left_neighbour->addValue(_left->getValue()); + } + if (right_neighbour != nullptr) { + right_neighbour->addValue(_right->getValue()); + } + _simple = true; + _simple_value = 0; + _left.reset(); + _right.reset(); + return true; + } + if (_left->explodeNumber(depth + 1)) { + return true; + } + if (_right->explodeNumber(depth + 1)) { + return true; + } + return false; + } + + bool splitNumber() { + if (!_simple) { + if (_left->splitNumber()) { + return true; + } + if (_right->splitNumber()) { + return true; + } + return false; + } + if (_simple_value > 9) { + _simple = false; + _left = std::make_unique(); + _right = std::make_unique(); + _left->setValue(_simple_value / 2); + _right->setValue(_simple_value - _left->getValue()); + std::shared_ptr me{}; + if (_parent->isRightChild(this)) { + me = _parent->getRightChild(); + } else { + me = _parent->getLeftChild(); + } + _left->setParent(me); + _right->setParent(me); + _simple_value = 0; + return true; + } + return false; + } + + bool _simple = false; + uint64_t _simple_value{}; + std::shared_ptr _left{ nullptr }; + std::shared_ptr _right{ nullptr }; + std::shared_ptr _parent{ nullptr }; +}; + +std::vector> +getNumbers(const std::string &file_name) { + std::vector> numbers{}; + + std::ifstream file(file_name); + std::string str; + while (std::getline(file, str)) { + auto cur = std::make_shared(); + numbers.push_back(cur); + std::deque> parents; + for (auto &c : str) { + if (c == '[') { + parents.push_back(cur); + cur = std::make_shared(); + cur->setParent(parents.back()); + parents.back()->setLeft(cur); + } + if (c >= '0' && c <= '9') { + cur->setValue(c - '0'); + } + if (c == ',') { + cur = std::make_shared(); + cur->setParent(parents.back()); + parents.back()->setRight(cur); + } + if (c == ']') { + cur = parents.back(); + parents.pop_back(); + } + } + if (parents.size() > 1) { + std::cout << "Something's wrong, I can feel it!" << std::endl; + } + } + + return numbers; +} + +std::shared_ptr +addNumbers(std::shared_ptr &a, + std::shared_ptr &b) { + auto result = std::make_shared(); + result->setLeft(a); + result->setRight(b); + a->setParent(result); + b->setParent(result); + result->fixNumber(); + return result; +} + +uint64_t part1(const std::vector> &numbers) { + auto n0 = numbers[0]->copySelf(); + auto n1 = numbers[1]->copySelf(); + auto res = addNumbers(n0, n1); + for (size_t i = 2; i < numbers.size(); i++) { + auto addition = numbers[i]->copySelf(); + res = addNumbers(res, addition); + } + return res->getMagnitude(); +} + +uint64_t part2(const std::vector> &numbers) { + uint64_t max_magnitude = 0; + for (const auto &number : numbers) { + for (const auto &number2 : numbers) { + if (number == number2) { + continue; + } + auto n1 = number->copySelf(); + auto n2 = number2->copySelf(); + auto res = addNumbers(n1, n2); + auto mag = res->getMagnitude(); + if (mag > max_magnitude) { + max_magnitude = mag; + } + } + } + return max_magnitude; +} + +int main(int argc, char **argv) { + if (argc < 2) { + std::cerr << "You must provide input file!" << std::endl; + return 1; + } + auto numbers = getNumbers(argv[1]); + std::cout << "The magnitude of final result is \033[91;1m" << part1(numbers) + << "\033[0m." << std::endl; + std::cout + << "The largest possible magnitude from only 2 numbers is \033[91;1m" + << part2(numbers) << "\033[0m." << std::endl; + return 0; +}