Beispiel #1
0
        private static void FindCandidatesPairsInCells(SolvingContext context, ICellGroup cellGroup)
        {
            var allNumbers             = GetAllSudokuNumbers();
            var unassignedValues       = allNumbers.Except(cellGroup.Select(x => x.Value)).ToList();
            var allNumbersCombinations = unassignedValues
                                         .SelectMany(x => unassignedValues, Tuple.Create)
                                         .Where(tuple => tuple.Item1 != tuple.Item2)
                                         .ToList();

            foreach (var combination in allNumbersCombinations)
            {
                var first           = combination.Item1;
                var firstValueCells = cellGroup.Where(x => x.CanPutCandidate(first)).ToList();

                var second           = combination.Item2;
                var secondValueCells = cellGroup.Where(x => x.CanPutCandidate(second)).ToList();

                if (firstValueCells.Count != 2 || secondValueCells.Count != 2 ||
                    !firstValueCells.SequenceEqual(secondValueCells))
                {
                    continue;
                }

                foreach (var cell in firstValueCells)
                {
                    context.CellsAffectedWithCrossOut += cell.RemoveCandidatesExcept(combination.ToArray());
                }

                RemoveCandidates(context, cellGroup, Tuple.Create(firstValueCells.First(), firstValueCells.Last()));
            }
        }
Beispiel #2
0
        private static void SearchForSingleInGroup(SolvingContext context, ICellGroup group)
        {
            var allNumbers = Enumerable.Range(1, 9)
                             .Select(x => (short)x)
                             .Except(group.Select(x => x.Value).Distinct())
                             .ToList();

            var singles = allNumbers.Select(x => new
            {
                Value = x,
                ElligibleCellsCount = group.Count(y => y.CanPutCandidate(x))
            })
                          .Where(x => x.ElligibleCellsCount == 1)
                          .Select(x => x.Value)
                          .ToList();

            var single = singles.FirstOrDefault();

            if (single == 0)
            {
                return;
            }

            var targetCell = group.FirstOrDefault(x => x.CanPutCandidate(single));

            if (targetCell == null)
            {
                return;
            }
            var newCell = new Cell(single, targetCell.X, targetCell.Y);

            context.Grid = context.Grid.UpdateCell(newCell);
            context.FilledInCellsCount++;
            context.GoToLoopStart = true;
        }
Beispiel #3
0
        private static void SearchForPairsInSquareRows(SolvingContext context, short[] allSquareIndices)
        {
            foreach (var rowIndex in Enumerable.Range(0, Consts.SudokuSquareSideSize))
            {
                var squaresInRow  = context.Grid.GetSquaresInRow(rowIndex).ToList();
                var sudokuNumbers = GetAllSudokuNumbers();

                foreach (var number in sudokuNumbers)
                {
                    var availableColumns = squaresInRow
                                           .Select((x, i) => new NumberInRow
                    {
                        Value = number,
                        Rows  =
                            x.Where(c => c.CanPutCandidate(number))
                            .Select(c => c.Y)
                            .Distinct()
                            .OrderBy(r => r)
                            .ToList(),
                        ColumnIndex = (short)i
                    })
                                           .Where(x => x.Rows.Count == 2)
                                           .ToList();

                    if (availableColumns.Count < 2)
                    {
                        continue;
                    }

                    var pairs = availableColumns.SelectMany(x => availableColumns, Tuple.Create)
                                .Where(x => x.Item1.Value == x.Item2.Value)
                                .Where(x => x.Item1.ColumnIndex != x.Item2.ColumnIndex)
                                .ToList();

                    foreach (var pair in pairs)
                    {
                        if (!pair.Item1.Rows.SequenceEqual(pair.Item2.Rows))
                        {
                            continue;
                        }

                        var remainingSquareIndex = allSquareIndices
                                                   .Except(pair.ToList().Select(x => x.ColumnIndex))
                                                   .Single();

                        var remainingSquare         = squaresInRow[remainingSquareIndex];
                        var cellsToRemoveCandidates = remainingSquare.Where(x => pair.Item1.Rows.Contains(x.Y))
                                                      .ToList();

                        foreach (var cell in cellsToRemoveCandidates)
                        {
                            context.CellsAffectedWithCrossOut += cell.RemoveCandidates(pair.Item1.Value);
                        }
                    }
                }
            }
        }
Beispiel #4
0
 private static SolvingResult ToSolvingResult(SolvingContext context)
 {
     return(new SolvingResult
     {
         IsSuccess = context.IsSuccess,
         SudokuGrid = context.Grid,
         FilledInCellsCount = context.FilledInCellsCount
     });
 }
Beispiel #5
0
        private static SolvingContext CreateContext(IGrid baseGrid)
        {
            var context = new SolvingContext
            {
                Grid = baseGrid
            };

            ResetContext(context);
            return(context);
        }
