Skip to content

Module sudoku.strategies

None

None

View Source
from .hidden_subset import HiddenSingle, HiddenSubset, PinnedDigit

from .naked_subset import ForcedDigit, NakedDouble, NakedQuad, NakedSingle, NakedSubset, NakedTriple

from .refresh_candidates import RefreshCandidates

from .strategy import Strategy

__all__ = (

    "Strategy",

    "RefreshCandidates",

    "HiddenSubset",

    "HiddenSingle",

    "PinnedDigit",

    "ForcedDigit",

    "NakedDouble",

    "NakedQuad",

    "NakedSingle",

    "NakedSubset",

    "NakedTriple",

)

Sub-modules

Classes

ForcedDigit

1
2
3
class ForcedDigit(

)
View Source
class ForcedDigit(NakedSingle):

    """

    Alias for the [[NakedSingle]] strategy

    """

Ancestors (in MRO)

  • sudoku.strategies.NakedSingle
  • sudoku.strategies.NakedSubset
  • sudoku.strategies.Strategy

Class variables

1
difficulty
1
name

Instance variables

1
difficulty
1
name
1
size

HiddenSingle

1
2
3
class HiddenSingle(

)
View Source
class HiddenSingle(HiddenSubset):

    """

    The [Hidden Single](http://sudopedia.enjoysudoku.com/Hidden_Single.html) strategy

    """

    def __init__(self):

        super().__init__(1)

Ancestors (in MRO)

  • sudoku.strategies.HiddenSubset
  • sudoku.strategies.Strategy

Descendants

  • sudoku.strategies.PinnedDigit

Class variables

1
difficulty
1
name

Instance variables

1
difficulty
1
name
1
size

HiddenSubset

1
2
3
class HiddenSubset(
    size
)
View Source
class HiddenSubset(Strategy):

    """

    Apply the [Hidden Subset](http://sudopedia.enjoysudoku.com/Hidden_Subset.html) strategy

    """

    __slots__ = ("size",)

    size: int

    def __init__(self, size):

        super().__init__(difficulty=0.163 * size)

        self.name += f" - {size}"

        self.size = size

    def __call__(self, puzzle: Puzzle[T]) -> int:

        if self.size <= 0 or self.size >= puzzle.order:

            return 0

        complement_size = puzzle.order - self.size

        if complement_size < self.size:

            from .naked_subset import NakedSubset

            return NakedSubset(complement_size)(puzzle)

        candidate_eliminations = 0

        for b, blank in puzzle._blank():

            if len(blank.candidates) >= self.size:

                for house in [puzzle._row, puzzle._col, puzzle._box]:

                    for hidden_candidates in itertools.combinations(blank.candidates, self.size):

                        subset = set(

                            p for p, peer in house(b) if (any((hc in peer.candidates) for hc in hidden_candidates))

                        )

                        subset.add(b)

                        if len(subset) == self.size:

                            for s in subset:

                                before_size = len(puzzle.cells[s].candidates)

                                puzzle.cells[s].candidates = set(hidden_candidates)

                                after_size = len(puzzle.cells[s].candidates)

                                candidate_eliminations += before_size - after_size

        return candidate_eliminations

Ancestors (in MRO)

  • sudoku.strategies.Strategy

Descendants

  • sudoku.strategies.HiddenSingle

Class variables

1
difficulty
1
name

Instance variables

1
difficulty
1
name
1
size

NakedDouble

1
2
3
class NakedDouble(

)
View Source
class NakedDouble(NakedSubset):

    """

    Apply the [Naked Double](http://sudopedia.enjoysudoku.com/Naked_Double.html) strategy

    """

    def __init__(self):

        super().__init__(2)

Ancestors (in MRO)

  • sudoku.strategies.NakedSubset
  • sudoku.strategies.Strategy

Class variables

1
difficulty
1
name

Instance variables

1
difficulty
1
name
1
size

NakedQuad

1
2
3
class NakedQuad(

)
View Source
class NakedQuad(NakedSubset):

    """

    Apply the [Naked Quad](http://sudopedia.enjoysudoku.com/Naked_Quad.html) strategy

    """

    def __init__(self):

        super().__init__(4)

Ancestors (in MRO)

  • sudoku.strategies.NakedSubset
  • sudoku.strategies.Strategy

Class variables

1
difficulty
1
name

Instance variables

1
difficulty
1
name
1
size

NakedSingle

1
2
3
class NakedSingle(

)
View Source
class NakedSingle(NakedSubset):

    """

    The [Naked Single](http://sudopedia.enjoysudoku.com/Naked_Single.html) strategy

    """

    def __init__(self):

        super().__init__(1)

Ancestors (in MRO)

  • sudoku.strategies.NakedSubset
  • sudoku.strategies.Strategy

Descendants

  • sudoku.strategies.ForcedDigit
  • sudoku.strategies.naked_subset.SoleCandidate

