Ejemplo n.º 1
0
        public void Apply(MutablePuzzle puzzle, RegionQueue changedRegions)
        {
            while (changedRegions.TryDequeueOfType(RegionType.Box, out int boxIndex))
            {
                var box          = puzzle.Puzzle.Boxes[boxIndex];
                var placedDigits = box.GetPlacedDigits();

                for (int digit = 1; digit <= Puzzle.LineLength; digit++)
                {
                    var value = SudokuValues.FromHumanValue(digit);

                    if (placedDigits.HasAnyOptions(value))
                    {
                        continue;
                    }

                    var rows = SudokuValues.None;
                    var cols = SudokuValues.None;

                    for (var i = 0; i < Puzzle.LineLength; i++)
                    {
                        var cellValue = box[i];
                        var cellCoord = box.GetCoordinate(i);

                        if (!cellValue.IsSingle && cellValue.HasAnyOptions(value))
                        {
                            rows = rows.AddOptions(SudokuValues.FromIndex(cellCoord.Row));
                            cols = cols.AddOptions(SudokuValues.FromIndex(cellCoord.Column));
                        }
                    }

                    if (rows.IsSingle)
                    {
                        var region     = puzzle.Puzzle.Rows[rows.ToIndex()];
                        var anyChanged = RemoveFromOtherBoxesInRegion(puzzle, region, value, boxIndex);

                        if (anyChanged)
                        {
#if DEBUG
                            Program.Debugger.AddAction($"{digit}s in {box} remove others in {region}.");
#endif
                            return;
                        }
                    }
                    if (cols.IsSingle)
                    {
                        var region     = puzzle.Puzzle.Columns[cols.ToIndex()];
                        var anyChanged = RemoveFromOtherBoxesInRegion(puzzle, region, value, boxIndex);

                        if (anyChanged)
                        {
#if DEBUG
                            Program.Debugger.AddAction($"{digit}s in {box} remove others in {region}.");
#endif
                            return;
                        }
                    }
                }
            }
        }
Ejemplo n.º 2
0
        public IndexablePosition SetValue(RegionType type, SudokuValues newValue)
        {
            var offset = GetOffset(type);
            var mask   = GetMask(offset);

            return(new IndexablePosition((_values & ~mask) | (newValue.Values << offset)));
        }
Ejemplo n.º 3
0
        public static Puzzle FromString(string puzzle)
        {
            var positions = new IndexablePosition[LineLength * LineLength];

            for (var i = 0; i < positions.Length; i++)
            {
                var value = SudokuValues.FromCharacter(puzzle[i]);
                var coord = new Coordinate(RegionType.Row, i);

                positions[coord.GlobalRowIndex]    = positions[coord.GlobalRowIndex].SetRowValue(value);
                positions[coord.GlobalColumnIndex] = positions[coord.GlobalColumnIndex].SetColumnValue(value);
                positions[coord.GlobalBoxIndex]    = positions[coord.GlobalBoxIndex].SetBoxValue(value);
            }

            return(new Puzzle(positions));
        }
Ejemplo n.º 4
0
        public Sudoku(string input)
        {
            Size = 9;
            var inputLines = input.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

            if (inputLines.Count() != Size)
            {
                throw new ArgumentException("Lines do not match size!");
            }

            var entries = inputLines
                          .Select(line => line.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries));

            if (!entries.All(e => e.Count() == Size))
            {
                throw new ArgumentException("Elements do not match size!");
            }
            var trimmedEntries = entries.Select(l => l.Select(el => el.Trim()));

            Func <Box, bool> isBoxDefault = (box) => box.Right == 0 || box.Bottom == 0;

            this.SudokuValues    = new Dictionary <Position, IValue>();
            this.BoxesByPosition = new Dictionary <Position, Box>();

            for (int row = 0; row < Size; row++)
            {
                var currentLine = trimmedEntries.ElementAt(row);
                for (int col = 0; col < Size; col++)
                {
                    var currentElement = currentLine.ElementAt(col);
                    var success        = int.TryParse(currentElement, out int parsedRes);
                    var currentValue   = new Value();
                    if (success)
                    {
                        currentValue.Solve(parsedRes);
                    }
                    var box      = Boxes.SingleOrDefault(b => b.Left <= col && b.Right >= col && b.Top <= row && b.Bottom >= row);
                    var position = new Position(row, col);
                    BoxesByPosition.Add(position, box);
                    if (isBoxDefault(box))
                    {
                        throw new ArgumentException("Could not find box!");
                    }
                    SudokuValues.Add(position, currentValue);
                }
            }
        }
Ejemplo n.º 5
0
        public void RemoveOptions(Coordinate coordinate, SudokuValues removedOptions)
        {
            var row = coordinate.GlobalRowIndex;
            var col = coordinate.GlobalColumnIndex;
            var box = coordinate.GlobalBoxIndex;

            var currentValue = _cells[row].RowValue;
            var newValue     = currentValue.RemoveOptions(removedOptions);

            _cells[row] = _cells[row].SetRowValue(newValue);
            _cells[col] = _cells[col].SetColumnValue(newValue);
            _cells[box] = _cells[box].SetBoxValue(newValue);

            _currentChangeSet.Queue.Enqueue(RegionType.Row, row / Puzzle.LineLength);
            _currentChangeSet.Queue.Enqueue(RegionType.Column, col / Puzzle.LineLength);
            _currentChangeSet.Queue.Enqueue(RegionType.Box, box / Puzzle.LineLength);
        }
