Skip to content

Commit 8df86d1

Browse files
Add 2016 day 14 puzzles
1 parent f540d82 commit 8df86d1

File tree

4 files changed

+194
-0
lines changed

4 files changed

+194
-0
lines changed

2016/puzzle-14-01.CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
find_package(OpenSSL REQUIRED)
2+
target_link_libraries("${puzzle_name}" OpenSSL::SSL)

2016/puzzle-14-01.cc

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//
2+
// Created by Matthew Gretton-Dann on 06/12/2021.
3+
//
4+
5+
#include <array>
6+
#include <iostream>
7+
#include <string>
8+
#include <string_view>
9+
10+
#include <openssl/evp.h>
11+
12+
using MD5Digest = std::array<unsigned char, EVP_MAX_MD_SIZE>;
13+
14+
auto md5(std::string const& s) -> std::string
15+
{
16+
MD5Digest digest;
17+
EVP_MD const* md{EVP_md5()};
18+
unsigned int md_len{0};
19+
20+
EVP_MD_CTX* md_context{EVP_MD_CTX_new()};
21+
assert(md_context != nullptr);
22+
EVP_DigestInit_ex2(md_context, md, nullptr);
23+
EVP_DigestUpdate(md_context, s.data(), s.length());
24+
EVP_DigestFinal_ex(md_context, digest.data(), &md_len);
25+
std::string result;
26+
static std::string_view letters{"0123456789abcdef"};
27+
for (auto i{0}; i < md_len; ++i) {
28+
result += letters[(digest[i] & 0xf0) >> 4];
29+
result += letters[(digest[i] & 0xf)];
30+
}
31+
return result;
32+
}
33+
34+
auto has_three_char_sequence(std::string const& s) -> char
35+
{
36+
std::string result;
37+
for (std::size_t idx{0}; idx < s.size() - 2; ++idx) {
38+
if (s[idx] == s[idx + 1] && s[idx] == s[idx + 2]) {
39+
return s[idx];
40+
}
41+
}
42+
return '\0';
43+
}
44+
45+
auto main() -> int
46+
{
47+
std::string line;
48+
if (!std::getline(std::cin, line)) {
49+
std::cerr << "Failed to read line\n";
50+
return 1;
51+
}
52+
53+
unsigned codes_seen{0};
54+
unsigned index{0};
55+
while (codes_seen != 64) {
56+
std::string code{line};
57+
code += std::to_string(index);
58+
auto md5sum{md5(code)};
59+
char c{has_three_char_sequence(md5sum)};
60+
if (c != '\0') {
61+
bool success{false};
62+
std::string s(5, c);
63+
for (unsigned i2 = index + 1; i2 < index + 1001; ++i2) {
64+
std::string code2{line};
65+
code2 += std::to_string(i2);
66+
auto md5sum2{md5(code2)};
67+
success = md5sum2.find(s) != std::string::npos;
68+
if (success) {
69+
break;
70+
}
71+
}
72+
if (success) {
73+
std::cout << "Code " << codes_seen << " at index " << index << '\n';
74+
++codes_seen;
75+
}
76+
}
77+
++index;
78+
}
79+
80+
std::cout << "Index " << index - 1 << '\n';
81+
return 0;
82+
}

2016/puzzle-14-02.CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
find_package(OpenSSL REQUIRED)
2+
target_link_libraries("${puzzle_name}" OpenSSL::SSL)

2016/puzzle-14-02.cc

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
//
2+
// Created by Matthew Gretton-Dann on 06/12/2021.
3+
//
4+
5+
#include <array>
6+
#include <iostream>
7+
#include <string>
8+
#include <string_view>
9+
#include <vector>
10+
11+
#include <openssl/evp.h>
12+
13+
using MD5Digest = std::array<unsigned char, EVP_MAX_MD_SIZE>;
14+
15+
auto md5(std::string const& s) -> std::string
16+
{
17+
MD5Digest digest;
18+
EVP_MD const* md{EVP_md5()};
19+
unsigned int md_len{0};
20+
21+
EVP_MD_CTX* md_context{EVP_MD_CTX_new()};
22+
assert(md_context != nullptr);
23+
EVP_DigestInit_ex2(md_context, md, nullptr);
24+
EVP_DigestUpdate(md_context, s.data(), s.length());
25+
EVP_DigestFinal_ex(md_context, digest.data(), &md_len);
26+
std::string result;
27+
static std::string_view letters{"0123456789abcdef"};
28+
for (auto i{0}; i < md_len; ++i) {
29+
result += letters[(digest[i] & 0xf0) >> 4];
30+
result += letters[(digest[i] & 0xf)];
31+
}
32+
return result;
33+
}
34+
35+
auto key_stretch(std::string const& s) -> std::string
36+
{
37+
std::string r{s};
38+
for (unsigned i = 0; i < 2017; ++i) {
39+
r = md5(r);
40+
}
41+
return r;
42+
}
43+
44+
struct Cache
45+
{
46+
explicit Cache(std::string const& key) : key_(key) {}
47+
48+
auto md5(unsigned index) -> std::string
49+
{
50+
while (index >= cache_.size()) {
51+
cache_.push_back(key_stretch(key_ + std::to_string(index)));
52+
}
53+
return cache_[index];
54+
}
55+
56+
std::string key_;
57+
std::vector<std::string> cache_;
58+
};
59+
60+
auto has_three_char_sequence(std::string const& s) -> char
61+
{
62+
std::string result;
63+
for (std::size_t idx{0}; idx < s.size() - 2; ++idx) {
64+
if (s[idx] == s[idx + 1] && s[idx] == s[idx + 2]) {
65+
return s[idx];
66+
}
67+
}
68+
return '\0';
69+
}
70+
71+
auto main() -> int
72+
{
73+
std::string line;
74+
if (!std::getline(std::cin, line)) {
75+
std::cerr << "Failed to read line\n";
76+
return 1;
77+
}
78+
79+
Cache cache{line};
80+
unsigned codes_seen{0};
81+
unsigned index{0};
82+
while (codes_seen != 64) {
83+
auto md5sum{cache.md5(index)};
84+
char c{has_three_char_sequence(md5sum)};
85+
if (c != '\0') {
86+
bool success{false};
87+
std::string s(5, c);
88+
for (unsigned i2 = index + 1; i2 < index + 1001; ++i2) {
89+
std::string code2{line};
90+
code2 += std::to_string(i2);
91+
auto md5sum2{cache.md5(i2)};
92+
success = md5sum2.find(s) != std::string::npos;
93+
if (success) {
94+
break;
95+
}
96+
}
97+
if (success) {
98+
std::cout << "Code " << codes_seen << " at index " << index << " letter " << c << " hash "
99+
<< cache.md5(index) << '\n';
100+
++codes_seen;
101+
}
102+
}
103+
++index;
104+
}
105+
106+
std::cout << "Index " << index - 1 << '\n';
107+
return 0;
108+
}

0 commit comments

Comments
 (0)