From 12fdc184cf3006f3c26d5a056c9f3c4b0ab70b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Sun, 1 Jun 2025 23:00:16 +0200 Subject: [PATCH] Add solution for "Day 19: Linen Layout", part 1 --- include/aoc/LinenLayout.hpp | 32 +++++++ include/aoc/extra/LinenTowelPatterns.hpp | 32 +++++++ src/LinenLayout.cpp | 58 +++++++++++++ src/Program.cpp | 2 + src/extra/LinenTowelPatterns.cpp | 101 +++++++++++++++++++++++ tests/src/TestCases.cpp | 14 ++++ 6 files changed, 239 insertions(+) create mode 100644 include/aoc/LinenLayout.hpp create mode 100644 include/aoc/extra/LinenTowelPatterns.hpp create mode 100644 src/LinenLayout.cpp create mode 100644 src/extra/LinenTowelPatterns.cpp diff --git a/include/aoc/LinenLayout.hpp b/include/aoc/LinenLayout.hpp new file mode 100644 index 0000000..6202b52 --- /dev/null +++ b/include/aoc/LinenLayout.hpp @@ -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 . + +#pragma once + +#include +#include + +class LinenLayout + : public Solver +{ +public: + 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: + LinenTowelPatterns patterns_{}; + bool isReadingDesigns_{ false }; +}; diff --git a/include/aoc/extra/LinenTowelPatterns.hpp b/include/aoc/extra/LinenTowelPatterns.hpp new file mode 100644 index 0000000..f71839e --- /dev/null +++ b/include/aoc/extra/LinenTowelPatterns.hpp @@ -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 . + +#pragma once + +#include +#include +#include + +class LinenTowelPatterns +{ +public: + LinenTowelPatterns(); + void add(const std::string& towelPattern); + bool isPossible(const std::string& design); +private: + std::vector> patterns_; + std::map stripes_; + void addBranch(); +}; diff --git a/src/LinenLayout.cpp b/src/LinenLayout.cpp new file mode 100644 index 0000000..8a60bcd --- /dev/null +++ b/src/LinenLayout.cpp @@ -0,0 +1,58 @@ +// 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 + +const std::string LinenLayout::getPuzzleName() const +{ + return "Linen Layout"; +} + +const int LinenLayout::getPuzzleDay() const +{ + return 19; +} + +void LinenLayout::processDataLine(const std::string& line) +{ + if (isReadingDesigns_) + { + if (patterns_.isPossible(line)) + { + part1++; + } + } + else if (line.empty()) + { + isReadingDesigns_ = true; + } + else + { + std::istringstream stream{ line }; + std::string pattern; + while (std::getline(stream, pattern, ',')) + { + patterns_.add(pattern); + // Removes the space between comma and next pattern. + char c = stream.get(); + } + } +} + +void LinenLayout::finish() +{ +} diff --git a/src/Program.cpp b/src/Program.cpp index 680a34c..0284db3 100644 --- a/src/Program.cpp +++ b/src/Program.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include void Program::run() @@ -75,6 +76,7 @@ void Program::runSolvers() runSolver(solverEngine); runSolver(solverEngine); runSolver(solverEngine); + runSolver(solverEngine); runSolver(solverEngine); } diff --git a/src/extra/LinenTowelPatterns.cpp b/src/extra/LinenTowelPatterns.cpp new file mode 100644 index 0000000..9afb7e8 --- /dev/null +++ b/src/extra/LinenTowelPatterns.cpp @@ -0,0 +1,101 @@ +// 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 + +LinenTowelPatterns::LinenTowelPatterns() + : patterns_{}, stripes_{ + { 'w', 0 }, + { 'u', 1 }, + { 'b', 2 }, + { 'r', 3 }, + { 'g', 4 } + } +{ + addBranch(); +} + +void LinenTowelPatterns::add(const std::string& towelPattern) +{ + size_t current{ 0 }; + size_t next{ 0 }; + for (const char stripe : towelPattern) + { + if (next >= patterns_.size()) + { + patterns_[current].first = next; + addBranch(); + } + current = next + stripes_[stripe]; + next = patterns_[current].first > 0 ? patterns_[current].first : patterns_.size(); + } + patterns_[current].second = true; +} + +bool LinenTowelPatterns::isPossible(const std::string& design) +{ + std::vector canStartFrom(design.size(), false); + canStartFrom[0] = true; + std::set unexploredStart; + unexploredStart.insert(0); + + while (!unexploredStart.empty()) + { + size_t designPosition = *unexploredStart.rbegin(); + unexploredStart.erase(designPosition); + + size_t i{ stripes_[design[designPosition]] }; + while (++designPosition < design.size() && patterns_[i].first > 0) + { + if (patterns_[i].second && !canStartFrom[designPosition]) + { + // The current accumulated stripe pattern exists and it ends at a new position within the design. + canStartFrom[designPosition] = true; + unexploredStart.insert(designPosition); + } + if (patterns_[i].first > 0) + { + // The current accumulated stripe pattern can be extended further. + i = patterns_[i].first + stripes_[design[designPosition]]; + } + } + if (patterns_[i].second) + { + if (designPosition == design.size()) + { + // The current accumulated stripe pattern exists and finishes the design. + return true; + } + else if (!canStartFrom[designPosition]) + { + // The current accumulated stripe pattern exists and it ends at a new position within the design. + canStartFrom[designPosition] = true; + unexploredStart.insert(designPosition); + } + } + } + + return false; +} + +void LinenTowelPatterns::addBranch() +{ + for (size_t i = 0; i < stripes_.size(); i++) + { + patterns_.emplace_back(std::make_pair(0, false)); + } +} diff --git a/tests/src/TestCases.cpp b/tests/src/TestCases.cpp index 81c1d4f..3e02b4e 100644 --- a/tests/src/TestCases.cpp +++ b/tests/src/TestCases.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #define REQUIRE_MESSAGE(cond, msg) if (!(cond)) { INFO(msg); REQUIRE(cond); } @@ -340,6 +341,19 @@ TEST_CASE("[RamRunTests]") } } +TEST_CASE("[LinenLayoutTests]") +{ + TestContext test; + SECTION("FullData") + { + test.run(std::make_unique(), 272, 0, test.getInputPaths()); + } + SECTION("ExampleData") + { + test.run(std::make_unique(), 6, 0, test.getExampleInputPaths()); + } +} + TEST_CASE("[LanPartyTests]") { TestContext test;