Esempio n. 1
0
        private static void Main()
        {
            Console.Title = Assembly.GetExecutingAssembly().GetName().Name;

            Console.CursorVisible = true;

            Console.WriteLine(ConsoleTextBlocks.ShowWelcome("Welcome to Sudoku Solver!"));
            Console.WriteLine();

            GetAvailableSudokuGrids();

            Console.WriteLine();

            while(true)
            {
                SudokuGrid grid;
                using (var selectedFile = ConsoleInteractions.ShowListAndSelectItem(USER_ABS_DIR_AVAILABLE_GRIDS,
                    SudokuGridFile.Extension,
                    Console.In,
                    Console.Out))
                {
                    grid = SudokuGrid.FromBinary(selectedFile);
                }

                Console.WriteLine();

                var solvingTask = new Task<bool>(() =>
                {
                    var gridSolver = new SudokuSolvingIterationAssumptionTechnique(grid);
                    gridSolver.Solve();
                    gridSolver.ApplySolutionToGrid();
                    return gridSolver.SolutionExists;
                });
                var dottingTaskCTS = new CancellationTokenSource();
                var dottingTask = new Task(() => ConsoleTextBlocks.ShowBlinkingDots(dottingTaskCTS.Token, Console.Out));
                var outputTask = new Task(() => ShowSolution(grid));
                var escapeTask = new Task<bool>(ConsoleInteractions.ShowEscapeQuestion);
                var checkingCorrectnessTask = new Task<bool>(grid.CheckCorrectness);

                checkingCorrectnessTask.ContinueWith((fin) =>
                {
                    if (fin.Result)
                    {
                        solvingTask.Start();
                    }
                    else
                    {
                        Console.WriteLine(ConsoleTextMessages.IncorrectInitialConfiguration + "\n");
                        escapeTask.Start();
                    }
                }, TaskContinuationOptions.OnlyOnRanToCompletion);
                solvingTask.ContinueWith((fin) => dottingTaskCTS.Cancel(), TaskContinuationOptions.OnlyOnRanToCompletion);
                dottingTask.ContinueWith((fin) =>
                {
                    if (solvingTask.Result)
                    {
                        outputTask.Start();
                    }
                    else
                    {
                        Console.WriteLine(ConsoleTextMessages.IncorrectInitialConfiguration + "\n");
                        escapeTask.Start();
                    }
                }, TaskContinuationOptions.OnlyOnRanToCompletion);
                outputTask.ContinueWith((fin) => escapeTask.Start(), TaskContinuationOptions.OnlyOnRanToCompletion);

                dottingTask.Start();
                checkingCorrectnessTask.Start();

                escapeTask.Wait();
                if (escapeTask.Result)
                {
                    break;
                }
            }
        }
        private SudokuGridCell[,] MakeAssumptionInCell(ref SudokuGridPosition? minCandidatesCellPos)
        {
            if (!minCandidatesCellPos.HasValue)
            {
                // TODO: optimize: lookup that kind of cell repetitively when its number of candidates changes (decreases): compare against the minimum value from a variable (where to put it?)
                minCandidatesCellPos = FindFirstCellWithMinimumCandidates(Grid).Position;
            }
            var minCandidatesCell = Grid.Cells[minCandidatesCellPos.Value.Y, minCandidatesCellPos.Value.X];

            byte assumedNumber = minCandidatesCell.Candidates.ToArray()[0];

            assumptionsGrid = (SudokuGrid)Grid.GetType()
                              .GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,
                                              null, CallingConventions.HasThis, new[] { typeof(SudokuGridConstraints) }, null)
                              .Invoke(new [] { (object)Grid.Constraints });

            // BUG: !!! as we use the standard grid here, which was not initially intended to be used anywhere except for decode-and-construct scenarios, by the time we reach this code the assumptionsGrid's cells are not initialized yet -- consider introducing some sort of temporary 'grid' (most probably, a kind of 'cells-only layer'). For that reason one of the ctor's code sections was moved into the Reset() method
            var assumptionsGridSolver = new SudokuSolvingIterationAssumptionTechnique(assumptionsGrid);

            // WI: cell-to-cell iteration is a very intensive process -- use cells array cloning instead with targeted minCandidatesCell... altering
            var minCandidatesCellPosCopy = minCandidatesCellPos.Value;

            assumptionsGrid.IterateLinesXY((x, y) =>
            {
                SudokuGridCell currCell;
                var currPos = new SudokuGridPosition(x, y, false);
                if (currPos.Equals(minCandidatesCellPosCopy))
                {
                    currCell = new SudokuGridCell(assumptionsGrid, currPos, assumedNumber);
                    assumptionsGridSolver.lastFilledPos   = currPos;
                    assumptionsGridSolver.currCheckingPos = currPos;
                    assumptionsGridSolver.currCheckingPos.Shift(1, assumptionsGrid.Metrics);
                }
                else
                {
                    currCell = new SudokuGridCell(assumptionsGrid, currPos, Grid.Cells[y, x].Number);
                    if (currCell.Candidates != null)
                    {
                        // just to bring into accord with the latest value from the 'parent' grid
                        currCell.Candidates.IntersectWith(Grid.Cells[y, x].Candidates);
                    }
                }
                SudokuGrid.AssignNewCell(assumptionsGrid, currCell);
                //assumptionsGrid.Cells[y, x] = currCell;
            });

            //List<SudokuGridCell[,]> assumptionGridSolutuons = assumptionGridSolver.SearchSolutions();
            //if (assumptionGridSolutuons.Count > 0) // correct assumption was made
            //{
            //    return assumptionsGrid.Cells;
            //}

            //SudokuGridCell[,] solution;
            if (assumptionsGridSolver.SearchSolutionDebug()) // correct assumption was made
            {
                //return solution;
                return(assumptionsGrid.Cells);
            }

            // incorrect assumption was made (executes on contradiction only)
            minCandidatesCell.Candidates.Remove(assumedNumber);
            // if there were only two candidates, with assumedNumber being one of them, then the remaining one is a clue
            if (minCandidatesCell.IsClue)
            {
                minCandidatesCellPos = null;
                var newPos = new SudokuGridPosition(minCandidatesCell.Position.X, minCandidatesCell.Position.Y, false);
                lastFilledPos   = newPos;
                currCheckingPos = newPos;
                currCheckingPos.Shift(1, Grid.Metrics);
            }
            return(null);
        }
        private SudokuGridCell[,] MakeAssumptionInCell(ref SudokuGridPosition? minCandidatesCellPos)
        {
            if (!minCandidatesCellPos.HasValue)
            {
                // TODO: optimize: lookup that kind of cell repetitively when its number of candidates changes (decreases): compare against the minimum value from a variable (where to put it?)
                minCandidatesCellPos = FindFirstCellWithMinimumCandidates(Grid).Position;
            }
            var minCandidatesCell = Grid.Cells[minCandidatesCellPos.Value.Y, minCandidatesCellPos.Value.X];

            byte assumedNumber = minCandidatesCell.Candidates.ToArray()[0];

            assumptionsGrid = (SudokuGrid)Grid.GetType()
                .GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,
                null, CallingConventions.HasThis, new[] { typeof(SudokuGridConstraints) }, null)
                .Invoke(new [] { (object)Grid.Constraints });

            // BUG: !!! as we use the standard grid here, which was not initially intended to be used anywhere except for decode-and-construct scenarios, by the time we reach this code the assumptionsGrid's cells are not initialized yet -- consider introducing some sort of temporary 'grid' (most probably, a kind of 'cells-only layer'). For that reason one of the ctor's code sections was moved into the Reset() method
            var assumptionsGridSolver = new SudokuSolvingIterationAssumptionTechnique(assumptionsGrid);

            // WI: cell-to-cell iteration is a very intensive process -- use cells array cloning instead with targeted minCandidatesCell... altering
            var minCandidatesCellPosCopy = minCandidatesCellPos.Value;
            assumptionsGrid.IterateLinesXY((x, y) =>
            {
                SudokuGridCell currCell;
                var currPos = new SudokuGridPosition(x, y, false);
                if (currPos.Equals(minCandidatesCellPosCopy))
                {
                    currCell = new SudokuGridCell(assumptionsGrid, currPos, assumedNumber);
                    assumptionsGridSolver.lastFilledPos = currPos;
                    assumptionsGridSolver.currCheckingPos = currPos;
                    assumptionsGridSolver.currCheckingPos.Shift(1, assumptionsGrid.Metrics);
                }
                else
                {
                    currCell = new SudokuGridCell(assumptionsGrid, currPos, Grid.Cells[y, x].Number);
                    if (currCell.Candidates != null)
                    {
                        // just to bring into accord with the latest value from the 'parent' grid
                        currCell.Candidates.IntersectWith(Grid.Cells[y, x].Candidates);
                    }
                }
                SudokuGrid.AssignNewCell(assumptionsGrid, currCell);
                //assumptionsGrid.Cells[y, x] = currCell;
            });

            //List<SudokuGridCell[,]> assumptionGridSolutuons = assumptionGridSolver.SearchSolutions();
            //if (assumptionGridSolutuons.Count > 0) // correct assumption was made
            //{
            //    return assumptionsGrid.Cells;
            //}

            //SudokuGridCell[,] solution;
            if (assumptionsGridSolver.SearchSolutionDebug()) // correct assumption was made
            {
                //return solution;
                return assumptionsGrid.Cells;
            }

            // incorrect assumption was made (executes on contradiction only)
            minCandidatesCell.Candidates.Remove(assumedNumber);
            // if there were only two candidates, with assumedNumber being one of them, then the remaining one is a clue
            if (minCandidatesCell.IsClue)
            {
                minCandidatesCellPos = null;
                var newPos = new SudokuGridPosition(minCandidatesCell.Position.X, minCandidatesCell.Position.Y, false);
                lastFilledPos = newPos;
                currCheckingPos = newPos;
                currCheckingPos.Shift(1, Grid.Metrics);
            }
            return null;
        }