using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExtensionMethods;
namespace CryptanalysisCore
{
class WordsCompleter
{
///
/// Původní nemodifikovaná zašifrovaná slova.
///
private string[] originWords;
///
/// Původní nemodifikované substituce.
///
private Dictionary originSubs;
///
/// Slovník slov, nad kterým pracujeme.
///
private Dictionary dictionary;
///
/// Slova s vyznačením již nalezených substitucí
///
private string[] modifWords;
///
/// Modifikované substituce.
///
private Dictionary substitutions;
public WordsCompleter(string[] words, Dictionary substitutions, Storage.Languages language)
{
this.originWords = words;
this.originSubs = substitutions;
this.substitutions = substitutions;
dictionary = Dictionary.Create(Storage.GetLangChar(language).Dictionary, x => x.Length);
}
public Dictionary Complete()
{
while (true)
{
modifWords = GetSubsWords(originWords, substitutions);
var testWords = GetWords(30);
var simWords = GetSimilarWords(testWords);
var onePossPairs = GetOnePossPairs(simWords);
if (onePossPairs.Count == 0)
break;
var certainPairs = GetCertainPairs(onePossPairs);
substitutions = TextAnalysis.GetLetterSubst(certainPairs, substitutions);
}
return substitutions;
}
private Dictionary GetCertainPairs(Dictionary pairs)
{
WordsFilter filter = new WordsFilter(pairs);
var res = filter.Filter(AreWordsSimilar);
return res;
}
private bool AreWordsSimilar(KeyValuePair pair1, KeyValuePair pair2)
{
var subst1 = TextAnalysis.GetLettersSubst(pair1);
var subst2 = TextAnalysis.GetLettersSubst(pair2);
return TextAnalysis.AreSubstMatch(subst1, subst2);
}
///
/// Vrátí dvojice slov, pro které existuje jen jedno podobné slovo
///
///
///
private Dictionary GetOnePossPairs(Dictionary similarWords)
{
var result = similarWords.Where(x => x.Value.Length == 1).ToDictionary(x => x.Key, x => x.Value[0]);
return result;
}
///
/// Pro všechna slova vrátí pole podobných slov
///
///
///
private Dictionary GetSimilarWords(Dictionary words)
{
Dictionary simWords = new Dictionary();
foreach (var pair in words)
simWords[pair.Value] = GetSimilarWords(pair.Key);
return simWords;
}
///
/// Vrátí všechna slova, která mohou odpovídat předanému slovu
/// s některými neidentifikovanými písmeny
///
///
///
private string[] GetSimilarWords(string word)
{
if (!dictionary.ContainsKey(word.Length))
return new string[] { };
List similarWords = new List();
string[] testWords = dictionary[word.Length];
foreach (string testWord in testWords)
{
if (AreWordsSimilar(testWord, word))
similarWords.Add(testWord);
}
return similarWords.ToArray();
}
///
/// Otestuje, zda se může nekompletní slovo doplnit na kompletní
///
///
///
///
private bool AreWordsSimilar(string completeWord, string incompleteWord)
{
for (int i = 0; i < completeWord.Length; i++)
{
char currChar = incompleteWord[i];
if (currChar != Analyse.Unknown && completeWord[i] != currChar)
return false;
}
return true;
}
///
/// Vrátí slova s požadovanou minimální délkou a minimálním
/// počtem neidentifikovaných písmen. Zároveň odstraní slova,
/// která jsou identifikována úplně.
///
///
///
///
private Dictionary GetWords(int maximum)
{
Dictionary resultWords = new Dictionary();
for (int i = 0; i < modifWords.Length; i++)
{
string modifWord = modifWords[i];
int unknownCount = modifWord.Count(Analyse.Unknown);
if (unknownCount > 0 && unknownCount < (modifWord.Length / 2))
{
resultWords[modifWord] = originWords[i];
}
}
resultWords = resultWords.OrderBy(x => x.Key.Count(Analyse.Unknown)).Take(maximum).ToDictionary(x => x.Key, x => x.Value);
return resultWords;
}
///
/// Pomocí substitucí zamění písmena ve slovech, pokud substituce dané
/// písmeno neobsahuje, vloží na jeho místo zástupný symbol.
///
///
///
///
private string[] GetSubsWords(string[] words, Dictionary substitutions)
{
string[] modifWords = new string[words.Length];
for (int i = 0; i < words.Length; i++)
{
string currWord = words[i];
char[] modifWord = new char[currWord.Length];
for (int j = 0; j < currWord.Length; j++)
{
char currChar = currWord[j];
if (substitutions.ContainsKey(currChar))
{
modifWord[j] = substitutions[currChar];
}
else
{
modifWord[j] = Analyse.Unknown;
}
modifWords[i] = new string(modifWord);
}
}
return modifWords;
}
}
}