Class variables

1
difficulty
1
name

Instance variables

1
difficulty
1
name
1
size

NakedSubset

1
2
3
class NakedSubset(
    size: 'int'
)
View Source
class NakedSubset(Strategy):

    """

    Apply the [Naked Subset](http://sudopedia.enjoysudoku.com/Naked_Subset.html) strategy

    """

    __slots__ = ("size",)

    def __init__(self, size: int):

        super().__init__(difficulty=0.323 * size)

        self.name += f" - {size}"

        self.size = size

    def __call__(self, puzzle: Puzzle[T]) -> int:

        if self.size <= 0 or self.size >= puzzle.order:

            return 0

        complement_size = puzzle.order - self.size

        if complement_size < self.size:

            from .hidden_subset import HiddenSubset

            return HiddenSubset(complement_size)(puzzle)

        candidate_eliminations = 0

        for b, blank in puzzle._blank():

            if len(blank.candidates) == self.size:

                for house in [puzzle._row, puzzle._col, puzzle._box]:

                    complement = set(

                        p

                        for p, peer in house(b)

                        if (

                            len(peer.candidates) > self.size

                            or any((pc not in blank.candidates) for pc in peer.candidates)

                        )

                    )

                    if len(complement) == complement_size:

                        for p in complement:

                            for c in blank.candidates:

                                if c in puzzle.cells[p].candidates:

                                    puzzle.cells[p].candidates.remove(c)

                                    candidate_eliminations += 1

        return candidate_eliminations

Ancestors (in MRO)

  • sudoku.strategies.Strategy

Descendants

  • sudoku.strategies.NakedSingle
  • sudoku.strategies.NakedDouble
  • sudoku.strategies.NakedTriple
  • sudoku.strategies.NakedQuad

Class variables

1
difficulty
1
name

Instance variables

1
difficulty
1
name
1
size

NakedTriple

1
2
3
class NakedTriple(

)
View Source
class NakedTriple(NakedSubset):

    """

    Apply the [Naked Triple](http://sudopedia.enjoysudoku.com/Naked_Triple.html) strategy

    """

    def __init__(self):

        super().__init__(3)

Ancestors (in MRO)

  • sudoku.strategies.NakedSubset
  • sudoku.strategies.Strategy

Class variables

1
difficulty
1
name

Instance variables

1
difficulty
1
name
1
size

PinnedDigit

1
2
3
class PinnedDigit(

)
View Source
class PinnedDigit(HiddenSingle):

    """

    Alias for the [[HiddenSingle]] strategy

    """

Ancestors (in MRO)

  • sudoku.strategies.HiddenSingle
  • sudoku.strategies.HiddenSubset
  • sudoku.strategies.Strategy

Class variables

1
difficulty
1
name

Instance variables

1
difficulty
1
name
1
size

RefreshCandidates

1
2
3
class RefreshCandidates(

)
View Source
class RefreshCandidates(Strategy):

    """

    Remove invalid candidates from each cell

    """

    def __init__(self):

        super().__init__(difficulty=0.769)

    def __call__(self, puzzle: Puzzle[T]) -> int:

        candidate_eliminations = 0

        for i, cell in enumerate(puzzle.cells):

            for _, peer in puzzle._peers(i):

                if cell.is_blank() and not peer.is_blank():

                    if peer.value in cell.candidates:

                        cell.candidates.remove(peer.value)

                        candidate_eliminations += 1

        return candidate_eliminations

Ancestors (in MRO)

  • sudoku.strategies.Strategy

Instance variables

1
difficulty
1
name

Strategy

1
2
3
4
class Strategy(
    name=None,
    difficulty=None
)

Attributes

Name Type Description Default
name str The name of the strategy None
difficulty float The difficulty rating of the strategy defined with
respect to eliminating a single candidate None
View Source
class Strategy:

    """

    Also known as a [Solving Technique](http://sudopedia.enjoysudoku.com/Solving_Technique.html)

    Attributes:

        name (str): The name of the strategy

        difficulty (float): The difficulty rating of the strategy defined with

            respect to eliminating a single candidate

    """

    __slots__ = "name", "difficulty"

    name: str

    difficulty: float

    def __init__(self, name=None, difficulty=None):

        self.name = name if name is not None else self.__class__.__name__

        self.difficulty = difficulty

    def __call__(self, puzzle: Puzzle[T]) -> int:

        """

        Apply the strategy to a given sudoku puzzle

        Args:

            puzzle (Puzzle[T]): The sudoku puzzle

        Returns:

            int: The number of candidates eliminated by the strategy with a

                single pass over the sudoku puzzle

        """

Descendants

  • sudoku.strategies.HiddenSubset
  • sudoku.strategies.NakedSubset
  • sudoku.strategies.RefreshCandidates

Instance variables

1
difficulty
1
name