Ejemplo n.º 1
0
 public Solver(Sudoku sudoku, Func <Sudoku, T> resultSelector, Random rnd = null)
 {
     _sudoku         = sudoku;
     _resultSelector = resultSelector;
     _rnd            = rnd;
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Generates a new puzzle based specified <paramref name="solved"/>.
        /// </summary>
        /// <param name="solved">The solution the puzzle will be generated for.</param>
        /// <param name="rnd">The random.</param>
        /// <param name="backtracking">indicates how backtracking is used to reduce the number of predefined values.</param>
        public Sudoku(Sudoku solved, Random rnd, SudokuBacktrackingOption backtracking = SudokuBacktrackingOption.Allowed) : this(solved.Cross, solved.Hyper)
        {
            if (solved == null)
            {
                throw new ArgumentNullException(nameof(solved));
            }
            if (rnd == null)
            {
                throw new ArgumentNullException(nameof(rnd));
            }
            if (solved.GetState() != SudokuState.Solved)
            {
                throw new ArgumentException("specified sudoku has to be solved");
            }

            BcfTransaction mainTransaction = null;

            // a loop to enforce "Not Solvable With AutoComplete" when backtracking is SudokuBacktrackingOption.Required
            do
            {
                if (mainTransaction != null)
                {
                    mainTransaction.Rollback();
                }
                mainTransaction = _model.BeginTransaction();

                // indexes of filled cells
                var predefined = new List <int>();

                // generate a puzzle solvable using autocomplete
                {
                    var subtransaction = _model.BeginTransaction();
                    var cellEntries    = _model.CellTable.Select((cellRow, index) => new { cellRow, index });
                    while (GetState() != SudokuState.Solved)
                    {
                        cellEntries = cellEntries.Where(entry => entry.cellRow.Value == 0).Randomize(rnd);

                        var indexOfBest            = -1;
                        var bestCellCandidateCount = 0;

                        foreach (var cellEntry in cellEntries)
                        {
                            var cellCandidateCount = Util.BitCountRegister[cellEntry.cellRow.AllowedValues];
                            if (cellCandidateCount > bestCellCandidateCount)
                            {
                                bestCellCandidateCount = cellCandidateCount;
                                indexOfBest            = cellEntry.index;
                                if (bestCellCandidateCount == 9)
                                {
                                    break;                              // 9 is best possible result
                                }
                            }
                        }

                        _model.CellTable[indexOfBest].Value = solved._model.CellTable[indexOfBest].Value;
                        AutoComplete();
                        predefined.Add(indexOfBest);
                    }

                    // AutoComplete() has updated the model. In next step we need values of predefined only
                    // so rollback subtransaction
                    subtransaction.Rollback();
                }

                {
                    // and set predefined only
                    foreach (var rowIndex in predefined)
                    {
                        _model.CellTable[rowIndex].Value = solved._model.CellTable[rowIndex].Value;
                    }
                }

                // try to omit each predefined value and if the puzzle remains solvable - remove it.
                {
                    foreach (var rowIndex in predefined)
                    {
                        var subtransaction = _model.BeginTransaction();
                        _model.CellTable[rowIndex].Value = 0;
                        if (backtracking != SudokuBacktrackingOption.Disabled)
                        {
                            if (Solve(x => 0).Take(2).Count() == 1)
                            {
                                subtransaction.Commit();
                            }
                        }
                        else
                        {
                            if (CanBeSolvedUsingAutoComplete())
                            {
                                subtransaction.Commit();
                            }
                        }

                        if (!subtransaction.IsCommitted)
                        {
                            subtransaction.Rollback();
                        }
                    }
                }
            } while (backtracking == SudokuBacktrackingOption.Required && CanBeSolvedUsingAutoComplete());
        }