コード例 #1
0
        /// <summary>
        /// Generate sudoku to fill from full-filled sudoku
        /// </summary>
        /// <param name="sudoku"></param>
        /// <param name="notCheckedPositionsFromPrev"></param>
        /// <param name="difficultyPoints"></param>
        /// <param name="symmetry"></param>
        /// <param name="token">Cancellation token</param>
        /// <returns></returns>
        private static bool GenerateFromFull(Domain.Sudoku sudoku, IEnumerable <Tuple <int, int> > notCheckedPositionsFromPrev,
                                             int difficultyPoints, Enums.SymmetryType symmetry, CancellationToken token)
        {
            var notCheckedPositions = new List <Tuple <int, int> >(notCheckedPositionsFromPrev);

            while (notCheckedPositions.Count > 0)
            {
                token.ThrowIfCancellationRequested();

                var removedCells = RemoveNext(sudoku, notCheckedPositions, symmetry);

                var solutions = Solver.GetTopNSolutions(sudoku, 2, Enums.TopType.Any);

                if (solutions.Count == 1 && solutions.First().DifficultyPoints > difficultyPoints)
                {
                    sudoku.DifficultyPoints = solutions.First().DifficultyPoints;
                    return(true);
                }

                if (solutions.Count > 1)
                {
                    RecoverCells(sudoku, removedCells);
                    return(false);
                }

                if (GenerateFromFull(sudoku, notCheckedPositions, difficultyPoints, symmetry, token))
                {
                    return(true);
                }

                RecoverCells(sudoku, removedCells);
            }

            return(false);
        }
