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; } } }