Convert day 19 part 1 to use regular expressions

master
Nick Krichevsky 2020-12-20 23:16:59 -05:00
parent ae8847bdd1
commit 196a679dc3
1 changed files with 49 additions and 57 deletions

View File

@ -1,3 +1,4 @@
#include <folly/Format.h>
#include <folly/String.h> #include <folly/String.h>
#include <fstream> #include <fstream>
@ -7,6 +8,7 @@
#include <memory> #include <memory>
#include <numeric> #include <numeric>
#include <optional> #include <optional>
#include <regex>
#include <string> #include <string>
#include <vector> #include <vector>
@ -92,76 +94,66 @@ MultiGrammarEntry parseSinglePattern(const std::string &rawPattern) {
return patternComponents; return patternComponents;
} }
std::unordered_map<int, AlternatableMultiGrammarEntry> parseGrammar(const std::vector<std::string> &patterns) { std::unordered_multimap<int, MultiGrammarEntry> parseGrammar(const std::vector<std::string> &patterns) {
std::unordered_map<int, AlternatableMultiGrammarEntry> grammar; std::unordered_multimap<int, MultiGrammarEntry> grammar;
std::transform( for (const std::string &patternLine : patterns) {
patterns.cbegin(), patterns.cend(), std::inserter(grammar, grammar.end()), [](const std::string &patternLine) { auto colonIndex = patternLine.find(":");
auto colonIndex = patternLine.find(":"); std::string rawIndex = patternLine.substr(0, colonIndex);
std::string rawIndex = patternLine.substr(0, colonIndex); int patternIndex = std::stoi(rawIndex);
int patternIndex = std::stoi(rawIndex); std::vector<std::string> rawAlternations;
std::vector<std::string> rawAlternations; // An extra +1 on the colon index to get rid of the space after the colon
// An extra +1 on the colon index to get rid of the space after the colon folly::split(ALTERNATING_DELIM, patternLine.substr(colonIndex + 2), rawAlternations);
folly::split(ALTERNATING_DELIM, patternLine.substr(colonIndex + 2), rawAlternations);
AlternatableMultiGrammarEntry entries; std::transform(
std::transform( rawAlternations.cbegin(),
rawAlternations.cbegin(), rawAlternations.cend(), std::back_inserter(entries), parseSinglePattern); rawAlternations.cend(),
std::inserter(grammar, grammar.end()),
return std::pair<int, AlternatableMultiGrammarEntry>(patternIndex, entries); [patternIndex](const std::string &pattern) {
}); return std::make_pair(patternIndex, parseSinglePattern(pattern));
});
}
return grammar; return grammar;
} }
int matchesHowManyChars( std::string convertToRegularExpression(const std::unordered_multimap<int, MultiGrammarEntry> &grammar, int rule) {
const std::unordered_map<int, AlternatableMultiGrammarEntry> &grammar, const std::string_view toParse, int rule = 0, std::vector<std::string> expressions;
int depth = 0) { auto ruleIterators = grammar.equal_range(rule);
auto indentation = std::string(depth, '|'); std::transform(
std::cout << indentation << "Working on " << toParse << std::endl; ruleIterators.first,
AlternatableMultiGrammarEntry ruleAlternations = grammar.at(rule); ruleIterators.second,
std::optional<std::pair<MultiGrammarEntry, int>> best; std::back_inserter(expressions),
for (const MultiGrammarEntry &alternation : ruleAlternations) { [&grammar](const std::pair<int, MultiGrammarEntry> &entry) {
int numMatched = 0; MultiGrammarEntry alternative = entry.second;
int i = 0; std::string expression;
for (auto entryIt = alternation.cbegin(); entryIt != alternation.cend(); (++entryIt, i++)) { for (const GrammarEntry &grammarEntry : alternative) {
GrammarEntry entry = *entryIt; if (grammarEntry.isLookup()) {
int ruleMatchCount; expression += convertToRegularExpression(grammar, grammarEntry.getIndex());
if (entry.isLookup()) { } else {
std::cout << indentation << "Checking rule " << entry.getIndex() << std::endl; expression += grammarEntry.getValue();
ruleMatchCount = matchesHowManyChars(grammar, toParse.substr(numMatched), entry.getIndex(), depth + 1); }
} else {
std::cout << indentation << "Checking rule " << entry.getValue() << std::endl;
char toMatch = toParse.at(i);
char ruleValue = entry.getValue();
ruleMatchCount = (toMatch == ruleValue);
} }
std::cout << indentation << "Result: " << numMatched << std::endl; return expression;
});
if (!ruleMatchCount) { if (expressions.size() == 1) {
break; return expressions.at(0);
} } else {
return folly::format("({})", folly::join("|", expressions)).str();
numMatched += ruleMatchCount;
}
std::cout << indentation << "Full result: " << numMatched << std::endl;
if (!best || numMatched > best->second) {
best = std::pair<MultiGrammarEntry, int>(alternation, numMatched);
}
} }
}
if (!best) { std::regex convertToRegularExpression(const std::unordered_multimap<int, MultiGrammarEntry> &grammar) {
return 0; auto rawRegularExpression = convertToRegularExpression(grammar, 0);
} return std::regex(rawRegularExpression);
return best->second;
} }
int part1(const std::vector<std::string> &patterns, const std::vector<std::string> &testStrings) { int part1(const std::vector<std::string> &patterns, const std::vector<std::string> &testStrings) {
std::unordered_map<int, AlternatableMultiGrammarEntry> grammar = parseGrammar(patterns); std::unordered_multimap<int, MultiGrammarEntry> grammar = parseGrammar(patterns);
return std::count_if(testStrings.cbegin(), testStrings.cend(), [&grammar](const std::string &testString) { std::regex inputRegex = convertToRegularExpression(grammar);
return matchesHowManyChars(grammar, testString) == testString.length(); return std::count_if(testStrings.cbegin(), testStrings.cend(), [&inputRegex](const std::string &testString) {
return std::regex_match(testString, inputRegex);
}); });
} }