AdventOfCode2024/src/extra/LinenTowelPatterns.cpp

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