Beispiel #6
0
        public static void SearchForPairsInRows(SolvingContext context)
        {
            foreach (var rowIndex in Enumerable.Range(0, Consts.SudokuGridSize))
            {
                var row          = context.Grid.GetRow(rowIndex);
                var combinations = GetValidPairsCombinations(row);
                var pairs        = HandleCellPairs(context, combinations, row).ToList();

                FindCandidatesPairsInCells(context, row);
            }
        }
Beispiel #7
0
        private static void SearchForPairsInColumns(SolvingContext context)
        {
            foreach (var columnIndex in Enumerable.Range(0, Consts.SudokuGridSize))
            {
                var column       = context.Grid.GetColumn(columnIndex);
                var combinations = GetValidPairsCombinations(column);
                var pairs        = HandleCellPairs(context, combinations, column).ToList();

                FindCandidatesPairsInCells(context, column);
            }
        }
Beispiel #8
0
 private static void ResetContext(SolvingContext context)
 {
     context.CellsAffectedWithCrossOut = 0;
     context.HasEmptyCells             = context.Grid.HasEmptyCells();
     context.GoToLoopStart             = false;
     context.Pairs = new List <Tuple <short, short> >();
     if (!context.HasEmptyCells)
     {
         context.ContinueSolving = false;
     }
 }
Beispiel #9
0
        private static void RemoveCandidates(SolvingContext context, ICellGroup cellGroup,
                                             Tuple <ICell, ICell> pair)
        {
            var otherCells  = cellGroup.Except(pair.ToList()).ToList();
            var firstFields = pair.Item1.GetCandidates().ToList();

            context.Pairs.Add(Tuple.Create(firstFields.First(), firstFields.Last()));
            context.PairFound = true;
            foreach (var otherCell in otherCells)
            {
                context.CellsAffectedWithCrossOut += otherCell.RemoveCandidates(firstFields.ToArray());
            }
        }
Beispiel #10
0
        private static void SearchForSinglesInContainers(SolvingContext context)
        {
            SearchSingleNumbersInSquares(context);

            foreach (var column in context.Grid.GetColumns())
            {
                SearchForSingleInGroup(context, column);
            }

            foreach (var row in context.Grid.GetRows())
            {
                SearchForSingleInGroup(context, row);
            }
        }
        public void SearchForPairsInSquare_SpecificCase_ShouldFindPair()
        {
            var grid = SudokuGrids.SpecificCaseForPairInSquare;

            var context = new SolvingContext
            {
                ContinueSolving = true,
                Grid            = grid
            };

            SolverService.SearchForPairsInSquares(context);

            Assert.True(context.PairFound);
        }
Beispiel #12
0
        public static void SearchSingleNumbersInSquares(SolvingContext context)
        {
            foreach (var square in context.Grid.GetSquares())
            {
                SearchForSingleInGroup(context, square);

                var notFilledInNumbers = Enumerable.Range(1, 9)
                                         .Select(x => (short)x)
                                         .Except(square.Select(x => x.Value).Distinct())
                                         .ToList();

                foreach (var number in notFilledInNumbers)
                {
                    var elligibleCells = square.Where(x => x.CanPutCandidate(number)).ToList();

                    if (elligibleCells.Count != 2)
                    {
                        continue;
                    }

                    var first  = elligibleCells.First();
                    var second = elligibleCells.Last();

                    if (first.X == second.X)
                    {
                        var column    = context.Grid.GetColumn(first.X);
                        var pairGroup = new List <ICell> {
                            first, second
                        };
                        var otherCells   = column.Except(pairGroup).ToList();
                        var updatedCells = otherCells.Aggregate(0, (a, b) => a + (b.RemoveCandidate(number) ? 1 : 0));
                        context.CellsAffectedWithCrossOut += updatedCells;
                    }

                    if (first.Y == second.Y)
                    {
                        var row       = context.Grid.GetRow(first.Y);
                        var pairGroup = new List <ICell> {
                            first, second
                        };
                        var otherCells   = row.Except(pairGroup).ToList();
                        var updatedCells = otherCells.Aggregate(0, (a, b) => a + (b.RemoveCandidate(number) ? 1 : 0));
                        context.CellsAffectedWithCrossOut += updatedCells;
                    }
                }
            }
        }
