using System; using System.Collections.Generic; using System.Security.Cryptography; using System.Text; namespace D14._1 { class Program { static byte[] ToB(string str) => Encoding.ASCII.GetBytes(str); static string ToS(byte[] b) => BitConverter.ToString(b).Replace("-", "").ToLower(); static bool HasQuintuplet(string str, char c) { for (int i = 4; i < str.Length; ++i) if (str[i - 4] == str[i - 3] && str[i - 3] == str[i - 2] && str[i - 2] == str[i - 1] && str[i - 1] == str[i] && str[i] == c) return true; return false; } static char? HasTriplet(string str) { for (int i = 2; i < str.Length; ++i) if (str[i - 2] == str[i - 1] && str[i - 1] == str[i]) return str[i]; return null; } static void Main(string[] args) { if (args.Length < 1) throw new ArgumentException(); string input = args[0]; int index1 = GetHashes(input, 0); Console.WriteLine($"Index for Part 1 is : {index1}"); int index2 = GetHashes(input, 2016); Console.WriteLine($"Index for Part 2 is : {index2}"); } static Dictionary cache = new Dictionary(); private static int GetHashes(string input, int stretching) { cache.Clear(); int index = -1; using (var md5 = MD5.Create()) { var found = 0; while (found < 64) { index++; string hash = TryGetHash(input, index, md5, stretching); var triplet = HasTriplet(hash); if (triplet.HasValue == false) continue; for (var i = index + 1; i < index + 1000; ++i) { string h = TryGetHash(input, i, md5, stretching); if (HasQuintuplet(h, triplet.Value)) { found++; break; } } } } return index; } private static string TryGetHash(string input, int index, MD5 md5, int stretching) { if (cache.ContainsKey(index)) return cache[index]; var hash = GetHash(input, index, md5, stretching); cache.Add(index, hash); return hash; } private static string GetHash(string input, int index, MD5 md5, int stretching) { var hash = ToS(md5.ComputeHash(ToB($"{input}{index}"))); for (var i = 0; i < stretching; ++i) hash = ToS(md5.ComputeHash(ToB(hash))); return hash; } } }