private bool ReduceCandidates(Mapping set, bool[] solvedWords, SolveData data) { Mapping helper = new Mapping(this.calpha.GetAlphabetQuantity()); int rounds = 0; bool dirty = true; while (dirty && rounds < DictionaryAttacker.maxReduceIterations) { dirty = false; for (int wordnum = 0; wordnum < words.Count; wordnum++) { Word w = words[wordnum]; if (solvedWords[wordnum] || !w.Enabled) { continue; } helper.SetEmpty(); for (int c = data.firstcand[wordnum]; c < w.Candidates.Length; c++) { Candidate candidate = w.Candidates[c]; if (set.IsMappingOK(w.ByteValue, candidate.ByteValue)) { helper.EnableMapping(w.ByteValue, candidate.ByteValue); } else { Candidate tmp = w.Candidates[data.firstcand[wordnum]]; w.Candidates[data.firstcand[wordnum]] = candidate; w.Candidates[c] = tmp; data.firstcand[wordnum]++; dirty = true; } } set.IntersectWith(helper); } long mappedTo = 0; for (int i = 0; i < this.calpha.GetAlphabetQuantity(); i++) { if (!set.HasMapping((byte)i)) { return(true); } int mi = set.GetMapping((byte)i); if (mi >= 0) { if ((mappedTo & (1 << mi)) > 0) { return(true); } mappedTo |= (1 << mi); } } rounds++; } return(false); }
private void Solve() { //First Mapping Mapping startMap = new Mapping(this.calpha.GetAlphabetQuantity()); startMap.SetFull(); // Prepare solution base data SolveData basis = new SolveData(); basis.solvedWords = new bool[this.words.Count]; basis.numSolvedWords = 0; basis.mapping = startMap; basis.firstcand = new int[this.words.Count]; for (int i = 0; i < this.words.Count; i++) { basis.firstcand[i] = 0; } Stack <SolveData> stack = new Stack <SolveData>(); stack.Push(basis); // Reduce root node if (pruneRootNode) { bool inconsistent = ReduceCandidates(basis.mapping, basis.solvedWords, basis); if (inconsistent) { basis.mapping = startMap.Copy(); } } int rounds = 0; int action; int index; do { if (this.stopFlag == true) { break; } rounds++; //// Store new data object to stack SolveData data = stack.Peek().Copy(); //// Break if all words are solved if (data.numSolvedWords == words.Count) { AddKeyToResult(data.mapping, true); break; } // Define next action action = this.DetermineNextSubstitution(data.solvedWords, data.mapping, out index, data); if (action == -1) { AddKeyToResult(data.mapping, true); break; } else if (action == -2) { AddKeyToResult(data.mapping, false); break; } else if (action == 1) { //// Implement action - Word Word w = words[index]; data.solvedWords[index] = true; data.numSolvedWords++; if (!w.Enabled) { continue; } Mapping helper = data.mapping.Copy(); bool leaf = true; if (scrambleWordOrder) { for (int c = data.firstcand[index]; c < w.Candidates.Length; c++) { int d = this.random.Next(w.Candidates.Length - data.firstcand[index]) + data.firstcand[index]; Candidate cc = w.Candidates[c]; Candidate cd = w.Candidates[d]; w.Candidates[d] = cc; w.Candidates[c] = cd; } } for (int c = data.firstcand[index]; c < w.Candidates.Length; c++) { Candidate candidate = w.Candidates[c]; if (!helper.IsMappingOK(w.ByteValue, candidate.ByteValue)) { continue; } leaf = false; helper.SetMapping(w.ByteValue, candidate.ByteValue); bool inconsistent = false; if (pruneEachNode) { inconsistent = ReduceCandidates(helper, data.solvedWords, data); } if (!inconsistent) { data.mapping = helper; data.firstcand[index] = c; stack.Push(data); leaf = false; break; } helper.SetTo(data.mapping); } if (leaf) { AddKeyToResult(helper, false); stack.Pop(); } } else if (action == 2) { /// Implement action - letter byte[] a = new byte[1]; byte[] b = new byte[1]; a[0] = (byte)(index); Mapping helper = data.mapping.Copy(); bool leaf = true; for (int c = 0; c < this.calpha.GetAlphabetQuantity(); c++) { b[0] = (byte)c; if (helper.IsMappingOK(a, b)) { helper.SetMapping(a, b); bool inconsistent = ReduceCandidates(helper, data.solvedWords, data); if (!inconsistent) { data.mapping = helper; leaf = false; break; } helper.SetTo(data.mapping); } } if (leaf) { AddKeyToResult(data.mapping, false); stack.Pop(); } } } while (rounds < DictionaryAttacker.maxIterations); }