100 lines
3.1 KiB
C++
100 lines
3.1 KiB
C++
// 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/LinenTowelPatterns.hpp>
|
|
|
|
#include <set>
|
|
|
|
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;
|
|
}
|
|
|
|
int64_t LinenTowelPatterns::countArrangements(const std::string& design)
|
|
{
|
|
std::vector<bool> canStartFrom(design.size() + 1, false);
|
|
canStartFrom[0] = true;
|
|
std::vector<int64_t> nArrangements(design.size() + 1, 0);
|
|
nArrangements[0] = 1;
|
|
size_t startPosition{ 0 };
|
|
|
|
while (startPosition < design.size())
|
|
{
|
|
size_t designPosition{ startPosition };
|
|
|
|
size_t i{ stripes_[design[designPosition]] };
|
|
while (++designPosition < design.size() && patterns_[i].first > 0)
|
|
{
|
|
// Checks if there is a towel with the current accumulated stripe pattern.
|
|
if (patterns_[i].second)
|
|
{
|
|
canStartFrom[designPosition] = true;
|
|
nArrangements[designPosition] += nArrangements[startPosition];
|
|
}
|
|
// Checks if the current accumulated stripe pattern can be extended further.
|
|
if (patterns_[i].first > 0)
|
|
{
|
|
i = patterns_[i].first + stripes_[design[designPosition]];
|
|
}
|
|
}
|
|
// Checks if there is a towel with the current accumulated stripe pattern, after its final extension.
|
|
if (patterns_[i].second)
|
|
{
|
|
canStartFrom[designPosition] = true;
|
|
nArrangements[designPosition] += nArrangements[startPosition];
|
|
}
|
|
|
|
// Seeks the next start position.
|
|
do
|
|
{
|
|
startPosition++;
|
|
} while (startPosition < canStartFrom.size() && !canStartFrom[startPosition]);
|
|
}
|
|
|
|
return nArrangements.back();
|
|
}
|
|
|
|
void LinenTowelPatterns::addBranch()
|
|
{
|
|
for (size_t i = 0; i < stripes_.size(); i++)
|
|
{
|
|
patterns_.emplace_back(std::make_pair<size_t, bool>(0, false));
|
|
}
|
|
}
|