예제 #1
0
        public static void Main(string [] args)
        {
            var numerBoardTokenizer = new NumberBoardTokenizer();

            using (var streamReader = new StreamReader(new FileStream("./question.txt", FileMode.Open)))
            {
                using (var streamWriter = new StreamWriter(new FileStream("./answer.txt", FileMode.OpenOrCreate)))
                {
                    var lines = streamReader.ReadToEnd().Split(new[] { Environment.NewLine },
                                                               StringSplitOptions.RemoveEmptyEntries);
                    for (var index = 0; index < lines.Length; index += 10)
                    {
                        var header = lines[index];
                        Console.WriteLine(header);
                        streamWriter.WriteLine(header);
                        var generate    = numerBoardTokenizer.Generate(string.Join("", lines, index + 1, 9));
                        var sudokuBoard = new SudokuBoard();
                        sudokuBoard.Make(generate);
                        streamWriter.WriteLine(sudokuBoard.Answer);
                        sudokuBoard.Solve();
                        streamWriter.WriteLine(sudokuBoard.Answer);
                    }
                }
            }
        }
예제 #2
0
        static void Main(string[] args)
        {
            //Set test Sudoku field
            var sudokuBoard = new SudokuBoard();

            SetTest(sudokuBoard);
            sudokuBoard.Print();

            //Solve
            sudokuBoard.Solve();
            sudokuBoard.Print();
        }
예제 #3
0
        private static void CompleteSolve(SudokuBoard board)
        {
            Console.WriteLine("Board:");
            Output(board);
            List <SudokuBoard> solutions = board.Solve().ToList();

            Console.WriteLine($"All {solutions.Count} solutions:");
            int i = 1;

            foreach (SudokuBoard solution in solutions)
            {
                Console.WriteLine("----------------");
                Console.WriteLine($"Solution {i++} / {solutions.Count}:");
                Output(solution);
            }
        }