Beispiel #13
0
        public static void SearchForPairsInSquareColumns(SolvingContext context, short[] allSquareIndices)
        {
            foreach (var columnIndex in Enumerable.Range(0, Consts.SudokuSquareSideSize))
            {
                var squaresInColumn = context.Grid.GetSquaresInColumn(columnIndex).ToList();
                var sudokuNumbers   = GetAllSudokuNumbers();

                foreach (var number in sudokuNumbers)
                {
                    var availableColumns = squaresInColumn
                                           .Select((x, i) => ToNumberInColumn(number, x, i))
                                           .Where(x => x.Columns.Count == 2)
                                           .ToList();

                    if (availableColumns.Count < 2)
                    {
                        continue;
                    }

                    var pairs = availableColumns.SelectMany(x => availableColumns, Tuple.Create)
                                .Where(x => x.Item1.Value == x.Item2.Value)
                                .Where(x => x.Item1.RowIndex != x.Item2.RowIndex)
                                .ToList();

                    foreach (var pair in pairs)
                    {
                        if (!pair.Item1.Columns.SequenceEqual(pair.Item2.Columns))
                        {
                            continue;
                        }

                        var remainingSquareIndex = allSquareIndices
                                                   .Except(pair.ToList().Select(x => x.RowIndex))
                                                   .Single();

                        var remainingSquare         = squaresInColumn[remainingSquareIndex];
                        var cellsToRemoveCandidates = remainingSquare.Where(x => pair.Item1.Columns.Contains(x.X))
                                                      .ToList();

                        foreach (var cell in cellsToRemoveCandidates)
                        {
                            context.CellsAffectedWithCrossOut += cell.RemoveCandidates(pair.Item1.Value);
                        }
                    }
                }
            }
        }
        public void SearchSingleNumbersInSquares_SpecificCase_ShouldCrossOut2InFourthRow()
        {
            var grid = SudokuGrids.SpecificCaseForPairInSquare;

            var context = new SolvingContext
            {
                ContinueSolving = true,
                Grid            = grid
            };

            SolverService.SearchSingleNumbersInSquares(context);
            var updatedGrid = context.Grid;
            var row         = updatedGrid.GetRow(3);
            var eigthCell   = row.GetCell(7);
            var ninthCell   = row.GetCell(8);

            Assert.False(eigthCell.CanPutCandidate(2));
            Assert.False(ninthCell.CanPutCandidate(2));
        }
        public void SearchForPairsInSquareColumns_ForPartaillySolvedHardGridThree_ShouldRemovesTwosInFirstSquare()
        {
            var grid = SudokuGrids.HardGridThreePartiallySolved;

            var context = new SolvingContext
            {
                ContinueSolving = true,
                Grid            = grid
            };

            var allSquareIndices = new short[] { 0, 1, 2 };

            SolverService.SearchForPairsInSquareColumns(context, allSquareIndices);
            var updatedGrid = context.Grid;

            var firstRow  = updatedGrid.GetRow(0);
            var firstCell = firstRow.GetCell(0);

            Assert.False(firstCell.CanPutCandidate(2));
        }
Beispiel #16
0
        public static void SearchForPairsInSquares(SolvingContext context)
        {
            foreach (var rowIndex in Enumerable.Range(0, Consts.SudokuSquareSideSize))
            {
                foreach (var columnIndex in Enumerable.Range(0, Consts.SudokuSquareSideSize))
                {
                    var square       = context.Grid.GetSquare(columnIndex, rowIndex);
                    var combinations = GetValidPairsCombinations(square);
                    var pairs        = HandleCellPairs(context, combinations, square).ToList();

                    ApplyPairsToRowsAndColumns(context, pairs);

                    FindCandidatesPairsInCells(context, square);
                }
            }

            var allSquareIndices = new short[] { 0, 1, 2 };

            SearchForPairsInSquareRows(context, allSquareIndices);
            SearchForPairsInSquareColumns(context, allSquareIndices);
        }
Beispiel #17
0
        private static void ApplyPairsToRowsAndColumns(SolvingContext context, IEnumerable <Tuple <ICell, ICell> > pairs)
        {
            foreach (var pair in pairs)
            {
                if (pair.Item1.X == pair.Item2.X)
                {
                    var colIndex = pair.Item1.X;
                    var column   = context.Grid.GetColumn(colIndex);

                    RemoveCandidates(context, column, pair);
                }

                if (pair.Item1.Y == pair.Item2.Y)
                {
                    var rowIdx = pair.Item2.Y;
                    var row    = context.Grid.GetRow(rowIdx);

                    RemoveCandidates(context, row, pair);
                }
            }
        }
Beispiel #18
0
        private static bool SearchForPairs(SolvingContext context)
        {
            context.TargetCell = context.Grid.GetCellWithLeastAvailableValues();

            if (context.TargetCell == null || context.TargetCell.GetCandidates().Count <= 1)
            {
                return(false);
            }

            SearchForPairsInRows(context);
            SearchForPairsInColumns(context);
            SearchForPairsInSquares(context);

            if (context.PairFound && context.CellsAffectedWithCrossOut > 0)
            {
                return(true);
            }

            context.IsSuccess       = false;
            context.ContinueSolving = false;
            return(true);
        }
Beispiel #19
0
        private static IEnumerable <Tuple <ICell, ICell> > HandleCellPairs(SolvingContext context,
                                                                           IEnumerable <Tuple <ICell, ICell> > combinations, ICellGroup cellGroup)
        {
            foreach (var combination in combinations)
            {
                if (combination.Item1 == null || combination.Item2 == null)
                {
                    break;
                }

                var firstFields  = combination.Item1.GetCandidates().ToList();
                var secondFields = combination.Item2.GetCandidates().ToList();
                if (firstFields.Count != 2 || secondFields.Count != 2 ||
                    !firstFields.SequenceEqual(secondFields))
                {
                    continue;
                }

                RemoveCandidates(context, cellGroup, combination);

                yield return(combination);
            }
        }