protected virtual void SearchUsing(Tile nextTile, List <Tile> tilesSoFar, string wordSoFar, TrieSearchResult searchResultSoFar)
        {
            tilesSoFar.Add(nextTile);
            nextTile.IsTaken = true;

            foreach (string word in nextTile.Extend(wordSoFar))
            {
                TrieSearchResult searchResult = Solution.Dictionary.Search(word, searchResultSoFar.TerminalNode);

                if (searchResult.ContainsWord)
                {
                    _words.Add(word);
                }

                if (searchResult.ContainsPrefix)
                {
                    foreach (Tile tile in _board.Tiles.Where(t => t.CanExtend(tilesSoFar)))
                    {
                        SearchUsing(nextTile: tile, tilesSoFar: tilesSoFar, wordSoFar: word, searchResultSoFar: searchResult);
                    }
                }
            }

            tilesSoFar.RemoveAt(tilesSoFar.Count - 1);
            nextTile.IsTaken = false;
        }
Beispiel #2
0
        public void Search_ForSmallTries()
        {
            var trie = new Trie(_strings);

            for (int i = 0; i < _strings.Length; ++i)
            {
                TrieSearchResult result = new TrieSearchResult();
                for (int j = 1; j <= _strings[i].Length; ++j)
                {
                    result = trie.Search(_strings[i].Substring(0, j), result.TerminalNode);

                    Assert.IsTrue(result.ContainsPrefix);
                    Assert.IsTrue(result.TerminalNode.Depth == j);

                    if (j == _strings[i].Length)
                    {
                        Assert.IsTrue(result.ContainsWord);
                        Assert.IsTrue(result.TerminalNode.IsAWordEnd);
                    }
                }
            }
            for (int i = 0; i < _evenMoreStrings.Length; ++i)
            {
                TrieSearchResult result = new TrieSearchResult();
                for (int j = 1; j <= _evenMoreStrings[i].Length; ++j)
                {
                    result = trie.Search(_evenMoreStrings[i].Substring(0, j), result.TerminalNode);

                    Assert.IsFalse(result.ContainsPrefix);
                    Assert.IsFalse(result.ContainsWord);
                    Assert.IsTrue(result.TerminalNode.Depth == 0);
                }
            }

            trie = new Trie(_moreStrings);
            for (int i = 0; i < _moreStrings.Length; ++i)
            {
                for (int j = 1; j <= _moreStrings[i].Length; ++j)
                {
                    Assert.IsTrue(trie.Search(_moreStrings[i].Substring(0, j)).ContainsPrefix);
                }
            }
            for (int i = 0; i < _evenMoreStrings.Length; ++i)
            {
                for (int j = 1; j <= _evenMoreStrings[i].Length; ++j)
                {
                    Assert.IsFalse(trie.Search(_evenMoreStrings[i].Substring(0, j)).ContainsPrefix);
                }
            }

            Assert.IsTrue(trie.Search("on").ContainsPrefix);
            Assert.IsFalse(trie.Search("ony").ContainsPrefix);
            Assert.IsFalse(trie.Search("onyx").ContainsPrefix);
            Assert.IsTrue(trie.Search("").ContainsPrefix);
            Assert.IsFalse(trie.Search("q").ContainsPrefix);
        }
