private void FillUnkownCellsAsEmpties() { // вызывается, если все "черные" ячейки заполнены. заполняет неокрашенные ячейки пустотами for (int i = 0; i < RowsCount; i++) { for (int j = 0; j < ColumnsCount; j++) { if (mainField[i, j].State == StatesOfCell.unknown) { mainField[i, j].State = StatesOfCell.empty; Cell.FillCell(i, j, false); } } } }
internal static void SetStatics(RowOrColumnToBeCalculated[] rowsAndColumnsToBeCalculated, CloneOfStaticsOfRowOrColumnToBeCalculated clone) { // возврат статических значений при вызове перебора всех вариантов CloneArray(clone.cloneRowOrColumnToBeCalculated, rowsAndColumnsToBeCalculated); rowsAndColumnsToBeCalculated = (RowOrColumnToBeCalculated[])clone.cloneRowOrColumnToBeCalculated.Clone(); IsError = false; IsMainFieldFilled = clone.isMainFieldFilled; TotalFilledCells = clone.totalFilledCells; for (int i = 0; i < RowsCount; i++) { for (int j = 0; j < ColumnsCount; j++) { mainField[i, j] = new Cell(); mainField[i, j].State = clone.mainField[i, j].State; Cell.FillCell(i, j, mainField[i, j].State == StatesOfCell.empty ? false : true, mainField[i, j].State == StatesOfCell.unknown ? true : false); } } }
private bool TryFillCellFullOrEmpty(RowOrColumnToBeCalculated[] rowsAndColumnsToBeCalculated, int deep = 0) { bool isAnyResultInThisItitration = false; // если варианты расположения условия не расчитаны - рассчитать if (!areAllVariantsCalculated) { VariantsCount = 0; SetPossibleSolusions(); areAllVariantsCalculated = true; IsNeedToRemoveVariants = false; } // если есть необходимость удалить неподходящие варианты* - удалить или дождаться выполнения удаления // *как только в какой-либо строке/столбце закрашивается любая ячейка, то часть вариантов расположения условия для столбца/строки этой ячейки можно отсечь if (IsNeedToRemoveVariants) { if (tasksForRemovingIrrelevantVariants.Count == 0) { TryRemoveIrrelevantVariants(); IsNeedToRemoveVariants = false; } else { //while (IsNeedToRemoveVariants) Task.WaitAll(tasksForRemovingIrrelevantVariants.ToArray()); } } if (VariantsCount == 0) { IsError = true; return(false); } (int, int)link = (IsRow ? IndexOfRowOrColumn : 0, IsRow ? 0 : IndexOfRowOrColumn); // проверка для каждой ячейки в дальнейшем решении for (int i = 0; i < lengthOfRowOrColumn; i++) { if (IsRow) { link.Item2 = i; } else { link.Item1 = i; } // если ячейка уже заполнена - переходим к следующей if (mainField[link.Item1, link.Item2].State == StatesOfCell.unknown) { // сравниваем значение данной ячейки в каждом из вариантов bool target = possibleSolutions[0][i]; bool areAllVariantsEquelForThisCell = true; for (int j = 1; j < VariantsCount; j++) { if (possibleSolutions[j][i] != target) { areAllVariantsEquelForThisCell = false; VariantsCount = possibleSolutions.Count; break; } } // если во всех вариантах расположения условия данная ячейка одинакова, то if (areAllVariantsEquelForThisCell) { mainField[link.Item1, link.Item2].State = target ? StatesOfCell.full : StatesOfCell.empty; // заполняем поле с решением Cell.FillCell(link.Item1, link.Item2, target); // красим ячейку для вывода пользователю TotalFilledCells += target ? 1 : 0; // увеличиваем счетчик заполненных "черных" ячеек isAnyResultInThisItitration = true; // указываем, что в данной итерации была заполнена как минимум 1 ячейка, т.е. следующую итерацию нужно начинать с элемента, // у которого меньше всего вариантов расположения условия int rowOrColumnToChangeIndex = i + (IsRow ? RowsCount : 0); // ячейка заполнена, значит можно отсечь часть вариантов, указываем индекс строки/столбца для удаления вариантов if (rowsAndColumnsToBeCalculated[rowOrColumnToChangeIndex].areAllVariantsCalculated == true) // если все варианты уже расчитаны, то запускаем удаление неподходящих в фоне { // в противном случае неподходящие варианты будут отсечены на этапе расчета rowsAndColumnsToBeCalculated[rowOrColumnToChangeIndex].IsNeedToRemoveVariants = true; // ***запуск расчета всех вариантов в фоне может занять очень большой объем памяти для больших кроссвордов AddAndStartTaskForRemovingIrrelevantVariants(rowsAndColumnsToBeCalculated, rowOrColumnToChangeIndex, IndexOfRowOrColumn); } } } } if (VariantsCount == 1) // если остался только один вариант, { IsFull = true; // строка заполнена if (TotalFilledCells == TotalFilledCellsTarget) // если все "черные" клетки заполнены, { IsMainFieldFilled = true; // решение найдено FillUnkownCellsAsEmpties(); // заполняем оставшиеся (если такие будут) незаполненные ячейки "пустыми" return(false); // выходим из цикла } } if (!isAnyResultInThisItitration && // если ни одна ячейка не заполнена за текущую итерацию, deep + 1 < RowsCount + ColumnsCount && // просматривается не последний элемент, !rowsAndColumnsToBeCalculated[GetIndexOfRowOrColumnByNumberInQueue(rowsAndColumnsToBeCalculated, deep + 1)].IsFull) // следующий элемент не заполнен полностью, //то рекурсивный вызов следующего элемента { isAnyResultInThisItitration = rowsAndColumnsToBeCalculated[GetIndexOfRowOrColumnByNumberInQueue(rowsAndColumnsToBeCalculated, deep + 1)].TryFillCellFullOrEmpty(rowsAndColumnsToBeCalculated, deep + 1); } return(isAnyResultInThisItitration); }