Unoptimized correct

rx
Inga 🏳‍🌈 7 years ago
parent 4d02d3e776
commit 80472cbbf2
  1. 118
      WhiteRabbit/PermutationsGenerator.cs
  2. 115
      WhiteRabbit/Processor.cs
  3. 30
      WhiteRabbit/Program.cs
  4. 7
      WhiteRabbit/WhiteRabbit.csproj
  5. 4
      WhiteRabbit/packages.config

@ -0,0 +1,118 @@
namespace WhiteRabbit
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// Code taken from https://ericlippert.com/2013/04/22/producing-permutations-part-three/
/// </summary>
internal class PermutationsGenerator
{
public static IEnumerable<Permutation> HamiltonianPermutations(int n)
{
if (n < 0)
{
throw new ArgumentOutOfRangeException("n");
}
return Permutation.HamiltonianPermutationsIterator(n);
}
public struct Permutation : IEnumerable<int>
{
private Permutation(int[] permutation)
{
this.PermutationData = permutation;
}
private Permutation(IEnumerable<int> 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<Permutation> 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<int> GetEnumerator()
{
foreach (int item in this.PermutationData)
{
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
}
public static class Extensions
{
public static IEnumerable<T> InsertAt<T>(IEnumerable<T> items, int position, T newItem)
{
if (items == null)
{
throw new ArgumentNullException("items");
}
if (position < 0)
{
throw new ArgumentOutOfRangeException("position");
}
return InsertAtIterator<T>(items, position, newItem);
}
private static IEnumerable<T> InsertAtIterator<T>(IEnumerable<T> 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");
}
}
}
}
}

@ -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<char, int> 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<string> GeneratePhrases(IEnumerable<string> words)
{
var filtered = FilterWords(words);
var dictionary = ImmutableStack.Create(filtered.Reverse().ToArray());
var anagrams = GenerateOrderedPhrases(this.NumberOfOccurrences, ImmutableStack.Create<int[]>(), 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<int[]> FilterWords(IEnumerable<string> 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<int[][]> GenerateOrderedPhrases(int[] currentState, ImmutableStack<int[]> phraseStack, ImmutableStack<int[]> 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<string[]> GeneratePermutations(string[] original)
{
foreach (var permutation in PermutationsGenerator.HamiltonianPermutations(original.Length))
{
yield return permutation.Select(i => original[i]).ToArray();
}
}
}
}

@ -1,5 +1,11 @@
namespace WhiteRabbit
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
/// <summary>
/// Main class
/// </summary>
@ -10,6 +16,30 @@
/// </summary>
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<string> ReadInput()
{
string line;
while ((line = Console.ReadLine()) != null)
{
yield return line;
}
}
}
}

@ -35,6 +35,10 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Collections.Immutable, Version=1.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@ -44,11 +48,14 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="PermutationsGenerator.cs" />
<Compile Include="Processor.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="System.Collections.Immutable" version="1.3.1" targetFramework="net46" />
</packages>
Loading…
Cancel
Save