Files
advent-of-code/2015/puzzle-19-02.cc

210 lines
6.1 KiB
C++

#include <cassert>
#include <cctype>
#include <climits>
#include <functional>
#include <iostream>
#include <map>
#include <numeric>
#include <random>
#include <regex>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <variant>
template<typename Map>
std::size_t dedup(Map const& replacements, std::string& molecule)
{
std::size_t steps = 0;
for (auto const& kv : replacements) {
if (kv.first != kv.second + kv.second) {
continue;
}
std::size_t pos = std::string::npos;
do {
pos = molecule.find(kv.first);
if (pos != std::string::npos) {
molecule = molecule.substr(0, pos) + kv.second + molecule.substr(pos + kv.first.size());
++steps;
}
} while (pos != std::string::npos);
}
return steps;
}
#if 0
std::size_t
simple_find(std::unordered_map<std::string, std::string> const &replacements,
std::string &molecule) {
std::size_t steps = 0;
bool changed = true;
while (!molecule.empty() && molecule != "e" && changed) {
changed = false;
for (auto const &kv : replacements) {
std::size_t pos = 0;
while (pos != std::string::npos) {
pos = molecule.find(kv.first, pos);
if (pos != std::string::npos) {
auto nm = molecule.substr(0, pos) + kv.second +
molecule.substr(pos + kv.first.size());
bool good = true;
for (auto const &kv2 : replacements) {
auto left =
std::max(kv2.first.size() - 1, pos) + 1 - kv2.first.size();
if (nm.substr(left, kv2.first.size() * 2 + kv.second.size() - 2)
.find(kv2.first) != std::string::npos) {
good = false;
break;
}
}
if (good) {
++steps;
// std::cout << "Step: " << steps << ": " << molecule << " => " <<
// nm
// << "\n";
molecule = nm;
changed = true;
}
++pos;
}
}
}
}
return steps;
}
std::size_t
find_molecule(std::unordered_map<std::string, std::string> const &replacements,
std::string const &m) {
std::string molecule = m;
std::size_t steps = 0;
steps += dedup(replacements, molecule);
steps += simple_find(replacements, molecule);
std::unordered_map<std::string, std::size_t> current_molecules = {
{molecule, steps}};
while (!current_molecules.empty() &&
current_molecules.find("e") == current_molecules.end()) {
std::unordered_map<std::string, std::size_t> new_molecules;
std::size_t mi = 0;
for (auto const &m : current_molecules) {
++mi;
std::string molecule = m.first;
std::size_t steps = m.second;
++steps;
for (auto const &kv : replacements) {
std::size_t pos = 0;
while (pos != std::string::npos) {
pos = molecule.find(kv.first, pos);
if (pos != std::string::npos) {
bool good = false;
auto nm = molecule.substr(0, pos) + kv.second +
molecule.substr(pos + kv.first.size());
for (auto const &kv2 : replacements) {
auto left = std::max(kv2.first.size(), pos) - kv2.first.size();
if (nm.substr(left, kv2.first.size() * 2 + kv.second.size())
.find(kv2.first) != std::string::npos) {
good = true;
break;
}
}
if (good) {
auto ns = steps;
ns += dedup(replacements, nm);
ns += simple_find(replacements, nm);
std::cout << '\r' << steps << ": " << mi << " " << kv.first
<< " => "
<< kv.second; //<< " ==> "
// << nm << "\n";
auto [it, success] = new_molecules.insert({nm, ns});
if (!success) {
it->second = std::min(it->second, ns);
}
}
++pos;
}
}
}
}
current_molecules = std::move(new_molecules);
std::cout << "\nStep " << 1000000 << " : " << current_molecules.size()
<< " modulecules.\n"
<< std::flush;
}
std::cout << "\n";
return current_molecules.find("e")->second;
}
#endif
template<typename Map>
bool is_good_replacement(Map const& replacements, std::string const& nm, std::size_t pos,
std::size_t replace_len)
{
for (auto const& kv : replacements) {
auto left = std::max(kv.first.size(), pos) - kv.first.size();
if (nm.substr(left, kv.first.size() * 2 + replace_len).find(kv.first) != std::string::npos) {
return true;
}
}
return false;
}
template<typename Map>
std::size_t find_molecule(Map& replacements, std::string const& molecule)
{
std::random_device rd;
std::mt19937 g(rd());
while (true) {
std::string m = molecule;
bool changed = true;
std::shuffle(replacements.begin(), replacements.end(), g);
std::size_t steps = 0;
do {
changed = false;
for (auto const& kv : replacements) {
auto pos = m.find(kv.first);
if (pos != std::string::npos) {
m = m.substr(0, pos) + kv.second + m.substr(pos + kv.first.length());
std::cout << "\r" << steps << " ";
++steps;
changed = true;
if (m == "e") {
std::cout << '\n';
return steps;
}
}
}
std::cout << '\n';
} while (changed);
}
}
int main(int argc, char** argv)
{
std::vector<std::pair<std::string, std::string>> replacements;
bool collecting_replacements = true;
std::string line;
while (std::getline(std::cin, line)) {
if (line.empty()) {
collecting_replacements = false;
}
else if (collecting_replacements) {
auto sep = line.find(" => ");
replacements.push_back({line.substr(sep + 4), line.substr(0, sep)});
}
else {
std::cout << line << "\n";
auto time = find_molecule(replacements, line);
std::cout << "Solution: " << time << "\n";
}
}
return 0;
}