Ejemplo n.º 6
0
        private void FindTuple(MutablePuzzle puzzle, RegionQueue regions, Region region, SudokuValues placedDigits)
        {
            var combinations = Helpers.GetCombinationIndices(Puzzle.LineLength, _size);

            for (int i = 0; i < combinations.Length; i++)
            {
                var comb = combinations[i];

                if (placedDigits.HasAnyOptions(comb))
                {
                    // skip any tuples that include placed digits
                    continue;
                }

                var positions = region.GetPositions(comb);

                if (positions.GetOptionCount() != _size)
                {
                    // these digits are placeable in more than tupleSize spots, so not hidden tuple
                    continue;
                }

                // we found a hidden tuple!
                var options = ArrayPool <int> .Shared.Rent(Puzzle.LineLength);

                var count      = positions.CopyIndices(options);
                var opposite   = comb.Invert();
                var anyChanged = false;

                for (var index = 0; index < count; index++)
                {
                    var cell = region[options[index]];

                    if (!cell.IsSingle && cell.HasAnyOptions(opposite))
                    {
                        var update = region.RemoveOptions(options[index], opposite);
                        puzzle.RemoveOptions(update);
                        anyChanged = true;

                        regions.Enqueue(RegionType.Row, update.Coordinate.Row);
                        regions.Enqueue(RegionType.Column, update.Coordinate.Column);
                        regions.Enqueue(RegionType.Box, update.Coordinate.Box);
                    }
                }

                ArrayPool <int> .Shared.Return(options);

                if (anyChanged)
                {
#if DEBUG
                    Program.Debugger.AddAction($"Hidden {comb} tuple in {region}");
#endif
                    return;
                }
            }
        }
Ejemplo n.º 7
0
 public CellUpdate(SudokuValues removedOptions, Coordinate coordinate)
 {
     RemovedOptions = removedOptions;
     Coordinate     = coordinate;
 }
Ejemplo n.º 8
0
        private bool RemoveFromOtherBoxesInRegion(MutablePuzzle puzzle, Region region, SudokuValues value, int boxIndex)
        {
            var anyChanged = false;

            for (int i = 0; i < Puzzle.LineLength; i++)
            {
                var coords = region.GetCoordinate(i);

                if (coords.Box == boxIndex)
                {
                    continue;
                }

                var cell = region[i];

                if (!cell.IsSingle && cell.HasAnyOptions(value))
                {
                    var update = new CellUpdate(value, coords);
                    puzzle.RemoveOptions(update);
                    anyChanged = true;
                }
            }

            return(anyChanged);
        }
Ejemplo n.º 9
0
 public IndexablePosition SetBoxValue(SudokuValues newValue)
 => new IndexablePosition((_values & ~_boxMask) | (newValue.Values << _boxOffset));
Ejemplo n.º 10
0
 public IndexablePosition SetColumnValue(SudokuValues newValue)
 => new IndexablePosition((_values & ~_colMask) | (newValue.Values << _colOffset));
Ejemplo n.º 11
0
 public IndexablePosition SetRowValue(SudokuValues newValue)
 => new IndexablePosition((_values & ~_rowMask) | (newValue.Values << _rowOffset));
Ejemplo n.º 12
0
 public IndexablePosition(SudokuValues rowValue, SudokuValues columnValue, SudokuValues boxValue)
     : this((rowValue.Values << _rowOffset) | (columnValue.Values << _colOffset) | (boxValue.Values << _boxOffset))
 {
 }
Ejemplo n.º 13
0
        private void FindTuple(MutablePuzzle puzzle, RegionQueue regions, Region region, SudokuValues placedDigits)
        {
            var combinations = Helpers.GetCombinationIndices(Puzzle.LineLength, _size);

            for (int j = 0; j < combinations.Length; j++)
            {
                var comb = combinations[j];

                if (placedDigits.HasAnyOptions(comb))
                {
                    // skip any tuples that include placed digits
                    continue;
                }

                var indices = ArrayPool <int> .Shared.Rent(_size);

                var count          = comb.CopyIndices(indices);
                var possibleValues = SudokuValues.None;

                for (int i = 0; i < count; i++)
                {
                    var cell = region[indices[i]];
                    possibleValues = possibleValues.AddOptions(cell);
                }

                ArrayPool <int> .Shared.Return(indices);

                var optionsCount = possibleValues.GetOptionCount();

                if (optionsCount == _size)
                {
                    // we found a tuple!

                    for (var i = 0; i < Puzzle.LineLength; i++)
                    {
                        var otherCell = region[i];

                        if (otherCell.IsSingle)
                        {
                            continue;
                        }

                        if (!otherCell.HasAnyOptions(possibleValues))
                        {
                            continue;
                        }

                        if (comb.HasAnyOptions(SudokuValues.FromIndex(i)))
                        {
                            continue;
                        }

                        var newCell = region.RemoveOptions(i, possibleValues);
                        puzzle.RemoveOptions(newCell);

                        regions.Enqueue(RegionType.Row, newCell.Coordinate.Row);
                        regions.Enqueue(RegionType.Column, newCell.Coordinate.Column);
                        regions.Enqueue(RegionType.Box, newCell.Coordinate.Box);
#if DEBUG
                        Program.Debugger.AddAction($"{possibleValues} tuple in {region}.");
#endif
                    }
                }
            }
        }