Add solution for 2015 Day 19
This commit is contained in:
@@ -13,7 +13,7 @@ for item in $list; do
|
||||
dir="res/$year/day$day/input.txt"
|
||||
if [ ! -e $dir ]; then
|
||||
webitem=${day#0}
|
||||
echo "Fetching $dir"
|
||||
echo "Fetching $dir from https://adventofcode.com/$year/day/$webitem/input"
|
||||
tmp_file=$(mktemp)
|
||||
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
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
e => H
|
||||
e => O
|
||||
H => HO
|
||||
H => OH
|
||||
O => HH
|
||||
|
||||
HOHOHO
|
||||
|
||||
+250
-9
@@ -2,30 +2,271 @@
|
||||
|
||||
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_TEST(2015, Day19, Input, 1, 0);
|
||||
REGISTER_TEST_EXAMPLE(2015, Day19, ExampleInput, 2, 0);
|
||||
REGISTER_TEST(2015, Day19, Input, 2, 0);
|
||||
REGISTER_DAY(2015, Day19, Input, int);
|
||||
|
||||
REGISTER_TEST_EXAMPLE(2015, Day19, ExampleInput, 1, 7);
|
||||
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)
|
||||
{
|
||||
std::vector<int> vec;
|
||||
Input i;
|
||||
std::string 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,9 +49,9 @@ struct Helper
|
||||
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)
|
||||
@@ -59,6 +59,11 @@ struct Helper
|
||||
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)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
|
||||
Reference in New Issue
Block a user