Add solution for 2015 Day 19

This commit is contained in:
Thraix
2026-07-29 00:30:29 +02:00
parent ce9bc29372
commit 9ef2809593
4 changed files with 265 additions and 12 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ for item in $list; do
dir="res/$year/day$day/input.txt" dir="res/$year/day$day/input.txt"
if [ ! -e $dir ]; then if [ ! -e $dir ]; then
webitem=${day#0} webitem=${day#0}
echo "Fetching $dir" echo "Fetching $dir from https://adventofcode.com/$year/day/$webitem/input"
tmp_file=$(mktemp) tmp_file=$(mktemp)
HTTP_CODE=$(curl -s -w "%{http_code}" -o "$tmp_file" --cookie cookies.txt https://adventofcode.com/$year/day/$webitem/input) HTTP_CODE=$(curl -s -w "%{http_code}" -o "$tmp_file" --cookie cookies.txt https://adventofcode.com/$year/day/$webitem/input)
if [ "$HTTP_CODE" -eq 200 ]; then if [ "$HTTP_CODE" -eq 200 ]; then
+7
View File
@@ -0,0 +1,7 @@
e => H
e => O
H => HO
H => OH
O => HH
HOHOHO
+250 -9
View File
@@ -2,30 +2,271 @@
namespace y2015::day19 namespace y2015::day19
{ {
REGISTER_DAY(2015, Day19, std::vector<int>, int); struct Input
{
std::multimap<std::string, std::string> conversions;
std::string molecule;
};
REGISTER_TEST_EXAMPLE(2015, Day19, ExampleInput, 1, 0); REGISTER_DAY(2015, Day19, Input, int);
REGISTER_TEST(2015, Day19, Input, 1, 0);
REGISTER_TEST_EXAMPLE(2015, Day19, ExampleInput, 2, 0); REGISTER_TEST_EXAMPLE(2015, Day19, ExampleInput, 1, 7);
REGISTER_TEST(2015, Day19, Input, 2, 0); REGISTER_TEST(2015, Day19, Input, 1, 576);
// REGISTER_TEST_EXAMPLE(2015, Day19, ExampleInput, 2, 6);
REGISTER_TEST(2015, Day19, Input, 2, 207);
READ_INPUT(input) READ_INPUT(input)
{ {
std::vector<int> vec; Input i;
std::string str; std::string str;
while (getline(input, str)) while (getline(input, str))
{ {
if (str.empty())
break;
std::string from;
std::string to;
std::stringstream ss{str};
ss >> from >> "=>" >> to;
i.conversions.emplace(from, to);
} }
return vec; getline(input, i.molecule);
return i;
}
std::vector<size_t> FindAll(const std::string& str, const std::string& find)
{
std::vector<size_t> positions;
size_t pos = str.find(find);
while (pos != std::string::npos)
{
positions.emplace_back(pos);
pos = str.find(find, pos + 1);
}
return positions;
}
bool IsAtom(const std::string& sv)
{
std::regex regex{"^(e|[A-Z][a-z]?)$"};
return std::regex_match(sv, regex);
}
std::string Prettify(const std::string& molecule)
{
std::string result = molecule;
for (size_t i = 0; i < result.size(); i++)
{
if (Helper::StartsWith(result, "Rn", i))
{
result.replace(i, 2, "(");
i--;
}
else if (Helper::StartsWith(result, "Ar", i))
{
result.replace(i, 2, ")");
i--;
}
else if (Helper::StartsWith(result, "Y", i))
{
result.replace(i, 1, ",");
}
}
return result;
}
std::pair<std::string, int> Solve(const std::string& molecule,
const std::multimap<std::string, std::string>& conversions,
std::map<std::string, std::pair<std::string, int>>& memoization);
void Solve(std::string& molecule,
int& steps,
size_t& offset,
size_t pos,
size_t size,
const std::multimap<std::string, std::string>& conversions,
std::map<std::string, std::pair<std::string, int>>& memoization)
{
std::string toReduce = molecule.substr(pos, size);
auto [solveStr, solveSteps] = Solve(toReduce, conversions, memoization);
Helper::Replace(molecule, toReduce.size(), solveStr, pos);
steps += solveSteps;
offset -= toReduce.size() - solveStr.size();
}
void SolveRnAr(std::string& molecule,
int& steps,
const std::multimap<std::string, std::string>& conversions,
std::map<std::string, std::pair<std::string, int>>& memoization)
{
// Solve all parts between Rn and Ar
int stack = 0;
size_t position = 0;
for (size_t i = 0; i < molecule.size(); i++)
{
if (Helper::StartsWith(molecule, "Rn", i))
{
if (stack == 0)
position = i + 2;
i++;
stack++;
}
else if (Helper::StartsWith(molecule, "Ar", i))
{
stack--;
if (stack == 0)
{
Solve(molecule, steps, i, position, i - position, conversions, memoization);
}
i++;
}
}
}
bool SolveY(std::string& molecule,
int& steps,
const std::multimap<std::string, std::string>& conversions,
std::map<std::string, std::pair<std::string, int>>& memoization)
{
// Reduce all parts split by Y
int stack = 0;
size_t position = 0;
bool hasY = false;
for (size_t i = 0; i < molecule.size(); i++)
{
if (Helper::StartsWith(molecule, "Rn", i))
stack++;
else if (Helper::StartsWith(molecule, "Ar", i))
stack--;
if (Helper::StartsWith(molecule, "Y", i))
{
if (stack != 0)
continue;
hasY = true;
Solve(molecule, steps, i, position, i - position, conversions, memoization);
position = i + 1;
}
}
if (hasY)
{
size_t i = 0;
Solve(molecule, steps, i, position, molecule.size(), conversions, memoization);
return true;
}
return false;
}
void SolveAr(std::string& molecule,
int& steps,
const std::multimap<std::string, std::string>& conversions,
std::map<std::string, std::pair<std::string, int>>& memoization)
{
// Reduce all parts ending with Ar (except the last one)
for (size_t i = 0; i < molecule.size(); i++)
{
if (Helper::StartsWith(molecule, "Ar", i) && i != molecule.size() - 2)
{
Solve(molecule, steps, i, 0, i + 2, conversions, memoization);
}
}
}
std::pair<std::string, int> SolveToAtom(const std::string& molecule,
const std::multimap<std::string, std::string>& conversions,
std::map<std::string, std::pair<std::string, int>>& memoization)
{
if (IsAtom(molecule))
return {molecule, 0};
auto it = memoization.find(molecule);
if (it != memoization.end())
return it->second;
int steps = std::numeric_limits<int>::max();
std::string result = ".";
for (const auto& [from, to] : conversions)
{
std::vector<size_t> positions = FindAll(molecule, from);
for (const auto& pos : positions)
{
std::string moleculeCpy = molecule;
moleculeCpy.replace(pos, from.size(), to);
auto [solveStr, solveSteps] = SolveToAtom(moleculeCpy, conversions, memoization);
if (solveStr == ".")
continue;
if (solveSteps < steps)
{
steps = solveSteps;
result = solveStr;
}
}
}
memoization[molecule] = {result, steps + 1};
return {result, steps + 1};
}
void SolveToAtom(std::string& molecule,
int& steps,
const std::multimap<std::string, std::string>& conversions,
std::map<std::string, std::pair<std::string, int>>& memoization)
{
// Reduce the rest
auto [solveStr, solveSteps] = SolveToAtom(molecule, conversions, memoization);
if (solveStr == ".")
{
std::cout << "No solution found for: " << molecule << std::endl;
}
Helper::Replace(molecule, molecule.size(), solveStr, 0);
steps += solveSteps;
}
std::pair<std::string, int> Solve(const std::string& molecule,
const std::multimap<std::string, std::string>& conversions,
std::map<std::string, std::pair<std::string, int>>& memoization)
{
if (IsAtom(molecule))
return {molecule, 0};
std::string result = molecule;
int steps = 0;
SolveRnAr(result, steps, conversions, memoization);
if (SolveY(result, steps, conversions, memoization))
return {result, steps};
SolveAr(result, steps, conversions, memoization);
SolveToAtom(result, steps, conversions, memoization);
return {result, steps};
} }
OUTPUT1(input) OUTPUT1(input)
{ {
return 0; std::set<std::string> uniques;
for (const auto& [from, to] : input.conversions)
{
std::vector<size_t> positions = FindAll(input.molecule, from);
for (const auto& pos : positions)
{
std::string str = input.molecule;
Helper::Replace(str, from.size(), to, pos);
uniques.emplace(str);
}
}
return uniques.size();
} }
OUTPUT2(input) OUTPUT2(input)
{ {
return 0; std::multimap<std::string, std::string> reverse;
for (const auto& [from, to] : input.conversions)
{
reverse.emplace(to, from);
}
std::map<std::string, std::pair<std::string, int>> memoization;
return Solve(input.molecule, reverse, memoization).second;
} }
} }
+7 -2
View File
@@ -49,9 +49,9 @@ struct Helper
t.erase(std::remove_if(t.begin(), t.end(), func), t.end()); t.erase(std::remove_if(t.begin(), t.end(), func), t.end());
} }
static bool StartsWith(const std::string_view& str, const std::string& prefix) static bool StartsWith(const std::string_view& str, const std::string& prefix, size_t offset = 0)
{ {
return str.substr(0, prefix.size()) == prefix; return str.substr(offset, prefix.size()) == prefix;
} }
static bool EndsWith(const std::string_view& str, const std::string& prefix) static bool EndsWith(const std::string_view& str, const std::string& prefix)
@@ -59,6 +59,11 @@ struct Helper
return str.substr(str.size() - prefix.size(), prefix.size()) == prefix; return str.substr(str.size() - prefix.size(), prefix.size()) == prefix;
} }
static void Replace(std::string& str, size_t size, const std::string& other, size_t pos)
{
str.replace(pos, size, other);
}
static bool IsDigit(char c) static bool IsDigit(char c)
{ {
return c >= '0' && c <= '9'; return c >= '0' && c <= '9';