diff --git a/2017/puzzle-14-01.cc b/2017/puzzle-14-01.cc new file mode 100644 index 0000000..9340450 --- /dev/null +++ b/2017/puzzle-14-01.cc @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include + +using Byte = std::uint8_t; +using KnotString = std::vector; + +auto knot_round(KnotString const& in, Byte current_position, Byte length) -> KnotString +{ + KnotString rot_left; + rot_left.reserve(in.size()); + std::copy(in.begin() + current_position, in.end(), std::back_inserter(rot_left)); + std::copy(in.begin(), in.begin() + current_position, std::back_inserter(rot_left)); + + std::reverse(rot_left.begin(), rot_left.begin() + length); + + KnotString rot_right; + std::copy(rot_left.end() - current_position, rot_left.end(), std::back_inserter(rot_right)); + std::copy(rot_left.begin(), rot_left.end() - current_position, std::back_inserter(rot_right)); + return rot_right; +} + +using Knot = std::pair; + +auto knot(std::string const& rounds) -> Knot +{ + /* Put the lengths into a vector. */ + std::vector lengths; + lengths.reserve(rounds.size() + 5); + for (auto c : rounds) { + lengths.emplace_back(static_cast(c)); + } + lengths.emplace_back(17); + lengths.emplace_back(31); + lengths.emplace_back(73); + lengths.emplace_back(47); + lengths.emplace_back(23); + + /* Run the hash */ + Byte current_pos{0}; + Byte skip{0}; + std::vector string; + string.resize(256); + std::iota(string.begin(), string.end(), 0); + + for (unsigned i{0}; i < 64; ++i) { + for (auto length : lengths) { + string = knot_round(string, current_pos, length); + current_pos += length + skip; + ++skip; + } + } + + /* Print the dense hash. */ + std::uint64_t result0{0}; + std::uint64_t result1{0}; + std::uint64_t* hash{&result0}; + for (unsigned i{0}; i < string.size(); ++i) { + if (i % 16 == 0) { + if (i == string.size() / 2) { + hash = &result1; + } + *hash <<= 8; + } + *hash ^= string[i]; + } + + return {result0, result1}; +} + +auto main() -> int +{ + std::string line; + if (!std::getline(std::cin, line)) { + std::cerr << "Unable to read Line\n"; + return 1; + } + + unsigned bit_count{0}; + for (unsigned i = 0; i < 128; ++i) { + std::string key{line}; + key += '-'; + key += std::to_string(i); + auto [knot1, knot2] = knot(key); + bit_count += std::popcount(knot1) + std::popcount(knot2); + } + + std::cout << "Population count " << bit_count << '\n'; + return 0; +} diff --git a/2017/puzzle-14-02.cc b/2017/puzzle-14-02.cc new file mode 100644 index 0000000..f4367d7 --- /dev/null +++ b/2017/puzzle-14-02.cc @@ -0,0 +1,133 @@ +#include +#include +#include +#include +#include +#include +#include + +using UInt = unsigned; +using Byte = std::uint8_t; +using KnotString = std::vector; + +auto knot_round(KnotString const& in, Byte current_position, Byte length) -> KnotString +{ + KnotString rot_left; + rot_left.reserve(in.size()); + std::copy(in.begin() + current_position, in.end(), std::back_inserter(rot_left)); + std::copy(in.begin(), in.begin() + current_position, std::back_inserter(rot_left)); + + std::reverse(rot_left.begin(), rot_left.begin() + length); + + KnotString rot_right; + std::copy(rot_left.end() - current_position, rot_left.end(), std::back_inserter(rot_right)); + std::copy(rot_left.begin(), rot_left.end() - current_position, std::back_inserter(rot_right)); + return rot_right; +} + +using Knot = std::pair; + +auto knot(std::string const& rounds) -> Knot +{ + /* Put the lengths into a vector. */ + std::vector lengths; + lengths.reserve(rounds.size() + 5); + for (auto c : rounds) { + lengths.emplace_back(static_cast(c)); + } + lengths.emplace_back(17); + lengths.emplace_back(31); + lengths.emplace_back(73); + lengths.emplace_back(47); + lengths.emplace_back(23); + + /* Run the hash */ + Byte current_pos{0}; + Byte skip{0}; + std::vector string; + string.resize(256); + std::iota(string.begin(), string.end(), 0); + + for (unsigned i{0}; i < 64; ++i) { + for (auto length : lengths) { + string = knot_round(string, current_pos, length); + current_pos += length + skip; + ++skip; + } + } + + /* Print the dense hash. */ + std::uint64_t result0{0}; + std::uint64_t result1{0}; + std::uint64_t* hash{&result0}; + for (unsigned i{0}; i < string.size(); ++i) { + if (i % 16 == 0) { + if (i == string.size() / 2) { + hash = &result1; + } + *hash <<= 8; + } + *hash ^= string[i]; + } + + return {result0, result1}; +} + +auto main() -> int +{ + std::string line; + if (!std::getline(std::cin, line)) { + std::cerr << "Unable to read Line\n"; + return 1; + } + + std::set> clusters; + + for (unsigned i = 0; i < 128; ++i) { + constexpr std::uint64_t top_bit{1ULL << 63}; + std::string key{line}; + key += '-'; + key += std::to_string(i); + auto [knot1, knot2] = knot(key); + for (auto j = 0; j < 64; ++j) { + if (0 != (knot1 & top_bit)) { + clusters.insert({j, i}); + } + if (0 != (knot2 & top_bit)) { + clusters.insert({j + 64, i}); + } + knot1 <<= 1; + knot2 <<= 1; + } + } + + std::cout << "Population count " << clusters.size() << '\n'; + + UInt cluster_count{0}; + while (!clusters.empty()) { + ++cluster_count; + std::set> to_check; + to_check.insert(*clusters.begin()); + while (!to_check.empty()) { + auto it{to_check.begin()}; + auto [x, y] = *it; + clusters.erase(*it); + to_check.erase(it); + if (clusters.contains({x + 1, y})) { + to_check.insert({x + 1, y}); + } + if (clusters.contains({x, y + 1})) { + to_check.insert({x, y + 1}); + } + if (x != 0 && clusters.contains({x - 1, y})) { + to_check.insert({x - 1, y}); + } + if (y != 0 && clusters.contains({x, y - 1})) { + to_check.insert({x, y - 1}); + } + } + } + + std::cout << "Number of cluster groups " << cluster_count << '\n'; + return 0; +}