From 312167908709bfdc929dae8e583b863b491a0445 Mon Sep 17 00:00:00 2001 From: Gnarwhal Date: Sat, 19 Dec 2020 00:39:13 -0800 Subject: [PATCH] Completed day 19 --- 2020/days/day19.cpp | 195 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 2020/days/day19.cpp diff --git a/2020/days/day19.cpp b/2020/days/day19.cpp new file mode 100644 index 0000000..9f3ed8c --- /dev/null +++ b/2020/days/day19.cpp @@ -0,0 +1,195 @@ +/******************************************************************************* + * + * Copyright (c) 2020 Gnarwhal + * + * ----------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files(the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + *******************************************************************************/ + +#include +#include +#include +#include +#include + +#include "../misc/types.hpp" +#include "../misc/print.hpp" + +enum RuleType { Char, Sequence, Alternator }; + +struct Rule { + RuleType type; + char c; + std::vector list; + std::vector> or_list; + + explicit Rule(char c) noexcept : type(Char), c(c) {} + explicit Rule(std::vector && list) noexcept : type(Sequence), list(std::move(list)) {} + explicit Rule(std::vector> && or_list) noexcept : type(Alternator), or_list(std::move(or_list)) {} +}; + +auto extract_numbers(const std::string & list) -> std::vector { + auto nums = std::vector(); + auto end = usize(0); + auto start = usize(0); + while ((end = list.find(" ", ++end)) != std::string::npos) { + nums.push_back(std::stoll(list.substr(start, end - start))); + start = end + 1; + } + return std::move(nums); +} + +auto matches(const std::string & string, usize & index, std::unordered_map & rules, u64 rule_id, bool sub) -> bool; + +auto matches_list(const std::string & string, usize & index, std::unordered_map & rules, const std::vector & rule_ids, bool sub) -> bool { + auto local_index = index; + for (auto i = usize(0); i < rule_ids.size(); ++i) { + if (!matches(string, local_index, rules, rule_ids[i], true)) { + return false; + } + } + index = local_index; + return (sub || index == string.size()); +} + +auto matches(const std::string & string, usize & index, std::unordered_map & rules, u64 rule_id, bool sub) -> bool { + if (index >= string.size()) { + return false; + } + auto & rule = rules.find(rule_id)->second; + switch (rule.type) { + case Char: { + if (string[index] == rule.c) { + ++index; + return (sub || index == string.size()); + } else { + return false; + } + } + case Sequence: { + return matches_list(string, index, rules, rule.list, sub); + } + case Alternator: { + for (auto i = usize(0); i < rule.or_list.size(); ++i) { + auto local_index = index; + if (matches_list(string, local_index, rules, rule.or_list[i], sub)) { + index = local_index; + return true; + } + } + return false; + } + } + // むだ!makes the compiler happy though + return false; +} + +auto min_length(std::unordered_map & rules, u64 rule_id) -> usize; + +auto min_length_list(std::unordered_map & rules, const std::vector & rule_ids) -> usize { + auto len = usize(0); + for (auto i = usize(0); i < rule_ids.size(); ++i) { + len += min_length(rules, rule_ids[i]); + } + return len; +} + +auto min_length(std::unordered_map & rules, u64 rule_id) -> usize { + auto & rule = rules.find(rule_id)->second; + switch (rule.type) { + case Char: return 1; + case Sequence: return min_length_list(rules, rule.list); + case Alternator: { + auto min = min_length_list(rules, rule.or_list[0]); + for (auto i = usize(1); i < rule.or_list.size(); ++i) { + auto len = min_length_list(rules, rule.or_list[i]); + if (len < min) { + min = len; + } + } + return min; + } + } + // このもむだ! + return 0; +} + +auto day19() -> void { + auto rules = std::unordered_map(); + auto strings = std::vector(); + { + auto line = std::string(); + auto file = std::ifstream("inputs/day19.input"); + getline(file, line); + while (line != "") { + auto end = line.find(":"); + auto id = std::stoll(line.substr(0, end)); + if ((end = line.find("\"")) != std::string::npos) { + rules.insert_or_assign(id, Rule(line[end + 1])); + } else if (line.find("|") != std::string::npos) { + end = line.find(":") + 2; + line = line.substr(end, line.size() - end) + " |"; + auto sequences = std::vector>(); + end = usize(0); + auto start = usize(0); + while ((end = line.find("|", ++end)) != std::string::npos) { + sequences.push_back(extract_numbers(line.substr(start, end - start))); + start = end + 2; + } + rules.insert_or_assign(id, Rule(std::move(sequences))); + } else { + end = line.find(":") + 2; + rules.insert_or_assign(id, Rule(extract_numbers(line.substr(end, line.size() - end) + ' '))); + } + getline(file, line); + } + while (getline(file, line)) { + strings.push_back(std::move(line)); + } + } + + auto successful = usize(0); + for (auto i = usize(0); i < strings.size(); ++i) { + auto index = usize(0); + successful += matches(strings[i], index, rules, 0, false); + } + print(successful); + + successful = usize(0); + auto min_length42 = min_length(rules, 42); + auto min_length31 = min_length(rules, 31); + for (auto i = usize(0); i < strings.size(); ++i) { + auto unsuccessful = true; + auto base = min_length42 * 2 + min_length31; + auto list = std::vector{ 42, 42, 31 }; + for (auto j = usize(0); unsuccessful && j * min_length42 + base <= strings[i].size(); ++j) { + auto copy = list; + for (auto k = usize(0); unsuccessful && k <= j; ++k) { + auto index = usize(0); + unsuccessful = !matches_list(strings[i], index, rules, copy, false); + copy.push_back(31); + } + list.insert(list.begin(), 42); + } + successful += !unsuccessful; + } + print(successful); +}