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¶
- sudoku.strategies.hidden_subset
- sudoku.strategies.naked_subset
- sudoku.strategies.refresh_candidates
- sudoku.strategies.strategy
Classes¶
ForcedDigit¶
1 2 3 |
|
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 |
|
1 |
|
Instance variables¶
1 |
|
1 |
|
1 |
|
HiddenSingle¶
1 2 3 |
|
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 |
|
1 |
|
Instance variables¶
1 |
|
1 |
|
1 |
|
HiddenSubset¶
1 2 3 |
|
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 |
|
1 |
|
Instance variables¶
1 |
|
1 |
|
1 |
|
NakedDouble¶
1 2 3 |
|
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 |
|
1 |
|
Instance variables¶
1 |
|
1 |
|
1 |
|
NakedQuad¶
1 2 3 |
|
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 |
|
1 |
|
Instance variables¶
1 |
|
1 |
|
1 |
|
NakedSingle¶
1 2 3 |
|
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 |
|
1 |
|
Instance variables¶
1 |
|
1 |
|
1 |
|
NakedSubset¶
1 2 3 |
|
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 |
|
1 |
|
Instance variables¶
1 |
|
1 |
|
1 |
|
NakedTriple¶
1 2 3 |
|
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 |
|
1 |
|
Instance variables¶
1 |
|
1 |
|
1 |
|
PinnedDigit¶
1 2 3 |
|
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 |
|
1 |
|
Instance variables¶
1 |
|
1 |
|
1 |
|
RefreshCandidates¶
1 2 3 |
|
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 |
|
1 |
|
Strategy¶
1 2 3 4 |
|
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 |
|
1 |
|