Add solution for "Day 21: Keypad Conundrum", part 1
This commit is contained in:
parent
c67bb9054a
commit
60798118ea
34
include/aoc/KeypadConundrum.hpp
Normal file
34
include/aoc/KeypadConundrum.hpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <aoc/extra/KeypadRobot.hpp>
|
||||||
|
#include <aoc/framework/Solver-types.hpp>
|
||||||
|
|
||||||
|
class KeypadConundrum
|
||||||
|
: public Solver<int64_t, int64_t>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KeypadConundrum();
|
||||||
|
virtual const std::string getPuzzleName() const override;
|
||||||
|
virtual const int getPuzzleDay() const override;
|
||||||
|
virtual void processDataLine(const std::string& line) override;
|
||||||
|
virtual void finish() override;
|
||||||
|
private:
|
||||||
|
static constexpr char getStartPositionChar();
|
||||||
|
KeypadRobot numericKeyboardRobot_;
|
||||||
|
KeypadRobot directionalKeyboardRobot_;
|
||||||
|
};
|
32
include/aoc/extra/KeypadRobot.hpp
Normal file
32
include/aoc/extra/KeypadRobot.hpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <aoc/common/Point2.hpp>
|
||||||
|
|
||||||
|
class KeypadRobot
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KeypadRobot(const std::map<char, Point2>&& keypad, const Point2&& forbidden);
|
||||||
|
std::string calcInputKeys(const std::string& targetOutputKeys) const;
|
||||||
|
private:
|
||||||
|
const std::map<char, Point2> keypad_;
|
||||||
|
const Point2 forbidden_;
|
||||||
|
void move(std::ostringstream& stream, const int delta, const char positive, const char negative) const;
|
||||||
|
};
|
62
src/KeypadConundrum.cpp
Normal file
62
src/KeypadConundrum.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <aoc/KeypadConundrum.hpp>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <aoc/common/Point2.hpp>
|
||||||
|
|
||||||
|
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 } }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string KeypadConundrum::getPuzzleName() const
|
||||||
|
{
|
||||||
|
return "Keypad Conundrum";
|
||||||
|
}
|
||||||
|
|
||||||
|
const int KeypadConundrum::getPuzzleDay() const
|
||||||
|
{
|
||||||
|
return 21;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeypadConundrum::processDataLine(const std::string& line)
|
||||||
|
{
|
||||||
|
std::istringstream stream{ line };
|
||||||
|
int64_t number;
|
||||||
|
stream >> number;
|
||||||
|
std::string inputKeys{ numericKeyboardRobot_.calcInputKeys(line) };
|
||||||
|
for (size_t i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
inputKeys = directionalKeyboardRobot_.calcInputKeys(inputKeys);
|
||||||
|
}
|
||||||
|
part1 += number * static_cast<int64_t>(inputKeys.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeypadConundrum::finish()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr char KeypadConundrum::getStartPositionChar()
|
||||||
|
{
|
||||||
|
return 'A';
|
||||||
|
}
|
@ -41,6 +41,7 @@
|
|||||||
#include <aoc/RamRun.hpp>
|
#include <aoc/RamRun.hpp>
|
||||||
#include <aoc/LinenLayout.hpp>
|
#include <aoc/LinenLayout.hpp>
|
||||||
#include <aoc/RaceCondition.hpp>
|
#include <aoc/RaceCondition.hpp>
|
||||||
|
#include <aoc/KeypadConundrum.hpp>
|
||||||
#include <aoc/LanParty.hpp>
|
#include <aoc/LanParty.hpp>
|
||||||
|
|
||||||
void Program::run()
|
void Program::run()
|
||||||
@ -79,6 +80,7 @@ void Program::runSolvers()
|
|||||||
runSolver<RamRun>(solverEngine);
|
runSolver<RamRun>(solverEngine);
|
||||||
runSolver<LinenLayout>(solverEngine);
|
runSolver<LinenLayout>(solverEngine);
|
||||||
runSolver<RaceCondition>(solverEngine);
|
runSolver<RaceCondition>(solverEngine);
|
||||||
|
runSolver<KeypadConundrum>(solverEngine);
|
||||||
runSolver<LanParty>(solverEngine);
|
runSolver<LanParty>(solverEngine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
68
src/extra/KeypadRobot.cpp
Normal file
68
src/extra/KeypadRobot.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <aoc/extra/KeypadRobot.hpp>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
KeypadRobot::KeypadRobot(const std::map<char, Point2>&& keypad, const Point2&& forbidden)
|
||||||
|
: keypad_{ keypad }, forbidden_{ forbidden }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string KeypadRobot::calcInputKeys(const std::string& targetOutputKeys) const
|
||||||
|
{
|
||||||
|
std::ostringstream stream{};
|
||||||
|
Point2 position{ 0, 0 };
|
||||||
|
for (const char c : targetOutputKeys)
|
||||||
|
{
|
||||||
|
Point2 next = keypad_.at(c);
|
||||||
|
|
||||||
|
// This specific order of robot arm movements aims to reduce resulting combinations of 'A' and '<' for the
|
||||||
|
// second robot, which expand to more key presses starting with the third robot.
|
||||||
|
bool horizontalFirst{ (next.x < position.x && !(next.x == forbidden_.x && position.y == forbidden_.y)) ||
|
||||||
|
(position.x == forbidden_.x && next.y == forbidden_.y) };
|
||||||
|
if (horizontalFirst)
|
||||||
|
{
|
||||||
|
move(stream, next.x - position.x, '>', '<');
|
||||||
|
}
|
||||||
|
move(stream, next.y - position.y, 'v', '^');
|
||||||
|
if (!horizontalFirst)
|
||||||
|
{
|
||||||
|
move(stream, next.x - position.x, '>', '<');
|
||||||
|
}
|
||||||
|
stream << 'A';
|
||||||
|
position = next;
|
||||||
|
}
|
||||||
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeypadRobot::move(std::ostringstream& stream, const int delta, const char positive, const char negative) const
|
||||||
|
{
|
||||||
|
if (delta > 0)
|
||||||
|
{
|
||||||
|
for (int i{ 0 }; i < delta; i++)
|
||||||
|
{
|
||||||
|
stream << positive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i{ 0 }; i < -delta; i++)
|
||||||
|
{
|
||||||
|
stream << negative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,7 @@
|
|||||||
#include <aoc/RamRun.hpp>
|
#include <aoc/RamRun.hpp>
|
||||||
#include <aoc/LinenLayout.hpp>
|
#include <aoc/LinenLayout.hpp>
|
||||||
#include <aoc/RaceCondition.hpp>
|
#include <aoc/RaceCondition.hpp>
|
||||||
|
#include <aoc/KeypadConundrum.hpp>
|
||||||
#include <aoc/LanParty.hpp>
|
#include <aoc/LanParty.hpp>
|
||||||
|
|
||||||
#define REQUIRE_MESSAGE(cond, msg) if (!(cond)) { INFO(msg); REQUIRE(cond); }
|
#define REQUIRE_MESSAGE(cond, msg) if (!(cond)) { INFO(msg); REQUIRE(cond); }
|
||||||
@ -369,6 +370,19 @@ TEST_CASE("[RaceConditionTests]")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[KeypadConundrumTests]")
|
||||||
|
{
|
||||||
|
TestContext test;
|
||||||
|
SECTION("FullData")
|
||||||
|
{
|
||||||
|
test.runFull(std::make_unique<KeypadConundrum>(), 136780, 0);
|
||||||
|
}
|
||||||
|
SECTION("ExampleData")
|
||||||
|
{
|
||||||
|
test.runExample(std::make_unique<KeypadConundrum>(), 126384, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("[LanPartyTests]")
|
TEST_CASE("[LanPartyTests]")
|
||||||
{
|
{
|
||||||
TestContext test;
|
TestContext test;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user