public IEnumerable <Gaddag> FindAllWords(Bank bank) { if (isEndOfWord) { yield return(this); } for (char c = 'a'; c <= 'z'; ++c) { if (!bank.HasLetter(c) || this[c] == null) { continue; } Bank after = new Bank(bank); after.TakeLetter(c); foreach (Gaddag word in this[c].FindAllWords(after)) { yield return(word); } } if (this['{'] != null) { foreach (Gaddag word in this['{'].FindAllWords(bank)) { yield return(word); } } }
public IEnumerable <Placement> FindLinePlacementsFrom(int lineIndex, int start, int frontLeeway, bool vertical, Bank startingBank, Gaddag words) { Dictionary <int, Line> axis = vertical ? columns : rows; Line line = axis[lineIndex]; Line[] neighbors = new Line[2]; neighbors[0] = GetLineLazy(axis, lineIndex - 1); neighbors[1] = GetLineLazy(axis, lineIndex + 1); Stack <(Gaddag, int, Bank)> nodes = new Stack <(Gaddag, int, Bank)>(); nodes.Push((words, start, startingBank)); while (nodes.Count != 0) { (Gaddag node, int index, Bank bank) = nodes.Pop(); if (line.IsEmptyAt(index)) { if (!(neighbors[0].IsEmptyAt(index) && neighbors[1].IsEmptyAt(index))) { continue; } for (char c = 'a'; c <= 'z'; ++c) { if (!bank.HasLetter(c) || node[c] == null) { continue; } Bank after = new Bank(bank); after.TakeLetter(c); nodes.Push((node[c], index - 1, after)); } if (node['{'] != null) { foreach (Gaddag word in node['{'].FindAllWords(bank)) { if (word.word.Length - word.reversePoint >= frontLeeway) { continue; } Bank after = new Bank(bank); after.TakeWord(word.word.Substring(word.reversePoint + 1)); if (Enumerable.SequenceEqual(startingBank.letters, after.letters)) { continue; } yield return(new Placement(word.word, lineIndex, start - word.reversePoint, vertical, after)); } } } else { char c = line[index]; if (node[c] != null) { nodes.Push((node[c], index - 1, bank)); } } } }
public float CalculateValue(List <string> words) { int exacts = 0; int exactCandidates = 0; int inexacts = 0; int inexactCandidates = 0; // The Size getter is actually quite expensive so we cache the size here. int size = Size; // I would much prefer a foreach here, but for actually gives better performance. for (int i = 0; i < words.Count; ++i) { string word = words[i]; if (word.Length > size + 1) { continue; } else if (word.Length == size + 1) { exactCandidates += 1; } else { inexactCandidates += 1; } Bank bank = new Bank(this); bool oneExtra = false; foreach (char c in word) { if (!bank.HasLetter(c)) { if (oneExtra) { // This word doesn't match, so skip it. oneExtra = false; break; } else { oneExtra = true; } } else { bank.TakeLetter(c); } } if (oneExtra) { if (word.Length == size + 1) { exacts += 1; } else { inexacts += 1; } } } float exactFreq = exactCandidates == 0 ? 0 : (float)exacts / exactCandidates; float inexactFreq = inexactCandidates == 0 ? 0 : (float)inexacts / inexactCandidates; float value = exactFreq * ExactWeight + inexactFreq * (1 - ExactWeight); return(value); }