From 7bae590b2036ceb36a09acbfc7a7624e67c141bd Mon Sep 17 00:00:00 2001 From: Eric Mertens Date: Tue, 15 Nov 2022 17:13:09 -0800 Subject: [PATCH] 21 --- 2019/21.cpp | 324 ++++++++++++++++++++++++++++++++++++++++++++ 2019/CMakeLists.txt | 3 + 2 files changed, 327 insertions(+) create mode 100644 2019/21.cpp diff --git a/2019/21.cpp b/2019/21.cpp new file mode 100644 index 0000000..f88b1e4 --- /dev/null +++ b/2019/21.cpp @@ -0,0 +1,324 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace aocpp; +using namespace intcode; + +namespace { + +auto OffByOne ( + std::string const& x, + std::string const& y +) -> std::size_t +{ + auto const [it_x, it_y] = std::mismatch(x.begin(), x.end(), y.begin()); + return + (it_x != x.end() && + *it_x == '.' && + *it_y == '#' && + std::equal(it_x+1, x.end(), it_y+1)) + ? std::distance(x.begin(), it_x) + : std::string::npos; +} + +auto CountOnes(std::string const& key) -> std::size_t { + return std::count_if(key.begin(), key.end(), [](auto c) { return c == '#'; }); +} + +auto QuineMcCluskey( + bool const polarity, + std::size_t const vars, + std::map const& behavior +) { + std::set done; + std::vector> current; + current.resize(vars+1); + bool working = true; + + for (std::size_t i = 0; i < (std::size_t(1)<second) { + done.insert(key); + current[CountOnes(key)].insert(key); + } + } + + while (working) { + working = false; + std::vector> nextbatch; + nextbatch.resize(current.size()-1); + + for (std::size_t ones = 0; ones+1 < nextbatch.size(); ones++) { + if (!current[ones+1].empty()) { + for (auto const& t1 : current[ones]) { + for (auto const& t2 : current[ones+1]) { + if (auto ix = OffByOne(t1, t2); ix != std::string::npos) { + auto d1 = done.erase(t1); + auto d2 = done.erase(t2); + + auto key = t1; + key[ix] = '-'; + nextbatch[ones].insert(key); + working = true; + + if (d1 || d2) done.insert(key); + } + } + } + } + } + current = nextbatch; + } + + return done; +} + +auto RunStream( + Machine m, + std::istream & in, + std::ostream & out +) -> ValueType +{ + ValueType answer {}; + Run(m, + [&]() -> ValueType { return in.get(); }, + [&](ValueType o) { + if (o < 256) out << char(o); else answer = o; }); + return answer; +} + +auto GetCounterExample(std::istream & in) -> std::string { + std::string line1, line2, line3, line4; + + // Skip lines until the counter example starts + while(std::getline(in, line1)) { + if (line1 == "Didn't make it across:") { + break; + } + } + + std::string result; + + while (std::getline(in, line1)) { // whitespace + std::getline(in, line1); // air + std::getline(in, line2); // air + std::getline(in, line3); // air + std::getline(in, line4); // platform + + std::size_t at_index; + if ((at_index = line1.find('@')) != std::string::npos) { + result += line4[at_index]; + } else if ((at_index = line2.find('@')) != std::string::npos) { + result += line4[at_index]; + } else if ((at_index = line3.find('@')) != std::string::npos) { + result += line4[at_index]; + if (line4[at_index] == '.') { + result += line4.substr(at_index+1); + return result; + } + } else { + at_index = line4.find('@'); + result += '.'; + result += line4.substr(at_index+1); + return result; + } + } + + return ""; +} + +auto LearnExample( + std::vector const& window, + std::map & behavior, + std::string::const_iterator begin, + std::string::const_iterator const end, + auto on_success +) -> void +{ +top: + // Standing on a hole; game over + if (*begin == '.') return; + + // Reached the end of the platform, report success + if (std::all_of(begin, end, [](auto c) { return c == '#'; })) { + on_success(); return; + } + + // Compute the sensor values + std::string key; + std::size_t tail = std::distance(begin, end); + for (auto i : window) { + key += i < tail ? begin[i] : '#'; + } + + auto [it, added] = behavior.try_emplace(std::move(key), false); + if (!added) { + // We've seen this sensor value before, do the same thing as last time + begin += it->second ? 4 : 1; + goto top; + } else { + LearnExample(window, behavior, begin + 1, end, on_success); + it->second = true; + LearnExample(window, behavior, begin + 4, end, on_success); + behavior.erase(it); + } +} + +auto LearnAll( + std::vector const& window, + std::map & behavior, + std::vector::const_iterator const example, + std::vector::const_iterator const end, + auto k +) -> void +{ + if (example == end) { + k(); + } else { + LearnExample( + window, behavior, + example->begin(), + example->end(), + [&]() { + LearnAll(window, behavior, std::next(example), end, k); + }); + } + +} + +auto EnhanceSensors( + std::size_t const n, + std::vector> const& previous +) { + std::vector> result; + + for (auto const& v : previous) { + auto const start = v.empty() ? 1 : v.back() + 1; + for (std::size_t i = start; i <= n; i++) { + result.push_back(v); + result.back().push_back(i); + } + } + return result; +} + +auto Compute( + Machine machine, + std::size_t const maxsensors, + std::vector const& examples, + char const* const input +) { + + std::istringstream in {input}; + std::stringstream out; + auto const output = RunStream(machine, in, out); + + if (output > 0) { + std::cout << "Hull damage: " << output << std::endl; + } else { + std::cout << "Learned " << GetCounterExample(out) << std::endl; + } + + std::vector> sensors {{}}; + bool searching = true; + while(searching && !sensors.empty()) { + for (auto const& sensor : sensors) { + std::map cases; + LearnAll(sensor, cases, examples.begin(), examples.end(), [&]() { + searching = false; + for (bool const p : {true,false}) { + auto const terms = QuineMcCluskey(p, sensor.size(), cases); + std::cout << (p ? "\nTRUE\n" : "\nFALSE\n"); + for (auto const s : sensor) { + std::cout << char('A'+s); + } + std::cout << std::endl; + for (auto const& term : terms) { + std::cout << term << std::endl; + } + } + }); + } + if (searching) { + sensors = EnhanceSensors(maxsensors, sensors); + } + } +} + +} // namespace + +auto main(int argc, char** argv) -> int { + Machine machine {ParseStream(aocpp::Startup(argc, argv))}; + + Compute(machine, 4, + { "#####.###########", + "#####.##.########", + "#####.#.#########", + "#####.#..########" + "#####..#.########", + "#####...#########", + }, + "OR A J\n" + "AND C J\n" + "NOT J J\n" + "AND D J\n" + "WALK\n" + ); + // FALSE + // BDE + // ##- + // --. + // n(AC or nD) + // n(AC) and D + + Compute(std::move(machine), 9, + { "#####.############", + "#####.###...#.####", + "#####.##.#########", + "#####.##.##...####", + "#####.#.##########", + "#####.#.##..#.####", + "#####.#.##...#####", + "#####.#.#.##..####", + "#####.#..#########", + "#####..###.#..####", + "#####..##.#.######", + "#####..#.#########", + "#####..#.###.#####", + "#####...##########", + "#####...####..####", + }, + "NOT H J\n" + "OR C J\n" + "AND B J\n" + "AND A J\n" + "NOT J J\n" + "AND D J\n" + "RUN\n" + ); + // FALSE + // 3 + // ABCDH + // ###-- + // ##--. + // ---.- + // + // n(ABC or ABnH or nD) + // n(AB(C or nH) or nD) + // n(AB(C or nH)) and D +} diff --git a/2019/CMakeLists.txt b/2019/CMakeLists.txt index 7ad5c2d..d453df4 100644 --- a/2019/CMakeLists.txt +++ b/2019/CMakeLists.txt @@ -55,6 +55,9 @@ target_link_libraries(19 aocpp intcode) add_executable(20 20.cpp) target_link_libraries(20 aocpp) +add_executable(21 21.cpp) +target_link_libraries(21 aocpp intcode) + add_executable(22 22.cpp) target_link_libraries(22 aocpp zmod)