// 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;
}