From 80472cbbf24b2cf9b068c6429179ce4e1d784768 Mon Sep 17 00:00:00 2001
From: inga-lovinde <52715130+inga-lovinde@users.noreply.github.com>
Date: Mon, 6 Mar 2017 15:54:01 +0300
Subject: [PATCH] Unoptimized correct
---
WhiteRabbit/PermutationsGenerator.cs | 118 +++++++++++++++++++++++++++
WhiteRabbit/Processor.cs | 115 ++++++++++++++++++++++++++
WhiteRabbit/Program.cs | 30 +++++++
WhiteRabbit/WhiteRabbit.csproj | 7 ++
WhiteRabbit/packages.config | 4 +
5 files changed, 274 insertions(+)
create mode 100644 WhiteRabbit/PermutationsGenerator.cs
create mode 100644 WhiteRabbit/Processor.cs
create mode 100644 WhiteRabbit/packages.config
diff --git a/WhiteRabbit/PermutationsGenerator.cs b/WhiteRabbit/PermutationsGenerator.cs
new file mode 100644
index 0000000..4033214
--- /dev/null
+++ b/WhiteRabbit/PermutationsGenerator.cs
@@ -0,0 +1,118 @@
+namespace WhiteRabbit
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ ///
+ /// Code taken from https://ericlippert.com/2013/04/22/producing-permutations-part-three/
+ ///
+ internal class PermutationsGenerator
+ {
+ public static IEnumerable HamiltonianPermutations(int n)
+ {
+ if (n < 0)
+ {
+ throw new ArgumentOutOfRangeException("n");
+ }
+
+ return Permutation.HamiltonianPermutationsIterator(n);
+ }
+
+ public struct Permutation : IEnumerable
+ {
+ private Permutation(int[] permutation)
+ {
+ this.PermutationData = permutation;
+ }
+
+ private Permutation(IEnumerable permutation)
+ : this(permutation.ToArray())
+ {
+ }
+
+ public static Permutation Empty { get; } = new Permutation(new int[] { });
+
+ private int[] PermutationData { get; }
+
+ public int this[int index] => this.PermutationData[index];
+
+ public static IEnumerable HamiltonianPermutationsIterator(int n)
+ {
+ if (n == 0)
+ {
+ yield return Empty;
+ yield break;
+ }
+
+ bool forwards = false;
+ foreach (Permutation permutation in HamiltonianPermutationsIterator(n - 1))
+ {
+ for (int index = 0; index < n; index += 1)
+ {
+ yield return new Permutation(Extensions.InsertAt(permutation, forwards ? index : n - index - 1, n - 1));
+ }
+
+ forwards = !forwards;
+ }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ foreach (int item in this.PermutationData)
+ {
+ yield return item;
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
+ }
+
+ public static class Extensions
+ {
+ public static IEnumerable InsertAt(IEnumerable items, int position, T newItem)
+ {
+ if (items == null)
+ {
+ throw new ArgumentNullException("items");
+ }
+
+ if (position < 0)
+ {
+ throw new ArgumentOutOfRangeException("position");
+ }
+
+ return InsertAtIterator(items, position, newItem);
+ }
+
+ private static IEnumerable InsertAtIterator(IEnumerable items, int position, T newItem)
+ {
+ int index = 0;
+ bool yieldedNew = false;
+ foreach (T item in items)
+ {
+ if (index == position)
+ {
+ yield return newItem;
+ yieldedNew = true;
+ }
+
+ yield return item;
+ index += 1;
+ }
+
+ if (index == position)
+ {
+ yield return newItem;
+ yieldedNew = true;
+ }
+
+ if (!yieldedNew)
+ {
+ throw new ArgumentOutOfRangeException("position");
+ }
+ }
+ }
+ }
+}
diff --git a/WhiteRabbit/Processor.cs b/WhiteRabbit/Processor.cs
new file mode 100644
index 0000000..d655387
--- /dev/null
+++ b/WhiteRabbit/Processor.cs
@@ -0,0 +1,115 @@
+namespace WhiteRabbit
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.Immutable;
+ using System.Linq;
+
+ internal class Processor
+ {
+ private const int DifferentChars = 12;
+ private const int ArraySize = DifferentChars * sizeof(int);
+
+ public Processor(string sourceString, int maxWordsCount)
+ {
+ var rawNumberOfOccurrences = sourceString.Where(ch => ch != ' ').GroupBy(ch => ch).ToDictionary(group => group.Key, group => group.Count());
+ this.IntToChar = rawNumberOfOccurrences.Select(kvp => kvp.Key).OrderBy(ch => ch).ToArray();
+ if (this.IntToChar.Length != DifferentChars)
+ {
+ throw new ArgumentException("Unsupported phrase", nameof(sourceString));
+ }
+ this.CharToInt = Enumerable.Range(0, DifferentChars).ToDictionary(i => this.IntToChar[i], i => i);
+ this.NumberOfOccurrences = Enumerable.Range(0, DifferentChars).Select(i => this.IntToChar[i]).Select(ch => rawNumberOfOccurrences.ContainsKey(ch) ? rawNumberOfOccurrences[ch] : 0).ToArray();
+ this.MaxWordsCount = maxWordsCount;
+ }
+
+ private Dictionary CharToInt { get; }
+
+ private char[] IntToChar { get; }
+
+ private int[] NumberOfOccurrences { get; }
+
+ private int TotalCharsNumber { get; }
+
+ private int MaxWordsCount { get; }
+
+ private long Iterations { get; set; } = 0;
+
+ public IEnumerable GeneratePhrases(IEnumerable words)
+ {
+ var filtered = FilterWords(words);
+ var dictionary = ImmutableStack.Create(filtered.Reverse().ToArray());
+ var anagrams = GenerateOrderedPhrases(this.NumberOfOccurrences, ImmutableStack.Create(), dictionary)
+ .Select(list => list.Select(word => new string(word.Select(i => this.IntToChar[i]).ToArray())).ToArray());
+ var anagramsWithPermutations = anagrams.SelectMany(GeneratePermutations).Select(list => string.Join(" ", list));
+ return anagramsWithPermutations;
+ }
+
+ private IEnumerable FilterWords(IEnumerable words)
+ {
+ return words
+ .Where(word => word.All(this.CharToInt.ContainsKey))
+ .OrderBy(word => word)
+ .Distinct()
+ .Select(word => word.Select(ch => this.CharToInt[ch]).ToArray())
+ .Where(word => word.GroupBy(ch => ch).All(group => group.Count() <= this.NumberOfOccurrences[group.Key]));
+ }
+
+ private int[] GetStatus(int[] originalState, int[] newWord, out int status)
+ {
+ var tmpArray = new int[DifferentChars];
+ Buffer.BlockCopy(originalState, 0, tmpArray, 0, ArraySize);
+
+ foreach (var ch in newWord)
+ {
+ --tmpArray[ch];
+ }
+
+ // Negative if at least one element is negative; zero if all elements are zero; positive if all elements are non-negative and at least one element is positive
+ status = tmpArray[0] | tmpArray[1] | tmpArray[2] | tmpArray[3] | tmpArray[4] | tmpArray[5] | tmpArray[6] | tmpArray[7] | tmpArray[8] | tmpArray[9] | tmpArray[10] | tmpArray[11];
+ return tmpArray;
+ }
+
+ // This method takes most of the time, so everything related to it must be optimized
+ private IEnumerable GenerateOrderedPhrases(int[] currentState, ImmutableStack phraseStack, ImmutableStack dictionaryStack)
+ {
+ var remainder = dictionaryStack;
+ var count = phraseStack.Count() + 1;
+ while (!remainder.IsEmpty)
+ {
+ int[] currentWord;
+ var nextRemainder = remainder.Pop(out currentWord);
+
+ this.Iterations++;
+ if (this.Iterations % 1000000 == 0)
+ {
+ Console.WriteLine($"Iteration #{this.Iterations}: {string.Join(" ", phraseStack.Push(currentWord).Reverse().Select(word => new string(word.Select(ch => this.IntToChar[ch]).ToArray())))}");
+ }
+
+ int status;
+ var state = GetStatus(currentState, currentWord, out status);
+ if (status > 0 && count < this.MaxWordsCount)
+ {
+ foreach (var result in GenerateOrderedPhrases(state, phraseStack.Push(currentWord), remainder))
+ {
+ yield return result;
+ }
+ }
+ else if (status == 0)
+ {
+ yield return phraseStack.Push(currentWord).Reverse().ToArray();
+ }
+
+ remainder = nextRemainder;
+ }
+ }
+
+ private IEnumerable GeneratePermutations(string[] original)
+ {
+ foreach (var permutation in PermutationsGenerator.HamiltonianPermutations(original.Length))
+ {
+ yield return permutation.Select(i => original[i]).ToArray();
+ }
+ }
+ }
+}
diff --git a/WhiteRabbit/Program.cs b/WhiteRabbit/Program.cs
index 7990474..3886a0b 100644
--- a/WhiteRabbit/Program.cs
+++ b/WhiteRabbit/Program.cs
@@ -1,5 +1,11 @@
namespace WhiteRabbit
{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Text;
+
///
/// Main class
///
@@ -10,6 +16,30 @@
///
public static void Main()
{
+ var processor = new Processor("poultry outwits ants", 3);
+ foreach (var phrase in processor.GeneratePhrases(ReadInput()))
+ {
+ Console.WriteLine(GetMd5Hash(phrase) + ": " + phrase);
+ }
+ }
+
+ private static string GetMd5Hash(string input)
+ {
+ using (MD5 md5Hash = MD5.Create())
+ {
+ // Convert the input string to a byte array and compute the hash.
+ byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
+ return string.Concat(data.Select(b => b.ToString("x2")));
+ }
+ }
+
+ private static IEnumerable ReadInput()
+ {
+ string line;
+ while ((line = Console.ReadLine()) != null)
+ {
+ yield return line;
+ }
}
}
}
diff --git a/WhiteRabbit/WhiteRabbit.csproj b/WhiteRabbit/WhiteRabbit.csproj
index 92e0b87..9fd51c2 100644
--- a/WhiteRabbit/WhiteRabbit.csproj
+++ b/WhiteRabbit/WhiteRabbit.csproj
@@ -35,6 +35,10 @@
+
+ ..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
+ True
+
@@ -44,11 +48,14 @@
+
+
+