public bool CreateTwoSymmetricOpenCells(Coordinates coord) { if ((coord.X < 1) || (coord.Y < 1)) { return(false); } if ((coord.X >= constants.dimensions) || (coord.Y >= constants.dimensions)) { return(false); } ICell cell = cellMatrix[coord.X, coord.Y]; if (cell == null) { debugLog.Write("creating an open cell at (" + coord.X + "," + coord.Y + ")\n"); OpenCell newCell = new OpenCell(coord, this); cellMatrix[coord.X, coord.Y] = newCell; openCells.Push(newCell); } Coordinates symmCoord = new Coordinates (constants.dimensions - coord.X, constants.dimensions - coord.Y); ICell symmetricCell = cellMatrix[symmCoord.X, symmCoord.Y]; if (symmetricCell == null) { debugLog.Write("creating a symmetric open cell at (" + symmCoord.X + "," + symmCoord.Y + ")\n"); OpenCell newCell = new OpenCell(symmCoord, this); cellMatrix[symmCoord.X, symmCoord.Y] = newCell; openCells.Push(newCell); } return(true); }
private bool FinalizeCell(OpenCell cellToFinalize) { debugLog.Write(" FinalizeCell " + cellToFinalize.ToString() + "...\n"); if (!cellToFinalize.OnlyOneSolution()) { debugLog.Write("Finalize is a no-op, since there is still more than one possible solution.\n"); return(false); } data.MoveToSolvedList(cellToFinalize); data.availableDigits.Remove(cellToFinalize.GetValue()); cellToFinalize.SetCellAsSolved(); foreach (OpenCell cell in data.GetCopyOfUnsolvedCells()) { if (cell == cellToFinalize) { continue; } SolutionInfo solutionInfo = cell.UpdateValueList(true); //if (solutionInfo.MovedCloserToSolution() && cell.OnlyOneSolution()) // FinalizeCell(cell); } return(true); }
public void MoveToSolvedList(OpenCell cell) { if (!unsolvedList.Remove(cell)) { return; } solvedList.Add(cell); }
public void FinalizeBothParents(OpenCell cellToFinalize) { bool cellWasFinalized = true; foreach (CellGroup parentGroup in cellToFinalize.GetParentGroups()) { cellWasFinalized &= parentGroup.FinalizeCell(cellToFinalize); } if (cellWasFinalized) { debugLog.Write("Finalized " + cellToFinalize.ToString() + ".\n"); } }
private void CreateARowGroup(Coordinates coordinates) { Queue <OpenCell> cellQueue = new Queue <OpenCell>(); SumCell rowSumCell = (SumCell)cellMatrix[coordinates.X - 1, coordinates.Y]; while ((coordinates.X < constants.dimensions) && CellIsOpen(coordinates)) { OpenCell cellToAdd = (OpenCell)cellMatrix[coordinates.X, coordinates.Y]; cellQueue.Enqueue(cellToAdd); coordinates = new Coordinates(coordinates.X + 1, coordinates.Y); } CellGroup newGroup = new RowCellGroup(rowSumCell, new List <OpenCell>(cellQueue), debugLog); CellGroup.rowList.Add(newGroup); cellGroupsWithoutSums.Push(newGroup); }
private SolutionInfo CheckCellValuesForViability(OpenCell cell) { // debugLog.Write("CheckCellValuesForViability(" + cell.ToString() + ")"); SolutionInfo solutionInfo = new SolutionInfo(); int sumOfUnsolvedCels = SumOfAllUnsolvedCells(); if (sumOfUnsolvedCels == 0) { solutionInfo.solvable = false; return(solutionInfo); } List <int> possibleDigits = new List <int>(cell.GetPossibleValues()); int initialNumberOfDigits = cell.GetPossibleValues().Count; List <OpenCell> copyOfUnsolvedCellList = data.GetCopyOfUnsolvedCells(); copyOfUnsolvedCellList.Remove(cell); Stack <OpenCell> cellStack = new Stack <OpenCell>(copyOfUnsolvedCellList); foreach (int digit in possibleDigits) { if (digit <= sumOfUnsolvedCels) { List <int> availableDigitsFromGroup = new List <int>(data.availableDigits); availableDigitsFromGroup.Remove(digit); if (!SumWorksForGroup(sumOfUnsolvedCels - digit, availableDigitsFromGroup, cellStack)) { cell.DigitIsNotAPossibleValue(digit); } } else { cell.DigitIsNotAPossibleValue(digit); } } int finalNumberOfDigits = cell.GetPossibleValues().Count; solutionInfo.increaseInNumber = finalNumberOfDigits - initialNumberOfDigits; debugLog.Write(" Validate cell " + cell.ToString() + "(start:" + initialNumberOfDigits + " end:" + finalNumberOfDigits + ")\n"); if (finalNumberOfDigits == 0) { solutionInfo.solvable = false; } return(solutionInfo); }
private bool SolveForLastCell() { debugLog.Write("Only one cell to try. Solving that cell...\n"); OpenCell cellToSolve = data.GetCopyOfUnsolvedCells().ElementAt(0); int randomValue = cellToSolve.GetARandomValue(); if (randomValue == 0) { return(false); } int sum = SumOfAllSolvedCells() + randomValue; if (data.unusableSums.Contains(sum)) { cellToSolve.DigitIsNotAPossibleValue(randomValue); return(SolveForLastCell()); } cellToSolve.SetToAValue(randomValue); FinalizeBothParents(cellToSolve); return(UpdateSum(sum)); // Need to deal with a failure here... }
private bool SumWorksForGroup(int sum, List <int> possibleDigits, Stack <OpenCell> cells) { // steps: // 1) pick a possible digit from the first item in the list. // 2) make sure that the digit chosen can't be used again. // 3) recurse using the sum that was passed in minus the chosen digit. //debugLog.Write(" Trying[sum:" + sum + ",cellCount:" + cells.Count() + "\n"); if (cells.Count == 0) { return((sum == 0) ? true : false); } OpenCell cellToTry = cells.Pop(); foreach (int possibleValue in cellToTry.GetPossibleValues()) { if ((possibleValue <= sum) && (possibleDigits.Contains(possibleValue))) { possibleDigits.Remove(possibleValue); bool sumWorks = SumWorksForGroup(sum - possibleValue, possibleDigits, cells); if (sumWorks) { // debugLog.Write(" Return true...\n"); cells.Push(cellToTry); possibleDigits.Add(possibleValue); return(true); } else { possibleDigits.Add(possibleValue); } } } cells.Push(cellToTry); return(false); }
public void AddOpenCell(OpenCell cell) { Controls.Add(cell); }
/****************************************************** * SetTheSum ****************************************************** * Chooses a random solution from the possibilities. This method assumes * the entire puzzle is in a state where all invalid values have been * tossed out. * * This method gets the cell group to a point where it is internally consistent. * It is up to the caller of this method to ensure that the rest of the puzzle * still works with the changes made here. * * Pick any valid digit for the cellToTry. See if the cellToTry can be forced to * that digit by: * 1) setting the sum of this group (assuming it hasn't already been set) * 2) setting the sum of the orthoganal group (again, if it hasn't been set.) * 3) Seeing if minimizing this group's sum and maximizing the other's works. * 4) Maximize this group and minimize the other, and see if that works. * 5) if nothing works, return false and try a different cellToTry. ******************************************************/ public UpdateResult SetTheSum() { debugLog.Write("Method SetTheSum called...\n"); BackUpData(); // UpdateResult result = new UpdateResult(); if (data.NumberOfUnsolvedCells() == 0) { if (!SumIsKnown()) { debugLog.Write("Returning for empty unsolvedCellList. Had to set the sum.\n"); if (!UpdateSum(SumOfAllSolvedCells())) { throw new UnsolvableGroupException2 ("The sum of all the cells apparently doesn't work for this group."); } return(UpdateResult.changed); } debugLog.Write("Returning for empty unsolvedCellList.\n"); return(UpdateResult.unchanged); } if (SumIsKnown()) { debugLog.Write("Returning for already determined sum.\n"); PrintAllCells(); return(UpdateResult.unchanged); } UpdateAvailableValueList(); // If this changes the group, is it bad to return unchanged later on?. PrintAllCells(); if (OneUnsolvedCellLeft()) { if (!SolveForLastCell()) { throw new UnsolvableGroupException2("Tried the one possible solution, and bombed out."); } return(UpdateResult.changed); } OpenCell cellToSolve = data.GetCopyOfUnsolvedCells().ElementAt(0); // To Do: Need to make this truly random. if (cellToSolve.TendencyOfCell() == Tendency.low) { int sum = 0; bool successful = MaximumSum(out sum); if (!successful) { throw new UnsolvableGroupException2("MaximumSum couldn't find anything."); } if (!UpdateSum(sum)) { throw new IllegalSumException2("Setting to maximum failed."); } } else { int sum = 0; bool successful = MinimumSum(out sum); if (!successful) { throw new UnsolvableGroupException2("MinimumSum couldn't find anything."); } if (!UpdateSum(sum)) { throw new IllegalSumException2("Setting to minimum failed."); } } return(UpdateResult.changed); }