From 2566a75466cdde8d682e36fe000e34b09e6d3d90 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Thu, 16 Dec 2021 13:59:58 +0000 Subject: [PATCH] Add 2017 day 16 puzzles. --- 2017/puzzle-16-01.cc | 102 ++++++++++++++++++++++++++++++++ 2017/puzzle-16-02.cc | 136 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 2017/puzzle-16-01.cc create mode 100644 2017/puzzle-16-02.cc diff --git a/2017/puzzle-16-01.cc b/2017/puzzle-16-01.cc new file mode 100644 index 0000000..107c9ab --- /dev/null +++ b/2017/puzzle-16-01.cc @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include + +using UInt = unsigned long; + +auto spin(std::string const& s, UInt num) -> std::string +{ + assert(num < s.size()); + + std::string result; + result.reserve(s.size()); + auto inserter{std::back_inserter(result)}; + std::copy(s.end() - num, s.end(), inserter); + std::copy(s.begin(), s.end() - num, inserter); + return result; +} + +auto exchange(std::string const& s, UInt a, UInt b) -> std::string +{ + assert(a < s.size()); + assert(b < s.size()); + + std::string result{s}; + std::swap(result[a], result[b]); + return result; +} + +auto partner(std::string const& s, char a, char b) -> std::string +{ + std::string result; + std::transform(s.begin(), s.end(), std::back_inserter(result), [a, b](char c) { + if (c == a) { + return b; + } + if (c == b) { + return a; + } + return c; + }); + + return result; +} + +auto main() -> int +{ + std::string line; + if (!std::getline(std::cin, line)) { + std::cerr << "Unable to read line.\n"; + return 1; + } + + std::string programs; + programs.resize(16); + std::iota(programs.begin(), programs.end(), 'a'); + + std::size_t idx{0}; + while (idx < line.size()) { + switch (line[idx++]) { + case ',': + break; + case 's': { + std::size_t end{0}; + auto x{std::stoul(line.substr(idx), &end)}; + idx += end; + programs = spin(programs, x); + break; + } + case 'x': { + std::size_t end{0}; + auto x{std::stoul(line.substr(idx), &end)}; + idx += end; + if (line[idx++] != '/') { + std::cerr << "Missing exchange / at " << idx - 1 << ": " << line.substr(idx - 1) << '\n'; + } + auto y{std::stoul(line.substr(idx), &end)}; + idx += end; + programs = exchange(programs, x, y); + break; + } + case 'p': { + auto a{line[idx++]}; + if (line[idx++] != '/') { + std::cerr << "Missing partner / at " << idx - 1 << ": " << line.substr(idx - 1) << '\n'; + } + auto b{line[idx++]}; + programs = partner(programs, a, b); + break; + } + default: + std::cerr << "Unable to understand at index " << idx - 1 << ": " << line.substr(idx - 1) + << '\n'; + abort(); + break; + } + } + + std::cout << "Result: " << programs << '\n'; + return 0; +} diff --git a/2017/puzzle-16-02.cc b/2017/puzzle-16-02.cc new file mode 100644 index 0000000..e8cc68e --- /dev/null +++ b/2017/puzzle-16-02.cc @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include + +using UInt = unsigned long; + +auto spin(std::string const& s, UInt num) -> std::string +{ + assert(num < s.size()); + + std::string result; + result.reserve(s.size()); + auto inserter{std::back_inserter(result)}; + std::copy(s.end() - num, s.end(), inserter); + std::copy(s.begin(), s.end() - num, inserter); + return result; +} + +auto exchange(std::string const& s, UInt a, UInt b) -> std::string +{ + assert(a < s.size()); + assert(b < s.size()); + + std::string result{s}; + std::swap(result[a], result[b]); + return result; +} + +auto partner(std::string const& s, char a, char b) -> std::string +{ + std::string result; + std::transform(s.begin(), s.end(), std::back_inserter(result), [a, b](char c) { + if (c == a) { + return b; + } + if (c == b) { + return a; + } + return c; + }); + + return result; +} + +auto initial_programs() -> std::string +{ + std::string programs; + programs.resize(16); + std::iota(programs.begin(), programs.end(), 'a'); + return programs; +} + +auto run(std::string const& line, std::string const& initial_programs) -> std::string +{ + std::string programs{initial_programs}; + std::size_t idx{0}; + while (idx < line.size()) { + switch (line[idx++]) { + case ',': + break; + case 's': { + std::size_t end{0}; + auto x{std::stoul(line.substr(idx), &end)}; + idx += end; + programs = spin(programs, x); + break; + } + case 'x': { + std::size_t end{0}; + auto x{std::stoul(line.substr(idx), &end)}; + idx += end; + if (line[idx++] != '/') { + std::cerr << "Missing exchange / at " << idx - 1 << ": " << line.substr(idx - 1) << '\n'; + } + auto y{std::stoul(line.substr(idx), &end)}; + idx += end; + programs = exchange(programs, x, y); + break; + } + case 'p': { + auto a{line[idx++]}; + if (line[idx++] != '/') { + std::cerr << "Missing partner / at " << idx - 1 << ": " << line.substr(idx - 1) << '\n'; + } + auto b{line[idx++]}; + programs = partner(programs, a, b); + break; + } + default: + std::cerr << "Unable to understand at index " << idx - 1 << ": " << line.substr(idx - 1) + << '\n'; + abort(); + break; + } + } + return programs; +} + +auto main() -> int +{ + std::string line; + if (!std::getline(std::cin, line)) { + std::cerr << "Unable to read line.\n"; + return 1; + } + + /* Start by running the program enough times to get back to the initial state. */ + /* We can't do this by counting cycle lengths as pX/Y swaps letters whilst xX/Y swaps positions so + * we don't have the same ultimate transformation each time we start. + */ + std::string programs{initial_programs()}; + bool cont{true}; + unsigned count{0}; + while (cont) { + ++count; + programs = run(line, programs); + cont = false; + for (unsigned i = 0; i < programs.size(); ++i) { + if (programs[i] != 'a' + i) { + cont = true; + break; + } + } + } + + /* We now only need to run 1'000'000'000 % count times to get to the state we want. */ + unsigned runs_left{1'000'000'000 % count}; + for (unsigned i{0}; i < runs_left; ++i) { + programs = run(line, programs); + } + + std::cout << "Result: " << programs << '\n'; + return 0; +}