/******************************************************************************* * * 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); }