/// <summary> /// https://projecteuler.net/problem=51 --skip=12,15,20,26,60 /// </summary> /// <param name="arguments"></param> /// <returns></returns> public static Result PrimeDigitReplacements(Problem arguments) { /// <summary> /// Return true if all digits in a numbers are the same, except those that repeat the /// same digit and it just increases/decreases from one to the other. For example /// CompareNumbers(124353,124757)=true, CompareNumbers(124353,124151)=true, /// CompareNumbers(121313,121757)=false. Also if numbers are the same return false. /// </summary> /// <param name="left"></param> /// <param name="right"></param> /// <returns></returns> bool NumbersBelongToSameDigitFamily(int left, int right, int repeating_sequences = 1) { var repeating = new Dictionary <char, List <int> >(); var sleft = left.ToString(); var sright = right.ToString(); if (left == right) { return(false); } if (sleft.Length != sright.Length) { return(false); } for (var i = 0; i < sleft.Length; i++) { var rdigit = sright[i]; var ldigit = sleft[i]; if ((repeating.Count < repeating_sequences) && !repeating.ContainsKey(ldigit) && (sleft.Count(c => c == ldigit) >= 2)) { if (repeating.ContainsKey(ldigit) && repeating[ldigit].Contains(i)) { continue; } else { repeating.Add(ldigit, new List <int>()); foreach (var(digit, j) in sleft.Enumerate()) { if (digit == ldigit) { repeating[ldigit].Add(j); } } bool match = true; foreach (var k in repeating[ldigit]) { match = match && sright[k] == rdigit; if (!match) { break; } } if (!match) { return(false); } } } else if (repeating.ContainsKey(ldigit) && repeating[ldigit].Contains(i)) { continue; } else if (rdigit == ldigit) { continue; } else if (ldigit != rdigit) { return(false); } } return(true); } // get all six digit primes var primes = UtilityMath.GeneratePrimes(100000, 1000000).ToArray(); var repeats = new List <int>(); // get primes with repeated digits (not necessarily adjacent digits) for (int i = 0; i < primes.Length; i++) { var counts = UtilityMath.GetRepeatedDigitCounts(primes[i]); if (counts.Count(c => c > 1) >= 1) // choose only primes with at least one repeatig digit { repeats.Add(primes[i]); } } // get first eight number prime-family HashSet <int> family = null; foreach (var prime in repeats) { family = new HashSet <int> { prime }; foreach (var n in repeats) { if (NumbersBelongToSameDigitFamily(prime, n)) { family.Add(n); } if (family.Count == 8) { break; } } if (family.Count == 8) { break; } } primes = null; repeats = null; var answer = family?.First().ToString(); var message = string.Format("The smallest prime which, by replacing part of the number (not necessarily adjacent digits) with the same digit, is part of an eight prime value family is {0}.", answer); if (Answers[arguments.Id] != answer) { message += string.Format(" => INCORRECT ({0})", Answers[arguments.Id]); } var r = new Result(arguments.Id, message) { Answer = answer }; return(r); }