// Solutions to the Advent Of Code 2024. // Copyright (C) 2025 Stefan Müller // // This program is free software: you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation, either version 3 of the License, or (at your option) any later // version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along with // this program. If not, see . #include #include #include KeypadConundrum::KeypadConundrum() : numericKeyboardRobot_{ { { 'A', { 0, 0 } }, { '0', { -1, 0 } }, { '1', { -2, -1 } }, { '2', { -1, -1 } }, { '3', { 0, -1 } }, { '4', { -2, -2 } }, { '5', { -1, -2 } }, { '6', { 0, -2 } }, { '7', { -2, -3 } }, { '8', { -1, -3 } }, { '9', { 0, -3 } } }, { -2, 0 } }, directionalKeyboardRobot_{ { { 'A', { 0, 0 } }, { '<', { -2, 1 } }, { '>', { 0, 1 } }, { '^', { -1, 0 } }, { 'v', { -1, 1 } } }, { -2, 0 } }, transformations_{} { } const std::string KeypadConundrum::getPuzzleName() const { return "Keypad Conundrum"; } const int KeypadConundrum::getPuzzleDay() const { return 21; } void KeypadConundrum::processDataLine(const std::string& line) { KeypadPatternTransformation target{ numericKeyboardRobot_.calcTransformation(line) }; updateTransformationMap(target); std::istringstream stream{ line }; int64_t number; stream >> number; part1 += number * calcAccumulatedLength(target, getPart1NRobots()); part2 += number * calcAccumulatedLength(target, getPart2NRobots()); } void KeypadConundrum::finish() { } constexpr char KeypadConundrum::getStartPositionChar() { return 'A'; } constexpr size_t KeypadConundrum::getPart1NRobots() { return 2; } constexpr size_t KeypadConundrum::getPart2NRobots() { return 25; } void KeypadConundrum::updateTransformationMap(KeypadPatternTransformation& targetTransformation) { std::stack stack{}; stack.push(&targetTransformation); std::vector added{}; while (!stack.empty()) { auto transformation = stack.top(); stack.pop(); for (const auto& part : transformation->parts) { auto it = transformations_.find(part); if (it == transformations_.end()) { const auto emplaceResult = transformations_.emplace(part, directionalKeyboardRobot_.calcTransformation(part)); it = emplaceResult.first; stack.push(&it->second); added.push_back(&it->second); } transformation->partPtrs.push_back(&it->second); } } updateTransformationMapLengths(added); } void KeypadConundrum::updateTransformationMapLengths(const std::vector& added) { for (auto& transformation : added) { transformation->accumulatedLengths.reserve(getPart2NRobots()); } for (size_t i = 0; i < getPart2NRobots(); i++) { for (auto& transformation : added) { transformation->accumulatedLengths.push_back(calcAccumulatedLength(*transformation, i)); } } } int64_t KeypadConundrum::calcAccumulatedLength(KeypadPatternTransformation& transformation, const size_t index) { int64_t n{ transformation.nDuplicates }; for (const auto& part : transformation.partPtrs) { n += part->accumulatedLengths[index]; } return n; }