Ejemplo n.º 1
0
            private readonly Stack <AllowedValueEnumerator> _stack; // store for regression

            public SolutionEnumerator(Sudoku sudoku, Func <Sudoku, T> resultSelector, Random rnd)
            {
                _sudoku         = sudoku;
                _resultSelector = resultSelector;
                _rnd            = rnd;
                _stack          = new Stack <AllowedValueEnumerator>();
                _transaction    = sudoku._model.BeginTransaction().Compute();
                _stack.Push(new AllowedValueEnumerator(sudoku, rnd));
            }
Ejemplo n.º 2
0
 public bool MoveNext()
 {
     while (_valueEnumerator.MoveNext())
     {
         // rollback previous enumeration step result
         if (!ReferenceEquals(null, _transaction))
         {
             _transaction.Rollback();
         }
         // create a subtransaction
         _transaction = _sudoku._model.BeginTransaction();
         // assign value
         _cell.Value = _valueEnumerator.Current;
         // autocomplete other cells
         _sudoku.AutoComplete();
         // in case of error try next value (if there is one)
         if (_sudoku.GetState() != SudokuState.Error)
         {
             return(true);
         }
     }
     return(false);
 }
Ejemplo n.º 3
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());
        }
Ejemplo n.º 4
0
 internal Scope([NotNull] BcfTransaction transaction, Action <Exception> onError = null)
 {
     _transaction = transaction;
     _onError     = onError;
 }