Beispiel #3
0
        public void SearchTraversal_ForSmallTries()
        {
            var result = new TrieSearchResult();
            var trie   = new Trie(_strings);

            result = trie.Search("di", result.TerminalNode);
            Assert.IsFalse(result.ContainsPrefix);
            Assert.IsTrue(result.TerminalNode.Depth == 0);
            Assert.IsTrue(result.TerminalNode.Value == default(char));

            result = trie.Search("o", result.TerminalNode);
            Assert.IsTrue(result.ContainsPrefix);
            Assert.IsTrue(result.TerminalNode.Depth == 1);
            Assert.IsTrue(result.TerminalNode.Value == 'o');

            result = trie.Search("on", result.TerminalNode);
            Assert.IsTrue(result.ContainsPrefix);
            Assert.IsTrue(result.TerminalNode.Depth == 2);
            Assert.IsTrue(result.TerminalNode.Value == 'n');

            result = trie.Search("onwa", result.TerminalNode);
            Assert.IsTrue(result.ContainsPrefix);
            Assert.IsTrue(result.TerminalNode.Depth == 4);
            Assert.IsTrue(result.TerminalNode.Value == 'a');

            result = trie.Search("onwarp", result.TerminalNode);
            Assert.IsFalse(result.ContainsPrefix);
            Assert.IsTrue(result.TerminalNode.Depth == 5);
            Assert.IsTrue(result.TerminalNode.Value == 'r');

            result = trie.Search("onwardly", result.TerminalNode);
            Assert.IsFalse(result.ContainsPrefix);
            Assert.IsFalse(result.ContainsWord);
            Assert.IsTrue(result.TerminalNode.Depth == 6);
            Assert.IsTrue(result.TerminalNode.Value == 'd');
            Assert.IsTrue(result.TerminalNode.IsAWordEnd);

            result = trie.Search("onward", result.TerminalNode);
            Assert.IsTrue(result.ContainsPrefix);
            Assert.IsTrue(result.ContainsWord);
            Assert.IsTrue(result.TerminalNode.Depth == 6);
            Assert.IsTrue(result.TerminalNode.Value == 'd');
            Assert.IsTrue(result.TerminalNode.IsAWordEnd);
        }
Beispiel #4
0
        // We use the rules governing board movement to figure out what tiles to try using next. For each of those tiles, we check
        // to see if it can extend the path. For example, if a tile is already used in the path, then it can't extend it. For each
        // of those tiles, we recurse. In the recursion, we know the tile can extend the path, so we stick it on. In extending the
        // path it produces some number of strings (one, possibly two) to check the trie for. Since these strings are prefixed by
        // the string searched for previously, we use the previous search result to jump to the start location in the trie. If the
        // trie doesn't contain the string as a prefix then we don't recurse, because it'll contain nothing after this point either,
        // since we're prefixing whatever would be next. Jumping down the trie with the previous search result isn't a big deal,
        // performance-wise--but stopping when we know the string doesn't prefix anything in the dictionary is. A simple HashSet
        // doesn't get us the latter. A sorted list can, but with an extra log(n) factor.
        protected virtual void SearchUsing(Tile nextTile, List <Tile> tilesSoFar, string stringSoFar, TrieSearchResult searchResultSoFar)
        {
            tilesSoFar.Add(nextTile);
            nextTile.IsTaken = true;

            foreach (string @string in nextTile.Extend(stringSoFar))
            {
                TrieSearchResult searchResult = Dictionary.Search(@string, searchResultSoFar.TerminalNode);

                if (searchResult.ContainsWord)
                {
                    // If we don't have a corresponding Word for the string yet, create one.
                    if (!_stringWordMap.TryGetValue(@string, out Word word))
                    {
                        word = new Word(@string);
                        _stringWordMap[@string] = word;
                    }

                    // If we don't have a corresponding Path for the tiles yet, create one.
                    if (!_tilesPathMap.TryGetValue(tilesSoFar, out Path path))
                    {
                        var tilesCopy = tilesSoFar.ToArray();
                        path = new Path(tilesCopy);
                        _tilesPathMap[tilesCopy] = path;
                    }

                    // Tie the word and the path together.
                    word.AddPath(path);
                    path.AddWord(word);
                }

                if (searchResult.ContainsPrefix)
                {
                    foreach (Tile tile in _board.Tiles.Where(t => t.CanExtend(tilesSoFar)))
                    {
                        SearchUsing(nextTile: tile, tilesSoFar: tilesSoFar, stringSoFar: @string, searchResultSoFar: searchResult);
                    }
                }
            }

            tilesSoFar.RemoveAt(tilesSoFar.Count - 1);
            nextTile.IsTaken = false;
        }