From 8df86d16e4f79f2c58665d20e5f54ee2053b6039 Mon Sep 17 00:00:00 2001 From: Matthew Gretton-Dann Date: Mon, 6 Dec 2021 19:55:36 +0000 Subject: [PATCH] Add 2016 day 14 puzzles --- 2016/puzzle-14-01.CMakeLists.txt | 2 + 2016/puzzle-14-01.cc | 82 +++++++++++++++++++++++ 2016/puzzle-14-02.CMakeLists.txt | 2 + 2016/puzzle-14-02.cc | 108 +++++++++++++++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 2016/puzzle-14-01.CMakeLists.txt create mode 100644 2016/puzzle-14-01.cc create mode 100644 2016/puzzle-14-02.CMakeLists.txt create mode 100644 2016/puzzle-14-02.cc diff --git a/2016/puzzle-14-01.CMakeLists.txt b/2016/puzzle-14-01.CMakeLists.txt new file mode 100644 index 0000000..1f298ff --- /dev/null +++ b/2016/puzzle-14-01.CMakeLists.txt @@ -0,0 +1,2 @@ +find_package(OpenSSL REQUIRED) +target_link_libraries("${puzzle_name}" OpenSSL::SSL) diff --git a/2016/puzzle-14-01.cc b/2016/puzzle-14-01.cc new file mode 100644 index 0000000..2459afe --- /dev/null +++ b/2016/puzzle-14-01.cc @@ -0,0 +1,82 @@ +// +// Created by Matthew Gretton-Dann on 06/12/2021. +// + +#include +#include +#include +#include + +#include + +using MD5Digest = std::array; + +auto md5(std::string const& s) -> std::string +{ + MD5Digest digest; + EVP_MD const* md{EVP_md5()}; + unsigned int md_len{0}; + + EVP_MD_CTX* md_context{EVP_MD_CTX_new()}; + assert(md_context != nullptr); + EVP_DigestInit_ex2(md_context, md, nullptr); + EVP_DigestUpdate(md_context, s.data(), s.length()); + EVP_DigestFinal_ex(md_context, digest.data(), &md_len); + std::string result; + static std::string_view letters{"0123456789abcdef"}; + for (auto i{0}; i < md_len; ++i) { + result += letters[(digest[i] & 0xf0) >> 4]; + result += letters[(digest[i] & 0xf)]; + } + return result; +} + +auto has_three_char_sequence(std::string const& s) -> char +{ + std::string result; + for (std::size_t idx{0}; idx < s.size() - 2; ++idx) { + if (s[idx] == s[idx + 1] && s[idx] == s[idx + 2]) { + return s[idx]; + } + } + return '\0'; +} + +auto main() -> int +{ + std::string line; + if (!std::getline(std::cin, line)) { + std::cerr << "Failed to read line\n"; + return 1; + } + + unsigned codes_seen{0}; + unsigned index{0}; + while (codes_seen != 64) { + std::string code{line}; + code += std::to_string(index); + auto md5sum{md5(code)}; + char c{has_three_char_sequence(md5sum)}; + if (c != '\0') { + bool success{false}; + std::string s(5, c); + for (unsigned i2 = index + 1; i2 < index + 1001; ++i2) { + std::string code2{line}; + code2 += std::to_string(i2); + auto md5sum2{md5(code2)}; + success = md5sum2.find(s) != std::string::npos; + if (success) { + break; + } + } + if (success) { + std::cout << "Code " << codes_seen << " at index " << index << '\n'; + ++codes_seen; + } + } + ++index; + } + + std::cout << "Index " << index - 1 << '\n'; + return 0; +} diff --git a/2016/puzzle-14-02.CMakeLists.txt b/2016/puzzle-14-02.CMakeLists.txt new file mode 100644 index 0000000..1f298ff --- /dev/null +++ b/2016/puzzle-14-02.CMakeLists.txt @@ -0,0 +1,2 @@ +find_package(OpenSSL REQUIRED) +target_link_libraries("${puzzle_name}" OpenSSL::SSL) diff --git a/2016/puzzle-14-02.cc b/2016/puzzle-14-02.cc new file mode 100644 index 0000000..c5b3a89 --- /dev/null +++ b/2016/puzzle-14-02.cc @@ -0,0 +1,108 @@ +// +// Created by Matthew Gretton-Dann on 06/12/2021. +// + +#include +#include +#include +#include +#include + +#include + +using MD5Digest = std::array; + +auto md5(std::string const& s) -> std::string +{ + MD5Digest digest; + EVP_MD const* md{EVP_md5()}; + unsigned int md_len{0}; + + EVP_MD_CTX* md_context{EVP_MD_CTX_new()}; + assert(md_context != nullptr); + EVP_DigestInit_ex2(md_context, md, nullptr); + EVP_DigestUpdate(md_context, s.data(), s.length()); + EVP_DigestFinal_ex(md_context, digest.data(), &md_len); + std::string result; + static std::string_view letters{"0123456789abcdef"}; + for (auto i{0}; i < md_len; ++i) { + result += letters[(digest[i] & 0xf0) >> 4]; + result += letters[(digest[i] & 0xf)]; + } + return result; +} + +auto key_stretch(std::string const& s) -> std::string +{ + std::string r{s}; + for (unsigned i = 0; i < 2017; ++i) { + r = md5(r); + } + return r; +} + +struct Cache +{ + explicit Cache(std::string const& key) : key_(key) {} + + auto md5(unsigned index) -> std::string + { + while (index >= cache_.size()) { + cache_.push_back(key_stretch(key_ + std::to_string(index))); + } + return cache_[index]; + } + + std::string key_; + std::vector cache_; +}; + +auto has_three_char_sequence(std::string const& s) -> char +{ + std::string result; + for (std::size_t idx{0}; idx < s.size() - 2; ++idx) { + if (s[idx] == s[idx + 1] && s[idx] == s[idx + 2]) { + return s[idx]; + } + } + return '\0'; +} + +auto main() -> int +{ + std::string line; + if (!std::getline(std::cin, line)) { + std::cerr << "Failed to read line\n"; + return 1; + } + + Cache cache{line}; + unsigned codes_seen{0}; + unsigned index{0}; + while (codes_seen != 64) { + auto md5sum{cache.md5(index)}; + char c{has_three_char_sequence(md5sum)}; + if (c != '\0') { + bool success{false}; + std::string s(5, c); + for (unsigned i2 = index + 1; i2 < index + 1001; ++i2) { + std::string code2{line}; + code2 += std::to_string(i2); + auto md5sum2{cache.md5(i2)}; + success = md5sum2.find(s) != std::string::npos; + if (success) { + break; + } + } + if (success) { + std::cout << "Code " << codes_seen << " at index " << index << " letter " << c << " hash " + << cache.md5(index) << '\n'; + ++codes_seen; + } + } + ++index; + } + + std::cout << "Index " << index - 1 << '\n'; + return 0; +}