From 0febe907d18c670655756241cc319ce527ea3151 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Tue, 12 Dec 2023 10:03:09 +0000 Subject: [PATCH] 2023 Day 12 Part 2 Proposed soln Needs optimisation. --- 2023/puzzle-12-02.cc | 132 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 2023/puzzle-12-02.cc diff --git a/2023/puzzle-12-02.cc b/2023/puzzle-12-02.cc new file mode 100644 index 0000000..f43bc60 --- /dev/null +++ b/2023/puzzle-12-02.cc @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include + +using UInt = std::uint64_t; +using StringVec = std::vector; +using UIntVec = std::vector; +using Pos = std::pair; +using PosVec = std::vector; + +auto split(std::string_view line) -> std::pair +{ + auto pos = line.find(' '); + auto pattern = line.substr(0, pos); + UIntVec nums; + + line = line.substr(pos); + while (!line.empty()) { + line = line.substr(1); + char* n{nullptr}; + nums.emplace_back(std::strtoll(line.data(), &n, 10)); + line = line.substr(n - line.data()); + } + + return std::make_pair(pattern, nums); +} + +[[nodiscard]] auto validate_subpattern(std::string_view pattern, std::string_view start, + UInt num_hashs, UInt gaps) -> bool +{ + if (pattern.size() < start.size()) { + return false; + } + UInt hash_count{0}; + + auto pit{pattern.begin()}; + for (auto sit{start.begin()}; sit != start.end(); ++pit, ++sit) { + if (*sit == '#') { ++hash_count; } + if (*pit != '?' && *pit != *sit) { + return false; + } + } + + for (; pit != pattern.end(); ++pit) { + if (*pit == '#') { ++hash_count; } + } + + if (num_hashs < hash_count) { + return false; + } + if (start.size() + (num_hashs - hash_count) + gaps > pattern.size()) { + return false; + } + + return true; +} + +void generate_pattern(std::string start, UIntVec::const_iterator it, UIntVec::const_iterator end, + std::string_view pattern, UInt hash_count, UInt& count) +{ + for (std::size_t p{0}; p + start.size() < pattern.size() && p < *it; ++p) { + if (pattern[start.size() + p] == '.') { return; } + } + start += std::string(*it++, '#'); + + if (it == end) { + if (start.size() <= pattern.size()) { + start.resize(pattern.size(), '.'); + if (validate_subpattern(pattern, start, hash_count, end - it - 1)) { + ++count; + if (count % 100'000 == 0) { + std::cout << start << '\n'; + } + } + } + return; + } + + start += '.'; + while (validate_subpattern(pattern, start, hash_count, end - it - 1)) { + generate_pattern(start, it, end, pattern, hash_count, count); + start += '.'; + } +} + +auto valid_sequences(std::string_view pattern, UIntVec const& nums) -> UInt +{ + UInt count{0}; + UInt hash_count{0}; + for (auto num : nums) { hash_count += num; } + std::string start; + while (validate_subpattern(pattern, start, hash_count, nums.size() - 1)) { + std::cout << start << '\n'; + generate_pattern(start, nums.begin(), nums.end(), pattern, hash_count, count); + start += '.'; + } + + return count; +} + +auto main() -> int try { + std::string line; + UInt count{0}; + + while (std::getline(std::cin, line)) { + auto [pattern, nums] = split(line); + UInt line_count{0}; + std::string unfolded_pattern{pattern}; + UIntVec unfolded_nums{nums.begin(), nums.end()}; + for (unsigned i = 1; i < 5; ++i) { + unfolded_pattern += '?'; + unfolded_pattern += pattern; + unfolded_nums.insert(unfolded_nums.begin(), nums.begin(), nums.end()); + } + + line_count += valid_sequences(unfolded_pattern, unfolded_nums); + std::cout << line << ": " << line_count << '\n'; + count += line_count; + } + + std::cout << "Valid sequences: " << count << '\n'; + + return EXIT_SUCCESS;; +} +catch (...) { + std::cerr << "Uncaught exception.\n"; + return EXIT_FAILURE; +}