Ejemplo n.º 1
0
        internal SudokuProgress CheckForOnlyOnePossibility()
        {
            // Check if there is only one number within this rule that can have a specific value
            IList <int>    existingNumbers = _tiles.Select(tile => tile.Value).Distinct().ToList();
            SudokuProgress result          = SudokuProgress.NO_PROGRESS;

            foreach (int value in Enumerable.Range(1, _tiles.Count))
            {
                if (existingNumbers.Contains(value)) // this rule already has the value, skip checking for it
                {
                    continue;
                }
                var possibles = _tiles.Where(tile => !tile.HasValue && tile.IsPossibleValue(value)).ToList();
                if (possibles.Count == 0)
                {
                    return(SudokuProgress.FAILED);
                }
                if (possibles.Count == 1)
                {
                    possibles.First().Fix(value, "Only possible in rule " + ToString());
                    result = SudokuProgress.PROGRESS;
                }
            }
            return(result);
        }
Ejemplo n.º 2
0
        internal SudokuProgress Solve()
        {
            // If both are null, return null (indicating no change). If one is null, return the other. Else return result1 && result2
            SudokuProgress result1 = RemovePossibles();
            SudokuProgress result2 = CheckForOnlyOnePossibility();

            return(SudokuTile.CombineSolvedState(result1, result2));
        }
Ejemplo n.º 3
0
        public IEnumerable <SudokuBoard> Solve()
        {
            ResetSolutions();
            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
            var 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;
            }

            Console.WriteLine("SudokuTile: " + chosen.ToString());

            foreach (var 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;
                }
                var copy = new SudokuBoard(this);
                copy.Tile(chosen.X, chosen.Y).Fix(value, "Trial and error");
                foreach (var innerSolution in copy.Solve())
                {
                    yield return(innerSolution);
                }
            }
            yield break;
        }
Ejemplo n.º 4
0
        internal static SudokuProgress CombineSolvedState(SudokuProgress a, SudokuProgress b)
        {
            switch (a)
            {
            case SudokuProgress.FAILED:
                return(a);

            case SudokuProgress.NO_PROGRESS:
                return(b);

            case SudokuProgress.PROGRESS:
                return(b == SudokuProgress.FAILED ? b : a);
            }
            throw new InvalidOperationException($"Invalid value for {nameof(a)}");
        }
Ejemplo n.º 5
0
 internal static SudokuProgress CombineSolvedState(SudokuProgress a, SudokuProgress b)
 {
     if (a == SudokuProgress.FAILED)
     {
         return(a);
     }
     if (a == SudokuProgress.NO_PROGRESS)
     {
         return(b);
     }
     if (a == SudokuProgress.PROGRESS)
     {
         return(b == SudokuProgress.FAILED ? b : a);
     }
     throw new InvalidOperationException("Invalid value for a");
 }
Ejemplo n.º 6
0
        internal SudokuProgress Simplify()
        {
            SudokuProgress result = SudokuProgress.NO_PROGRESS;
            bool           valid  = CheckValid();

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

            foreach (SudokuRule rule in rules)
            {
                result = SudokuTile.CombineSolvedState(result, rule.Solve());
            }

            return(result);
        }
Ejemplo n.º 7
0
        internal SudokuProgress RemovePossibles()
        {
            // Tiles that have numbers already
            IEnumerable <SudokuTile> withNumber = _tiles.Where(tile => tile.HasValue);

            // Tiles without a number
            IEnumerable <SudokuTile> withoutNumber = _tiles.Where(tile => !tile.HasValue);

            // The existing numbers in this rule
            IEnumerable <int> existingNumbers = new HashSet <int>(withNumber.Select(tile => tile.Value).Distinct().ToList());

            SudokuProgress result = SudokuProgress.NO_PROGRESS;

            foreach (SudokuTile tile in withoutNumber)
            {
                result = SudokuTile.CombineSolvedState(result, tile.RemovePossibles(existingNumbers));
            }
            return(result);
        }
Ejemplo n.º 8
0
        internal SudokuProgress RemovePossibles(IEnumerable <int> existingNumbers)
        {
            if (_blocked)
            {
                return(SudokuProgress.NO_PROGRESS);
            }
            // Takes the current possible values and removes the ones existing in `existingNumbers`
            possibleValues = new HashSet <int>(possibleValues.Where(x => !existingNumbers.Contains(x)));
            SudokuProgress result = SudokuProgress.NO_PROGRESS;

            if (possibleValues.Count == 1)
            {
                Fix(possibleValues.First(), "Only one possibility");
                result = SudokuProgress.PROGRESS;
            }
            if (possibleValues.Count == 0)
            {
                return(SudokuProgress.FAILED);
            }
            return(result);
        }
Ejemplo n.º 9
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;
        }
Ejemplo n.º 10
0
 internal static SudokuProgress CombineSolvedState(SudokuProgress a, SudokuProgress b)
 {
     if (a == SudokuProgress.FAILED)
         return a;
     if (a == SudokuProgress.NO_PROGRESS)
         return b;
     if (a == SudokuProgress.PROGRESS)
         return b == SudokuProgress.FAILED ? b : a;
     throw new InvalidOperationException("Invalid value for a");
 }