コード例 #2
0
        /// <summary>
        /// Check if Sudoku remain consistent if we put number in specified location
        /// </summary>
        /// <param name="board">Board to check</param>
        /// <param name="row">row in board</param>
        /// <param name="column">column in board</param>
        /// <param name="value">value to put</param>
        /// <returns></returns>
        public static bool ConsistentIfPut(Domain.Sudoku board, int row, int column, int value)
        {
            for (var i = 0; i < Domain.Sudoku.BigSide; i++)
            {
                if (board[row, i] == value)
                {
                    return(false);
                }
                if (board[i, column] == value)
                {
                    return(false);
                }
            }

            var rowStart    = row - row % Domain.Sudoku.SmallSide;
            var columnStart = column - column % Domain.Sudoku.SmallSide;

            for (var m = 0; m < Domain.Sudoku.SmallSide; m++)
            {
                for (var k = 0; k < Domain.Sudoku.SmallSide; k++)
                {
                    if (board[rowStart + k, columnStart + m] == value)
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
コード例 #3
0
ファイル: SimpleSolver.cs プロジェクト: ilyakom/Sudoku
        private void ClearAndSolve(Domain.Sudoku sudoku, int currentIndex, Enums.TopType type, int count)
        {
            _currentIterationsCount = 0;
            _solutions.Clear();

            SolveBruteForce(sudoku, currentIndex, type, count);
        }
コード例 #4
0
        private static void RecoverCells(Domain.Sudoku sudoku, IList <Cell> cellsToRecover)
        {
            foreach (var cell in cellsToRecover)
            {
                sudoku[cell.Row, cell.Column] = cell.Value;
            }

            cellsToRecover.Clear();
        }
コード例 #5
0
ファイル: SimpleSolver.cs プロジェクト: ilyakom/Sudoku
        /// <summary>
        /// Count number of solutions for given sudoku
        /// </summary>
        /// <param name="sudoku"></param>
        /// <returns></returns>
        public int CountSolutions(Domain.Sudoku sudoku)
        {
            if (sudoku == null)
            {
                throw new ArgumentNullException(nameof(sudoku));
            }

            ClearAndSolve(sudoku.Copy(), 0, Enums.TopType.Any, int.MaxValue);
            return(_solutions.Count);
        }
コード例 #6
0
ファイル: SimpleSolver.cs プロジェクト: ilyakom/Sudoku
        /// <summary>
        /// Solve sudoku and return first available solution
        /// </summary>
        /// <param name="sudoku"></param>
        /// <returns></returns>
        public Domain.Sudoku SolveSudoku(Domain.Sudoku sudoku)
        {
            if (sudoku == null)
            {
                throw new ArgumentNullException(nameof(sudoku));
            }

            ClearAndSolve(sudoku.Copy(), 0, Enums.TopType.Any, 1);

            return(_solutions.FirstOrDefault());
        }
コード例 #7
0
ファイル: SudokuAdapter.cs プロジェクト: ilyakom/Sudoku
        /// <summary>
        /// Save sudoku to local file named <see cref="LocalFile"/>
        /// </summary>
        /// <param name="sudoku"><see cref="Domain.Sudoku"/>></param>
        /// <returns></returns>
        public static async Task SaveSudokuAsync(Domain.Sudoku sudoku)
        {
            if (sudoku == null)
            {
                throw new NullReferenceException(nameof(sudoku));
            }

            using (var fileStream = new FileStream(LocalFile, FileMode.Create))
                using (var stream = new StreamWriter(fileStream))
                {
                    await stream.WriteAsync(sudoku.ToString());
                }
        }
コード例 #8
0
        internal static Domain.Sudoku GenerateFull()
        {
            var sudoku = new Domain.Sudoku();

            for (var i = 0; i < Domain.Sudoku.BigSide; i++)
            {
                for (var j = 0; j < Domain.Sudoku.BigSide; j++)
                {
                    sudoku[i, j] = (i * Domain.Sudoku.SmallSide + i / Domain.Sudoku.SmallSide + j) % Domain.Sudoku.BigSide + 1;
                }
            }

            return(sudoku);
        }
コード例 #9
0
        private static List <Cell> RemoveNext(Domain.Sudoku sudoku, IList <Tuple <int, int> > notCheckedPositions, Enums.SymmetryType symmetry)
        {
            var randomPosition = Random.Next(0, notCheckedPositions.Count - 1);

            var currentCell = notCheckedPositions[randomPosition];

            notCheckedPositions.RemoveAt(randomPosition);

            var row    = currentCell.Item1;
            var column = currentCell.Item2;

            var removedValues = new List <Cell>()
            {
                new Cell(row, column, sudoku[row, column])
            };

            sudoku[row, column] = 0;

            if (symmetry == Enums.SymmetryType.Horizontal)
            {
                if (row == 4)
                {
                    return(removedValues);
                }

                var symmetricRow = Domain.Sudoku.BigSide - 1 - row;
                removedValues.Add(new Cell(symmetricRow, column, sudoku[symmetricRow, column]));
                notCheckedPositions.Remove(Tuple.Create(symmetricRow, column));

                sudoku[symmetricRow, column] = 0;
            }
            else if (symmetry == Enums.SymmetryType.Vertical)
            {
                if (column == 4)
                {
                    return(removedValues);
                }

                var symmetricColumn = Domain.Sudoku.BigSide - 1 - column;
                removedValues.Add(new Cell(row, symmetricColumn, sudoku[row, symmetricColumn]));
                notCheckedPositions.Remove(Tuple.Create(row, symmetricColumn));

                sudoku[row, symmetricColumn] = 0;
            }

            return(removedValues);
        }
コード例 #10
0
ファイル: SimpleSolver.cs プロジェクト: ilyakom/Sudoku
        /// <summary>
        /// Solve sudoku and return given number of solutions in given order
        /// </summary>
        /// <param name="sudoku"> Sudoku to solve </param>
        /// <param name="count"> Number of solutions to return </param>
        /// <param name="topType"> Sort order </param>
        /// <returns></returns>
        public List <Domain.Sudoku> GetTopNSolutions(Domain.Sudoku sudoku, int count, Enums.TopType topType)
        {
            if (sudoku == null)
            {
                throw  new ArgumentNullException(nameof(sudoku));
            }
            if (count < 0)
            {
                throw new Exception("Number of solutions can not be negative value");
            }

            ClearAndSolve(sudoku.Copy(), 0, topType, count);

            return(topType == Enums.TopType.Hardest
                                ? _solutions.Skip(Math.Max(0, _solutions.Count - count)).ToList()
                                : _solutions.ToList());
        }
コード例 #11
0
ファイル: GeneratorTest.cs プロジェクト: ilyakom/Sudoku
        private static bool CheckSudoku(Domain.Sudoku sudoku)
        {
            var vHash = new HashSet <int>();
            var hHash = new HashSet <int>();

            for (var i = 0; i < 9; i++)
            {
                for (var j = 0; j < 9; j++)
                {
                    vHash.Clear();
                    hHash.Clear();
                    for (var k = 0; k < Domain.Sudoku.BigSide; k++)
                    {
                        if (vHash.Contains(sudoku[i, k]))
                        {
                            return(false);
                        }
                        vHash.Add(sudoku[i, k]);

                        if (hHash.Contains(sudoku[k, j]))
                        {
                            return(false);
                        }
                        hHash.Add(sudoku[k, j]);
                    }

                    var rowStart    = i - i % Domain.Sudoku.SmallSide;
                    var columnStart = j - j % Domain.Sudoku.SmallSide;

                    vHash.Clear();
                    for (var m = 0; m < Domain.Sudoku.SmallSide; m++)
                    {
                        for (var k = 0; k < Domain.Sudoku.SmallSide; k++)
                        {
                            if (vHash.Contains(sudoku[rowStart + k, columnStart + m]))
                            {
                                return(false);
                            }
                            vHash.Add(sudoku[rowStart + k, columnStart + m]);
                        }
                    }
                }
            }
            return(true);
        }
コード例 #12
0
        private static bool ValidateSubSquare(Domain.Sudoku board, int colStart, int rowStart)
        {
            var set = new bool[Domain.Sudoku.BigSide + 1];

            for (var i = 0; i < Domain.Sudoku.SmallSide; i++)
            {
                for (var j = 0; j < Domain.Sudoku.SmallSide; j++)
                {
                    if (board[rowStart + i, colStart + j] != 0 && set[board[rowStart + i, colStart + j]])
                    {
                        return(false);
                    }

                    set[board[rowStart + i, colStart + j]] = true;
                }
            }

            return(true);
        }
コード例 #13
0
ファイル: SimpleSolver.cs プロジェクト: ilyakom/Sudoku
        private bool SolveBruteForce(Domain.Sudoku sudoku, int currentIndex, Enums.TopType type, int count)
        {
            while (true)
            {
                if (currentIndex == Domain.Sudoku.BigSide * Domain.Sudoku.BigSide)
                {
                    var solutionBoard = sudoku.Copy();
                    solutionBoard.DifficultyPoints = _currentIterationsCount;
                    _solutions.Add(solutionBoard);
                    return(true);
                }
                else
                {
                    var row    = currentIndex / Domain.Sudoku.BigSide;
                    var column = currentIndex % Domain.Sudoku.BigSide;

                    if (sudoku[row, column] != 0)
                    {
                        currentIndex = currentIndex + 1;
                        continue;
                    }

                    for (var i = 1; i <= Domain.Sudoku.BigSide; i++)
                    {
                        _currentIterationsCount++;
                        if (!Validations.ConsistentIfPut(sudoku, row, column, i))
                        {
                            continue;
                        }

                        sudoku[row, column] = i;
                        if (SolveBruteForce(sudoku, currentIndex + 1, type, count) &&
                            (type == Enums.TopType.Any || type == Enums.TopType.Easiest) && _solutions.Count >= count)
                        {
                            return(true);
                        }
                        sudoku[row, column] = 0;
                    }
                }

                return(false);
            }
        }
コード例 #14
0
        internal static void RunShuffle(Domain.Sudoku sudoku, int shufflesCount, CancellationToken token)
        {
            for (var i = 0; i < shufflesCount; i++)
            {
                token.ThrowIfCancellationRequested();

                var firstParam  = Random.Next(0, 2);
                var secondParam = Random.Next(0, 2);
                var thirdParam  = Random.Next(0, 2);

                // to avoid exchange between one row/column
                while (secondParam == thirdParam)
                {
                    thirdParam = Random.Next(0, 2);
                }

                var shuffleMethod = Random.Next(0, 4);

                switch (shuffleMethod)
                {
                case 0:
                    sudoku.Transpose();
                    break;

                case 1:
                    sudoku.SwapSmallRows(firstParam, secondParam, thirdParam);
                    break;

                case 2:
                    sudoku.SwapSmallColumns(firstParam, secondParam, thirdParam);
                    break;

                case 3:
                    sudoku.SwapBigRows(secondParam, thirdParam);
                    break;

                case 4:
                    sudoku.SwapBigColumns(secondParam, thirdParam);
                    break;
                }
            }
        }
コード例 #15
0
ファイル: SudokuAdapter.cs プロジェクト: ilyakom/Sudoku
        /// <summary>
        /// Import Sudoku from file
        /// </summary>
        /// <param name="path">Path to .txt file</param>
        /// <returns><see cref="Domain.Sudoku"/></returns>
        public static async Task <Domain.Sudoku> ReadFromFileAsync(string path)
        {
            if (!File.Exists(path))
            {
                return(null);
            }

            var fileInfo = new FileInfo(path);

            var sudoku = new Domain.Sudoku();

            var lineNumber = 0;

            using (var stream = new StreamReader(fileInfo.OpenRead()))
            {
                while (stream.Peek() >= 0)
                {
                    var line = await stream.ReadLineAsync();

                    if (line.Length != Domain.Sudoku.BigSide)
                    {
                        throw new Exception($"Incorrect sudoku. Line {lineNumber} has length of {line.Length}");
                    }

                    for (var column = 0; column < line.Length; column++)
                    {
                        if (int.TryParse(line[column].ToString(), out var num) && num != 0)
                        {
                            sudoku[lineNumber, column] = num;
                        }
                        else
                        {
                            sudoku[lineNumber, column] = 0;
                        }
                    }

                    lineNumber++;
                }
            }

            return(sudoku);
        }
コード例 #16
0
        private static bool ValidateRowColumn(Domain.Sudoku board, int idx)
        {
            var rowSet = new bool[Domain.Sudoku.BigSide + 1];
            var colSet = new bool[Domain.Sudoku.BigSide + 1];

            for (var i = 0; i < Domain.Sudoku.BigSide; i++)
            {
                if (board[idx, i] != 0 && rowSet[board[idx, i]])
                {
                    return(false);
                }

                if (board[i, idx] != 0 && colSet[board[i, idx]])
                {
                    return(false);
                }

                rowSet[board[idx, i]] = true;
                colSet[board[i, idx]] = true;
            }

            return(true);
        }
コード例 #17
0
        /// <summary>
        /// Validate sudoku if it's consistent
        /// </summary>
        /// <param name="board"></param>
        /// <returns></returns>
        public static bool ValidateSudoku(Domain.Sudoku board)
        {
            for (var i = 0; i < Domain.Sudoku.BigSide; i++)
            {
                if (!ValidateRowColumn(board, i))
                {
                    return(false);
                }
            }

            for (var i = 0; i < Domain.Sudoku.BigSide; i += Domain.Sudoku.SmallSide)
            {
                for (var j = 0; j < Domain.Sudoku.BigSide; j += Domain.Sudoku.SmallSide)
                {
                    if (!ValidateSubSquare(board, i, j))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }