public static List <List <CrosswordBuilder.Cell> > CopyCellsList(List <List <CrosswordBuilder.Cell> > cells) { List <List <CrosswordBuilder.Cell> > cellsCopy = new List <List <CrosswordBuilder.Cell> >(); for (int i = 0; i < cells.Count; i++) { cellsCopy.Add(new List <CrosswordBuilder.Cell>()); for (int j = 0; j < cells[i].Count; j++) { CrosswordBuilder.Cell cell = cells[i][j]; CrosswordBuilder.Cell cellCopy = new CrosswordBuilder.Cell(); cellCopy.isBlock = cell.isBlock; cellCopy.isNumbered = cell.isNumbered; cellCopy.character = cell.character; cellCopy.startRowAcross = cell.startRowAcross; cellCopy.startColAcross = cell.startColAcross; cellCopy.acrossCount = cell.acrossCount; cellCopy.hasAcrossWord = cell.hasAcrossWord; cellCopy.startRowDown = cell.startRowDown; cellCopy.startColDown = cell.startColDown; cellCopy.downCount = cell.downCount; cellCopy.hasDownWord = cell.hasDownWord; cellsCopy[i].Add(cellCopy); } } return(cellsCopy); }
public List <string> GetPossibleWords(List <List <CrosswordBuilder.Cell> > cells, int startRow, int startCol, int length, bool isAcross) { if (!HasWordsOfLength(length)) { // Return an empty list return(null); } string wordDictKey = ""; List <string> possibleWords = null; for (int i = 0; i < length; i++) { int row = startRow + (isAcross ? 0 : i); int col = startCol + (isAcross ? i : 0); CrosswordBuilder.Cell cell = cells[row][col]; if (cell.character != ' ') { wordDictKey = CBWordDict.AddToKey(wordDictKey, i, cell.character); if (length > CBUtilities.MaxLengthForFullWordMapping) { List <string> words = GetMappedWords(length, wordDictKey); // If there are no words with this key then there are no words that fit in the given cells if (words == null) { return(null); } // If the new list is less than the one we have so far then lets use that one instead if (possibleWords == null || words.Count < possibleWords.Count) { possibleWords = words; } wordDictKey = ""; } } } // If possible words is not null then we still need to get the words if (possibleWords == null) { // If wordDictKey is empty then all the cells are blank if (string.IsNullOrEmpty(wordDictKey)) { // Return all words of the given length return(loadedWords[length]); } // Return the words using the key return(GetMappedWords(length, wordDictKey)); } return(possibleWords); }
public static void RemoveWord(List <List <CrosswordBuilder.Cell> > cells, int startRow, int startCol, int length, bool across) { bool removedOneChar = false; for (int i = 0; i < length; i++) { int row = startRow + (across ? 0 : i); int col = startCol + (across ? i : 0); CrosswordBuilder.Cell cell = cells[row][col]; if (across) { CrosswordBuilder.Cell downStartCell = cells[cell.startRowDown][cell.startColDown]; if (!downStartCell.hasDownWord) { cell.character = ' '; removedOneChar = true; } } else { CrosswordBuilder.Cell acrossStartCell = cells[cell.startRowAcross][cell.startColAcross]; if (!acrossStartCell.hasAcrossWord) { cell.character = ' '; removedOneChar = true; } } } if (removedOneChar) { CrosswordBuilder.Cell startCell = cells[startRow][startCol]; if (across) { startCell.hasAcrossWord = false; startCell.acrossWord = ""; } else { startCell.hasDownWord = false; startCell.downWord = ""; } } }
private bool TryWord(string word, int startRow, int startCol, bool isAcross, int depth, out int fitCount) { fitCount = 0; UsedWords.Add(word); List <CrosswordBuilder.Cell> changedCells = new List <CrosswordBuilder.Cell>(); // Place the word, keeping track of the cells that where changed for (int i = 0; i < word.Length; i++) { int row = startRow + (isAcross ? 0 : i); int col = startCol + (isAcross ? i : 0); CrosswordBuilder.Cell cell = Cells[row][col]; if (cell.character == ' ') { changedCells.Add(cell); cell.character = word[i]; } } bool foundFitForAllChangedCells = true; // Check the perpendicular cells for all the cells what where blank, these are the ones without words on them for (int i = 0; i < changedCells.Count; i++) { if (Stopping) { // Threads are shutting down, we don't care about the state of Cells so just return return(false); } // Get the start row and col of the perpendicular word int sr = isAcross ? changedCells[i].startRowDown : changedCells[i].startRowAcross; int sc = isAcross ? changedCells[i].startColDown : changedCells[i].startColAcross; CrosswordBuilder.Cell startCell = Cells[sr][sc]; int len = isAcross ? startCell.downCount : startCell.acrossCount; if (len == 1) { continue; } // Get the words that can fit in the cells given the characters that are already there List <string> wordsToTry = WordDictionary.GetPossibleWords(Cells, sr, sc, len, !isAcross); // If wordsToTry is null then there was no word that can fit in the cell if (wordsToTry == null) { foundFitForAllChangedCells = false; break; } fitCount += wordsToTry.Count; // If there were words that could fit in the cells and depth is 0 then dont check the individual words, just continue to the next changed cell if (depth >= CBUtilities.MaxCheckDepth && len <= CBUtilities.MaxLengthForFullWordMapping) { continue; } bool foundFit = false; for (int j = 0; j < wordsToTry.Count; j++) { if (Stopping) { // Threads are shutting down, we don't care about the state of Cells so just return return(false); } string wordToTry = wordsToTry[j]; bool fits = true; // Don't reuse words if (UsedWords.Contains(wordToTry)) { continue; } if (len > CBUtilities.MaxLengthForFullWordMapping) { for (int k = 0; k < len; k++) { int row = sr + (!isAcross ? 0 : k); int col = sc + (!isAcross ? k : 0); CrosswordBuilder.Cell cell = Cells[row][col]; if (cell.character != ' ' && cell.character != wordToTry[k]) { fits = false; break; } } } if (fits) { int temp = 0; // Check if this word will cause the baord to be unsolvable if (depth >= CBUtilities.MaxCheckDepth || TryWord(wordToTry, sr, sc, !isAcross, depth + 1, out temp)) { // This word doesn't cause the board to be unsolvable (alteast up to the depth that was set) foundFit = true; // If depth is one we want to count how many words fit so we can present the best ones to the user break; } } } // We could not fit a word without causing an unsolvable board, so the word we where given cannot be placed if (!foundFit) { foundFitForAllChangedCells = false; break; } } fitCount = (int)((float)fitCount / (float)changedCells.Count); // Set the changed cells back to blank for (int i = 0; i < changedCells.Count; i++) { changedCells[i].character = ' '; } UsedWords.Remove(word); return(foundFitForAllChangedCells); }
public static List <CrosswordBuilder.Cell> PlaceWordOnCell(string word, List <List <CrosswordBuilder.Cell> > cells, int startRow, int startCol, int length, bool across) { List <CrosswordBuilder.Cell> blankCells = new List <CrosswordBuilder.Cell>(); CrosswordBuilder.Cell startCell = cells[startRow][startCol]; if (across) { startCell.hasAcrossWord = true; startCell.acrossWord = word; length = startCell.acrossCount; } else { startCell.hasDownWord = true; startCell.downWord = word; length = startCell.downCount; } for (int i = 0; i < length; i++) { int row = startRow + (across ? 0 : i); int col = startCol + (across ? i : 0); CrosswordBuilder.Cell cell = cells[row][col]; if (cell.character == ' ') { blankCells.Add(cell); } // Set the character in the cell cell.character = word[i]; // Now we need to check if this created a crossing word bool crossAcross = !across; int crossRowStart = crossAcross ? cell.startRowAcross : cell.startRowDown; int crossColStart = crossAcross ? cell.startColAcross : cell.startColDown; int crossLength = crossAcross ? cell.acrossCount : cell.downCount; string crossWord = ""; bool setCrossWord = true; if (crossLength == 1) { setCrossWord = false; } else { for (int j = 0; j < crossLength; j++) { int crossRow = crossRowStart + (crossAcross ? 0 : j); int crossCol = crossColStart + (crossAcross ? j : 0); CrosswordBuilder.Cell crossCell = cells[crossRow][crossCol]; if (crossCell.character == ' ') { setCrossWord = false; break; } crossWord += crossCell.character; } } if (setCrossWord) { CrosswordBuilder.Cell crossStartCell = cells[crossRowStart][crossColStart]; if (crossAcross) { crossStartCell.hasAcrossWord = true; crossStartCell.acrossWord = crossWord; } else { crossStartCell.hasDownWord = true; crossStartCell.downWord = crossWord; } } } return(blankCells); }