예제 #4
0
        public Bitmap SolveSudokuPhoto(Bitmap sudokuPhoto)
        {
            Bitmap transformedImage = ImageTransformation.TranformImage(sudokuPhoto);
            //transformedImage.Save(@"D:\k\trash\transformedImage.jpg");

            Bitmap thresholdedImage = ImageTransformation.PerformThresholding(transformedImage);
            //thresholdedImage.Save(@"D:\k\trash\thresholdedImage.jpg");


            //todo del
            //ImageTransformation.Test(transformedImage).Save(@"D:\k\trash\abc.jpg");


            //TODO: Threshold will probably be needed for noisy images
            //var thresholdFilter = new Threshold(100);
            //thresholdFilter.ApplyInPlace(image);
            var invertFilter  = new Invert();
            var invertedImage = invertFilter.Apply(thresholdedImage);

            //invertedImage.Save(@"D:\k\trash\invertedInput.jpg");


            var blobCounter = new BlobCounter
            {
                BackgroundThreshold = Color.FromArgb(255, 70, 70, 70)
            };

            blobCounter.ProcessImage(invertedImage);

            var invertedImageBlobs        = blobCounter.GetObjectsInformation();
            var boardBlobCandidates       = invertedImageBlobs;
            var biggestBoardBlobCandidate = boardBlobCandidates.OrderByDescending(b => b.Area).First();
            var boardBlob = biggestBoardBlobCandidate;

            var expectedCellBlobHeight = boardBlob.Rectangle.Height /
                                         SudokuBoard.NumberOfBoardCellsInSingleDirection;

            var expectedCellBlobWidth = boardBlob.Rectangle.Width /
                                        SudokuBoard.NumberOfBoardCellsInSingleDirection;

            var blobCellSizeTolerance = 0.25;

            blobCounter.ProcessImage(thresholdedImage);

            //todo
            thresholdedImage = transformedImage;

            var cellBlobCandidates = blobCounter.GetObjectsInformation();

            var cellBlobs = cellBlobCandidates.Where(
                b =>
                boardBlob.Rectangle.Contains(b.Rectangle) &&
                IsMatch(b.Rectangle.Width, expectedCellBlobWidth, blobCellSizeTolerance) &&
                IsMatch(b.Rectangle.Height, expectedCellBlobHeight, blobCellSizeTolerance)).ToArray();

            if (cellBlobs.Length != SudokuBoard.NumberOfBoardCells)
            {
                throw new InvalidOperationException();
            }

            var expectedCellsData =
                Enumerable.Range(0, SudokuBoard.NumberOfBoardCellsInSingleDirection)
                .SelectMany(
                    cvi =>
                    Enumerable.Range(0, SudokuBoard.NumberOfBoardCellsInSingleDirection)
                    .Select(chi => new
            {
                CellHorizontalIndex = chi,
                CellVerticalIndex   = cvi,
                ExpectedCellCenter  =
                    new Point((int)(boardBlob.Rectangle.X + (cvi + 0.5) * expectedCellBlobWidth),
                              boardBlob.Rectangle.Y + (int)((chi + 0.5) * expectedCellBlobHeight)),
            })).ToArray();

            var sudokuBoard = new SudokuBoard();
            var digitImages = new List <Bitmap>();
            var parsedDigitIndexToCellBlobMap = new Dictionary <int, Blob>();
            var lastParsedDigitIndex          = 0;

            foreach (var cellBlob in cellBlobs)
            {
                // TODO: There may be more than one blob candidate
                var digitBlob = invertedImageBlobs.SingleOrDefault(b => cellBlob.Rectangle.Contains(b.Rectangle));

                if (digitBlob == null)
                {
                    continue;
                }

                var digitImage = thresholdedImage.Clone(digitBlob.Rectangle, thresholdedImage.PixelFormat);
                digitImages.Add(digitImage);
                parsedDigitIndexToCellBlobMap[lastParsedDigitIndex++] = cellBlob;
            }

            IReadOnlyCollection <int> parsedDigits;

            using (var digitParser = new DigitParser())
            {
                parsedDigits = digitParser.ParseDigits(digitImages);
            }

            foreach (var digitImage in digitImages)
            {
                digitImage.Dispose();
            }

            for (var parsedDigitIndex = 0; parsedDigitIndex < parsedDigits.Count; parsedDigitIndex++)
            {
                var digitCellBlob = parsedDigitIndexToCellBlobMap[parsedDigitIndex];

                var expectedCellData =
                    expectedCellsData.Single(d => digitCellBlob.Rectangle.Contains(d.ExpectedCellCenter));

                var parsedDigit = parsedDigits.ElementAt(parsedDigitIndex);

                if (!SudokuBoard.ValidNumbers.Contains(parsedDigit))
                {
                    throw new InvalidOperationException();
                }

                sudokuBoard[expectedCellData.CellHorizontalIndex, expectedCellData.CellVerticalIndex] =
                    parsedDigit;
            }

            var solvedBoard = sudokuBoard.Solve();

            if (solvedBoard == null)
            {
                return(null);
            }

            Debug.Assert(solvedBoard.IsComplete() && solvedBoard.IsValid());

            var cellsToPrint = Enumerable.Range(0, SudokuBoard.NumberOfBoardCellsInSingleDirection)
                               .SelectMany(
                vi =>
                Enumerable.Range(0, SudokuBoard.NumberOfBoardCellsInSingleDirection)
                .Select(hi => new
            {
                HorizontalIndex = hi,
                VerticalIndex   = vi
            })).Where(c => sudokuBoard[c.HorizontalIndex, c.VerticalIndex] == null).Select(
                i =>
            {
                var expectedCellData =
                    expectedCellsData.Single(
                        d =>
                        d.CellHorizontalIndex == i.HorizontalIndex &&
                        d.CellVerticalIndex == i.VerticalIndex);

                var cellBlob =
                    cellBlobs.Single(
                        b => b.Rectangle.Contains(expectedCellData.ExpectedCellCenter));

                var cellCenter = new Point(cellBlob.Rectangle.X + cellBlob.Rectangle.Width / 2,
                                           cellBlob.Rectangle.Y + cellBlob.Rectangle.Height / 2);
                return(new Cell(i.HorizontalIndex, i.VerticalIndex, cellBlob.Rectangle));
            }).ToList();

            var solutionPhoto = PrintSolutionToSourceImage(thresholdedImage, cellsToPrint, solvedBoard);

            return(solutionPhoto);
        }
예제 #5
0
        public IEnumerable <SudokuBoard> Solve()
        {
            SudokuProgress Simplify()
            {
                bool valid = _rules.All(rule => rule.CheckValid());

                if (!valid)
                {
                    return(SudokuProgress.FAILED);
                }

                return(_rules.Aggregate(SudokuProgress.NO_PROGRESS,
                                        (progress, rule) => SudokuTile.CombineSolvedState(progress, rule.Solve())));
            }

            // reset solution
            foreach (SudokuTile tile in _tiles)
            {
                tile.ResetPossibles();
            }

            SudokuProgress simplify = SudokuProgress.PROGRESS;

            while (simplify == SudokuProgress.PROGRESS)
            {
                simplify = Simplify();
            }

            if (simplify == SudokuProgress.FAILED)
            {
                yield break;
            }

            // Find one of the values with the least number of alternatives, but that still has at least 2 alternatives
            IEnumerable <SudokuTile> query = from rule in _rules
                                             from tile in rule
                                             where tile.PossibleCount > 1
                                             orderby tile.PossibleCount ascending
                                             select tile;

            SudokuTile chosen = query.FirstOrDefault();

            if (chosen == null)
            {
                // The board has been completed, we're done!
                yield return(this);

                yield break;
            }

            foreach (int value in Enumerable.Range(1, _maxValue))
            {
                // Iterate through all the valid possibles on the chosen square and pick a number for it
                if (!chosen.IsValuePossible(value))
                {
                    continue;
                }
                SudokuBoard copy = new SudokuBoard(this);
                copy[chosen.X, chosen.Y].Fix(value, "Trial and error");
                foreach (SudokuBoard innerSolution in copy.Solve())
                {
                    yield return(innerSolution);
                }
            }
            yield break;
        }