/// <summary> /// Solve the puzzle and output the found words to the results pane. /// </summary> private void Solve() { // Get distinct characters entered into TextBoxes HashSet<char> enteredCharacters = new HashSet<char>(_textboxes.SelectMany(textBox => textBox.Text).Distinct()); // Filter words by the entered characters var filteredWords = _allWords.Where(word => word.ToCharArray().Distinct().All(character => enteredCharacters.Contains(character))); Trie filteredLexicon = new Trie(filteredWords); List<string> foundWords = new List<string>(); for (int i = 0; i < 16; i++) { bool[] visited = new bool[16]; FindWords(i, string.Empty, visited, filteredLexicon, foundWords); } var words = foundWords.Distinct().OrderByDescending(w => w.Length); txtResults.Text = string.Format("Found {0} words:" + Environment.NewLine, words.Count()); txtResults.Text += string.Join(Environment.NewLine, words); }
/// <summary> /// Recursively find words starting from the specified box. /// </summary> /// <param name="box">Starting box.</param> /// <param name="prefix">Prefix for the current word.</param> /// <param name="visited">Indicates which boxes have already been visited for this path.</param> /// <param name="lexicon">Lexicon of words to search.</param> /// <param name="foundWords">List in which to add found words.</param> private void FindWords(int box, string prefix, bool[] visited, Trie lexicon, List<string> foundWords) { visited[box] = true; string possibleWord = prefix + _textboxes[box].Text; bool isPrefix; bool isWord = lexicon.Contains(possibleWord, out isPrefix); if (!isPrefix) // No possible words based on this path, so abort return; if (possibleWord.Length >= MIN_WORD_LENGTH && isWord) { foundWords.Add(possibleWord); } // Visit children that haven't already been visited foreach (int child in _adjacent[box].Where(x => !visited[x])) { bool[] newVisited = new bool[16]; visited.CopyTo(newVisited, 0); FindWords(child, possibleWord, newVisited, lexicon, foundWords); } }