/// <summary> /// This method accepts a node and tries to forms its children by inserting new words one at a time. /// This is a recursive depth first built algorithm. The memory impact is very low because local variables are used. /// </summary> /// <param name="node"></param> private void InsertChildren(Node node) { foreach (Word w in node.CrozzleWords) { if (w.IsProcessed == false && w.Type == "Horizontal") { int x = w.Startx; int y = w.Starty; foreach (Char c in costSortedAlphabets) { if (w.Value.Contains(c)) { var allindexes = FindIndexes(w.Value, c); foreach (int index in allindexes) { if (node.CheckIfIntersection(x, y + index) == false) { var listOfIntersections = WordList.GetIntersections(w.Value, c).Except(node.Words).ToList(); foreach (string word in listOfIntersections) { var allIndexesInChosenWord = FindIndexes(word, c); foreach (int chosenindex in allIndexesInChosenWord) { if (node.TryFitVerticalWord(x, y + index, chosenindex, word, Rows, Columns) && TemporaryWordsAlreadyInCrozzle.Contains(word) == false) { node.SubSolutions.Add(new Word(word, "Vertical", x - chosenindex, y + index, false), GetCost(word)); } } } } } } } } } foreach (Word w in node.CrozzleWords) { if (w.IsProcessed == false && w.Type == "Vertical") { int x = w.Startx; int y = w.Starty; foreach (Char c in costSortedAlphabets) { if (w.Value.Contains(c)) { var allindexes = FindIndexes(w.Value, c); foreach (int index in allindexes) { if (node.CheckIfIntersection(x + index, y) == false) { var listOfIntersections = WordList.GetIntersections(w.Value, c).Except(node.Words).ToList(); foreach (string word in listOfIntersections) { var allIndexesInChosenWord = FindIndexes(word, c); foreach (int chosenindex in allIndexesInChosenWord) { if (node.TryFitHorizontalWord(x + index, y, chosenindex, word, Rows, Columns) && TemporaryWordsAlreadyInCrozzle.Contains(word) == false) { node.SubSolutions.Add(new Word(word, "Horizontal", x + index, y - chosenindex, false), GetCost(word)); } } } } } } } } } if (node.SubSolutions.Count == 0) { if (node.GetScore(Config) > BestNode.GetScore(Config)) { BestNode = node.Copy(); BestNode.Score = GetScore(node.Array); } } else { var sorted = node.SubSolutions.OrderByDescending(k => k.Value).ToList(); var first10sorted = sorted.Take(2); foreach (KeyValuePair <Word, Int32> pair in first10sorted) { Node childnode = new Node(); //childnode.SubSolutions = new List<Word>(); childnode.SubSolutions = new Dictionary <Word, int>(); childnode.ListOfChildren = new List <Node>(); childnode.CrozzleWords = node.CrozzleWords.ToList(); childnode.Words = node.Words.ToList(); childnode.PaddedArray = new char[Rows + 2, Columns + 2]; childnode.Array = new char[Rows, Columns]; foreach (Word w in childnode.CrozzleWords) { childnode.Insert(w.Value, w.Type, w.Startx, w.Starty); } childnode.GetPaddedArray(); childnode.Insert(pair.Key.Value, pair.Key.Type, pair.Key.Startx, pair.Key.Starty); //childnode.SubSolutions.Remove(word); childnode.CrozzleWords.Add(pair.Key); childnode.Words.Add(pair.Key.Value); //node.addChild(childnode); InsertChildren(childnode); } } }
/// <summary> /// This method does the filling work, but only for those characters which are our favourite for forming Intersections. /// </summary> /// <param name="alphabet"></param> private void DoFillingWork(char alphabet) { foreach (Word w in TemporaryCrozzleWords.ToList()) { if (w.IsProcessed == false && w.Type == "Horizontal") { int x = w.Startx; int y = w.Starty; foreach (Char c in costSortedAlphabets) { if (w.Value.Contains(c)) { var allindexes = FindIndexes(w.Value, c); foreach (int index in allindexes) { if (CheckIfIntersection(x, y + index) == false) { var listOfIntersections = WordList.GetIntersections(w.Value, c); listOfIntersections = listOfIntersections.Intersect(TemporaryWords).ToList(); listOfIntersections = listOfIntersections.OrderByDescending(s => int.Parse(s.Split(alphabet).Count().ToString())).ToList(); string bestWord = ""; int bestScore = 0; int chosenIndex = 0; foreach (string word in listOfIntersections) { var allIndexesInChosenWord = FindIndexes(word, c); foreach (int chosenindex in allIndexesInChosenWord) { if (TryFitVerticalWord(x, y + index, chosenindex, word) && TemporaryWordsAlreadyInCrozzle.Contains(word) == false) { int wordCost = GetCost(word); if (wordCost > bestScore) { bestWord = word; chosenIndex = chosenindex; bestScore = wordCost; } } } } if (bestScore != 0 || bestWord != "") { TemporaryCrozzleWords.Add(new Word(bestWord, "Vertical", x - chosenIndex, y + index, false)); Insert(bestWord, "Vertical", x - chosenIndex, y + index); TemporaryWords.Remove(bestWord); TemporaryWordsAlreadyInCrozzle.Add(bestWord); } } } } } } } foreach (Word w in TemporaryCrozzleWords.ToList()) { if (w.IsProcessed == false && w.Type == "Vertical") { int x = w.Startx; int y = w.Starty; foreach (Char c in costSortedAlphabets) { if (w.Value.Contains(c)) { var allindexes = FindIndexes(w.Value, c); foreach (int index in allindexes) { if (CheckIfIntersection(x + index, y) == false) { var listOfIntersections = WordList.GetIntersections(w.Value, c); listOfIntersections = listOfIntersections.Intersect(TemporaryWords).ToList(); listOfIntersections = listOfIntersections.OrderByDescending(s => int.Parse(s.Split(alphabet).Count().ToString())).ToList(); string bestWord = ""; int bestScore = 0; int chosenIndex = 0; foreach (string word in listOfIntersections) { var allIndexesInChosenWord = FindIndexes(word, c); foreach (int chosenindex in allIndexesInChosenWord) { if (TryFitHorizontalWord(x + index, y, chosenindex, word) && TemporaryWordsAlreadyInCrozzle.Contains(word) == false) { int wordCost = GetCost(word); if (wordCost > bestScore) { bestWord = word; bestScore = wordCost; chosenIndex = chosenindex; } } } } if (bestScore != 0 || bestWord != "") { TemporaryCrozzleWords.Add(new Word(bestWord, "Horizontal", x + index, y - chosenIndex, false)); Insert(bestWord, "Horizontal", x + index, y - chosenIndex); TemporaryWords.Remove(bestWord); TemporaryWordsAlreadyInCrozzle.Add(bestWord); } } } } } } } }
/// <summary> /// This method is called to do filling work for all characters. It will first form intersections at characters with highest cost. /// </summary> /// <returns></returns> private void DoSimpleFilling() { foreach (Word w in TemporaryCrozzleWords.ToList()) { if (w.IsProcessed == false) { if (w.Type == "Horizontal") { int x = w.Startx; int y = w.Starty; foreach (Char c in w.Value) { if (CheckIfIntersection(x, y) == false) { var listOfIntersections = WordList.GetIntersections(w.Value, c); listOfIntersections = listOfIntersections.Intersect(TemporaryWords).ToList(); foreach (string word in listOfIntersections) { if (TryFitVerticalWord(x, y, word.IndexOf(c), word)) { if (TemporaryWordsAlreadyInCrozzle.Contains(word) == false) { TemporaryCrozzleWords.Add(new Word(word, "Vertical", x - word.IndexOf(c), y, false)); Insert(word, "Vertical", x - word.IndexOf(c), y); TemporaryWords.Remove(word); TemporaryWordsAlreadyInCrozzle.Add(word); break; } } } } // move to next column y++; } } } } foreach (Word w in TemporaryCrozzleWords.ToList()) { if (w.IsProcessed == false) { if (w.Type == "Vertical") { int x = w.Startx; int y = w.Starty; foreach (Char c in w.Value) { if (CheckIfIntersection(x, y) == false) { var listOfIntersections = WordList.GetIntersections(w.Value, c); listOfIntersections = listOfIntersections.Intersect(TemporaryWords).ToList(); foreach (string word in listOfIntersections) { if (TryFitHorizontalWord(x, y, word.IndexOf(c), word)) { if (TemporaryWordsAlreadyInCrozzle.Contains(word) == false) { TemporaryCrozzleWords.Add(new Word(word, "Horizontal", x, y - word.IndexOf(c), false)); Insert(word, "Horizontal", x, y - word.IndexOf(c)); TemporaryWords.Remove(word); TemporaryWordsAlreadyInCrozzle.Add(word); break; } } } } // move to next column x++; } } } } }