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