def puzzle1() -> None: # INFO = "123456789123456789123456789123456789123456789123456789123456789123456789123456789" puzzle = "...6.1.....4...2...1.....6.1.......2....8....6.......4.7.....9...1...4.....1.2..3" texts = [(3, 1, 8), *[(x, 9) for x in range(1, 9)]] features: List[Feature] = [ ContainsTextFeature(i, text) for i, text in enumerate(texts, start=1) ] sudoku = Sudoku() sudoku.solve(puzzle, features=features)
def you_tuber() -> None: puzzle = '...........12986...3.....7..8.....2..1.....6..7.....4..9.....8...54823..........' features = [ LimitedKnightsMove(), *[ SameValueAsExactlyOneMateFeature((row, column)) for row in (4, 5, 6) for column in (4, 5, 6) ] ] sudoku = Sudoku() sudoku.solve(puzzle, features=features)
def magic_squares() -> None: puzzle = ('.' * 17) + "1" + ('.' * 54) + '.6.......' features = [ MagicSquareFeature((2, 6)), MagicSquareFeature((4, 2)), MagicSquareFeature((6, 8)), MagicSquareFeature((8, 4)), ] sudoku = Sudoku() sudoku.solve(puzzle, features=features)
def puzzle5() -> None: previo = '..7......3.....5......................3..8............15.............9....9......' puzzle = '......3...1...............72.........................2..................8........' diadem = SnakeFeature([(4, 2), (2, 1), (3, 3), (1, 4), (3, 5), (1, 6), (3, 7), (2, 9), (4, 8)]) thermometers = [ ThermometerFeature(name, [(row, column) for row in (9, 8, 7, 6, 5, 4)]) for column in (2, 4, 6, 8) for name in [f'Thermometer #{column // 2}'] ] features = [diadem, *thermometers] sudoku = Sudoku() sudoku.solve(merge(puzzle, previo), features=features)
def puzzle4() -> None: previo = '.......................1....4..................5...1.............................' puzzle = '...............5.....6.....' + (54 * '.') puzzle = merge(puzzle, previo) info1 = ((1, 2), (2, 2), (3, 3), (4, 4), (5, 4), (6, 4), (7, 4), (8, 4), (8, 3)) info2 = tuple((row, 10 - column) for (row, column) in info1) sudoku = Sudoku() sudoku.solve(puzzle, features=[ GermanSnakeFeature("Left", info1), GermanSnakeFeature("Right", info2), KnightsMoveFeature() ])
def puzzle3() -> None: previo = '....4........6.............8.....9..........6.........2..........................' puzzle = '..9...7...5.....3.7.4.....9.............5.............5.....8.1.3.....9...7...5..' evens = [(2, 3), (3, 2), (3, 3), (1, 4), (1, 5), (1, 6)] evens = evens + [(column, 10 - row) for row, column in evens] evens = evens + [(10 - row, 10 - column) for row, column in evens] features = [ SnakeFeature([(3, 6), (3, 5), (4, 4), (5, 4), (5, 5), (5, 6), (6, 6), (7, 5), (7, 4)]), LimitedValuesFeature(evens, (2, 4, 6, 8)), ] sudoku = Sudoku() sudoku.solve(merge(puzzle, previo), features=features)
def double_sum_puzzle(*, show: bool = False) -> None: class CheckSpecialFeature(Feature): cells: Sequence[Cell] def initialize(self, grid: Grid) -> None: self.cells = [grid.matrix[1, 6], grid.matrix[2, 6]] def check_special(self) -> bool: if len(self.cells[0].possible_values) == 4: print("Danger. Danger") Cell.keep_values_for_cell(self.cells, {3, 7}) return True return False features = [ DoubleSumFeature(House.Type.ROW, 1, 6), DoubleSumFeature(House.Type.ROW, 4, 10, 10), DoubleSumFeature(House.Type.ROW, 5, 10, 9), DoubleSumFeature(House.Type.ROW, 6, 10, 10), DoubleSumFeature(House.Type.ROW, 7, 10, 10), DoubleSumFeature(House.Type.ROW, 9, 9, 11), DoubleSumFeature(House.Type.COLUMN, 1, 16), DoubleSumFeature(House.Type.COLUMN, 3, 13, 13), DoubleSumFeature(House.Type.COLUMN, 4, 12, 11), DoubleSumFeature(House.Type.COLUMN, 5, 9), DoubleSumFeature(House.Type.COLUMN, 6, 10, 10), DoubleSumFeature(House.Type.COLUMN, 7, 11, 15), DoubleSumFeature(House.Type.COLUMN, 8, 11, 9), CheckSpecialFeature(), ] Sudoku().solve('.' * 81, features=features, show=show)
def puzzle_08_26(*, show: bool = False) -> None: class PrimeRing(AdjacentRelationshipFeature): def __init__(self, squares): super().__init__("Prime", squares, cyclic=True, color='red') def match(self, digit1: int, digit2: int) -> bool: return digit1 + digit2 in {2, 3, 5, 7, 11, 13, 17} columns = (21, 25, 11, 0, 35, 23, 13, 4, 18) rows = (13, 13, 6, 9, 0, 29, 2, 13, 2) thermo = "3,7,S,S,S,S" wave = "2,2,E,E,S,E,E,N,E,E,S,S,W,S,S,E,S,S,W,W,N,W,W,S,W,W,N,N,E,N,N,W,N" features = [ ThermometerFeature(f'Thermo', Feature.parse_line(thermo)), PrimeRing(Feature.parse_line(wave)), *[ SandwichFeature(House.Type.ROW, row, total) for row, total in enumerate(rows, start=1) ], *[ SandwichFeature(House.Type.COLUMN, col, total) for col, total in enumerate(columns, start=1) ], ] Sudoku().solve(' ' * 81, features=features, show=show)
def puzzle_09_21(*, show: bool = False) -> None: class Multiplication(PossibilitiesFeature): def __init__(self, row, column): squares = [(row, column), (row, column + 1), (row + 1, column), (row + 1, column + 1)] super().__init__(f"Square{row}{column}", squares, neighbors=True) def get_possibilities(self) -> List[Tuple[Set[int], ...]]: for x, y in itertools.product(range(1, 10), repeat=2): if x <= y: z = x * y if z >= 11 and z % 10 != 0: yield ({x, y}, {x, y}, {z // 10}, {z % 10}) def draw(self, context: dict) -> None: self.draw_rectangles(self.squares, color='lightgray') puzzle = "X..7-6...5.-.8.-..9-X-5..-.6.-.9...1-2..X".replace( "X", "---").replace("-", "...") features = [ Multiplication(1, 1), Multiplication(1, 8), Multiplication(3, 3), Multiplication(6, 6), Multiplication(8, 1), Multiplication(8, 8) ] Sudoku().solve(puzzle, features=features, show=show)
def tour_puzzle_one(*, show: bool = False) -> None: features = [ *(LocateOneFeature(House.Type.ROW, i) for i in range(2, 9)), *(LocateOneFeature(House.Type.COLUMN, i) for i in range(2, 9)), DrawCircleFeature(((1,2), (1,4), (2, 9), (4, 8), (5, 2), (5, 3), (5, 7), (5, 8), (6, 2), (8, 1), (9, 6,), (9, 8))) ] puzzle = '.......................9.......5.3.....4.37....3.8.......36...........5..........' Sudoku().solve(puzzle, features=features, show=show)
def puzzle_08_15(*, show: bool = False) -> None: puzzle = "....1...4........5.............................1.....8........75.3....6.....3...." odds = [(3, 2), (3, 4), (3, 6), (3, 7), (3, 8), (4, 1), (4, 2), (4, 4), (4, 8), (5, 2), (5, 4), (5, 5), (5, 6), (5, 8), (6, 2), (6, 5), (6, 8), (7, 2), (7, 5), (7, 8)] features = [ KingsMoveFeature(), LimitedValuesFeature(odds, (1, 3, 5, 7, 9), color='lightgray') ] Sudoku().solve(puzzle, features=features, show=show)
def puzzle_09_20(*, show: bool = False) -> None: puzzle = "XXXXX-1..-XXX".replace("X", "---").replace("-", "...") features = [ *SandwichFeature.all(House.Type.ROW, [10, 19, 25, 28, 17, 3, 23, 6, 7]), *SandwichFeature.all(House.Type.COLUMN, [18, 8, 21, 18, 13, 27, 25, 13, 3]), KnightsMoveFeature() ] Sudoku().solve(puzzle, features=features, show=show)
def tour_puzzle_two(*, show: bool = False) -> None: previous = ".4.8.............7................9..85...76..7................4.............4.7." puzzle = "X,,6--XXXXX--6...5.--".replace('X', '---').replace('-', '...') puzzle = merge(previous, puzzle) # foobar = "XX..1--XXXX.....1...X".replace('X', '---').replace('-', '...') # print(len(foobar)) # puzzle = merge(foobar, puzzle) features = [PainInTheButtFeature(i) for i in range(1, 4)] features.append(PainInTheButtFeatureX()) Sudoku().solve(puzzle, features=features, show=show)
def puzzle_09_15(*, show: bool = False) -> None: puzzle = "-----.5.3.8.2.2.5.3.6.9.9.4.6.1.-".replace('-', '.........') features = XVFeature.setup( down_x=[(1, 3), (1, 5), (1, 7), (2, 2), (2, 4), (2, 6), (2, 8), (3, 3), (3, 5), (3, 7)]) Sudoku().solve(puzzle, features=features, show=show)
def thermometer_07_23() -> None: puzzle = ".....................9.............5...............3.................8.......9..." thermos = [ "1,1,SE,SE,SE,SW,SW", "1,9,SW,SW,SW,NW,NW", "9,1,NE,NE,NE,SE,SE", "9,9,NW,NW,NW,NE,NE" ] thermometers = [ ThermometerFeature(f'Thermo#{i}', Feature.parse_line(line), color='lightgray') for i, line in enumerate(thermos) ] Sudoku().solve(puzzle, features=thermometers)
def puzzle_07_30(*, show: bool = False) -> None: features = [ SandwichXboxFeature(House.Type.ROW, 3, 16), SandwichXboxFeature(House.Type.ROW, 4, 10, right=True), SandwichXboxFeature(House.Type.COLUMN, 3, 30), SandwichXboxFeature(House.Type.COLUMN, 4, 3), SandwichXboxFeature(House.Type.COLUMN, 7, 17), KingsMoveFeature(), QueensMoveFeature(), ] puzzle = "." * 63 + '.5.......' + '.' * 9 Sudoku().solve(puzzle, features=features, show=show)
def puzzle_alice(*, show: bool = False) -> None: # puzzle = "......... 3......8. ..4...... ......... 2...9...7 ......... ......5.. .1......6 ........." puzzle = "......... 3....6.8. ..4...... ......... 2...9...7 ......... ......5.. .1......6 ........." # 18:30 pieces = "122222939112122333911123333441153666445555696497758966447958886447559886777778889" features = [ AlternativeBoxesFeature(pieces), *(SameValueAsMateFeature((r, c)) for r in range(1, 10) for c in range(1, 10)) ] puzzle = puzzle.replace(' ', '') Sudoku().solve(puzzle, features=features, show=show)
def puzzle_08_12(*, show: bool = False) -> None: thermos = [ "5,5,nw,nw,n,ne", "5,5,nw,nw,sw,sw,s", "5,5,ne,ne,n,nw", "5,5,ne,ne,se,se,s", "5,5,s,s,sw,w,nw", "5,5,s,s,se,e,ne", "1,1,e", "1,1,s", "2,9,n,w", "8,1,s,e", "9,9,w", "9,9,n", "4,3,ne", "3,5,e,se,s", "6,7,sw,w,w", "6,3,n" ] thermometers = [ ThermometerFeature(f'Thermo#{i}', Feature.parse_line(line)) for i, line in enumerate(thermos, start=1) ] puzzle = "." * 63 + "....8...." + "." * 9 Sudoku().solve(puzzle, features=thermometers, show=show)
def puzzle7() -> None: puzzles = [ '925631847364578219718429365153964782249387156687215934472853691531796428896142573', # Diary, Red '398541672517263894642987513865372941123894756974156238289435167456718329731629485', # Ring, Purple '369248715152769438784531269843617952291854376675392184526973841438125697917486523', # Locket, Orangeish '817325496396487521524691783741952638963148257285763149158279364632814975479536812', # Cup, Yellow '527961384318742596694853217285619473473528169961437852152396748746285931839174625', # Crown, Blue '196842753275361489384759126963125847548937261721684935612578394837496512459213678', # Snake, Green ] pluses = [(1, 1), (1, 9), (2, 4), (2, 6), (3, 3), (3, 7), (4, 2), (4, 4), (4, 6), (4, 8), (5, 3)] pluses = pluses + [(10 - row, 10 - column) for row, column in pluses] puzzle = '......................7..1.....8.................6.....3..5......................' Sudoku().solve(puzzle, features=[(PlusFeature(pluses, puzzles))])
def puzzle_08_31(*, show: bool = False) -> None: thermos = [ "1,5,SW,SW,E,S", "1,8,W,W", "3,8,SW,S,SE,E", "7,3,NW,NW", "9,1,E,E", "9,8,NW,SW,NW,N,N,N,N" ] thermometers = [ ThermometerFeature(f'Thermo#{i}', Feature.parse_line(line)) for i, line in enumerate(thermos, start=1) ] snake_squares = [thermometer.squares[0] for thermometer in thermometers] snake_squares.extend(((2, 2), (4, 1), (7, 2))) snake = SnakeFeature(snake_squares, line=False) puzzle = ".....8....................9.................6.....4.................6.......7.9.." Sudoku().solve(puzzle, features=[*thermometers, snake], show=show)
def puzzle_08_02(*, show: bool = False) -> None: thermos = [ "2,1,SE,SE,NE,N,NE", "2,9,SW,SW,NW,N,NW", "6,1,N,N,N", "3,9,S,S,S", "8,1,E,E", "8,7,E,E", "5,6,SW,NW" ] features = [ MagicSquareFeature(), KingsMoveFeature(), *[ ThermometerFeature(f'Thermo#{i}', Feature.parse_line(line)) for i, line in enumerate(thermos, start=1) ], ] Sudoku().solve('.' * 81, features=features, show=show)
def puzzle_07_30_Simon(*, show: bool = False) -> None: thermos = [ "2,1,NE,S,NE,S,NE", "2,4,NE,S,NE,S,NE", "2,7,NE,S", "4,3,W,S,E,E,N", "4,7,W,S,E,E,N", "7,5,E,N,NW", "8,3,S,E,E,E", "9,8,N,E,N" ] thermometers = [ ThermometerFeature(f'Thermo#{i}', Feature.parse_line(line), color='lightblue') for i, line in enumerate(thermos, start=1) ] nada = "........." puzzle = nada + "......3.." + nada * 6 + ".......3." Sudoku().solve(puzzle, features=thermometers, show=show)
def thermo_magic() -> None: thermometers = [[(6 - r, 1) for r in range(1, 6)], [(6 - r, r) for r in range(1, 6)], [(1, 10 - r) for r in range(1, 6)], [(10 - r, 9) for r in range(1, 6)], [(10 - r, 4 + r) for r in range(1, 6)], [(9, 6 - r) for r in range(1, 6)]] features = [ MagicSquareFeature(dr=4, dc=4, color='lightblue'), *[ ThermometerFeature(f'Thermo #{count}', squares) for count, squares in enumerate(thermometers, start=1) ] ] puzzle = ("." * 18) + '.....2...' + ('.' * 27) + '...8.....' + ('.' * 18) Sudoku().solve(puzzle, features=features)
def slow_thermometer_puzzle2() -> None: puzzle = '.' * 72 + ".....1..." thermos = [ "2,4,N,W,S,S,E,SE", "2,7,N,W,S", "4,6,N,NW", "4,7,N,SE,SE", "4,2,SW,E,SW,E,SW,E,SW,E,SW", "5,4,SE,E", "6,4,E,E", "7,3,S,S", "9,5,NW,S", "9,6,N", "9,6,NW", "6,7,E,SW,W,W,W,NW", "6,9,W,SW,W,W,W,NW", "8,8,NW", "8,8,W,SE,W" ] thermometers = [ SlowThermometerFeature(f'Thermo#{i}', Feature.parse_line(line), color='lightblue') for i, line in enumerate(thermos) ] Sudoku().solve(puzzle, features=thermometers)
def puzzle_08_06(*, show: bool = False) -> None: OFFSETS1 = [(dr, dc) for dx in (-1, 1) for dy in (-2, 2) for (dr, dc) in ((dx, dy), (dy, dx))] OFFSETS2 = [(dr, dc) for delta in range(1, 9) for dr in (-delta, delta) for dc in (-delta, delta)] OFFSETS = OFFSETS1 + OFFSETS2 class MyFeature(SameValueAsMateFeature): def get_mates(self, cell: Cell, grid: Grid) -> Iterable[Cell]: return self.neighbors_from_offsets(grid, cell, OFFSETS) features = [ MyFeature((i, j)) for i, j in itertools.product(range(1, 10), repeat=2) ] puzzle = "39.1...822.....5.....4.....6..2.....1....4.........3............6...3..551.....64" Sudoku().solve(puzzle, features=features, show=show)
def sandwich_07_28(*, show: bool = False) -> None: class LiarsSandwichFeature(SandwichFeature): def get_possibilities(self) -> Iterable[Tuple[Set[int], ...]]: yield from self._get_possibilities(self.total - 1) yield from self._get_possibilities(self.total + 1) puzzle = "..6................1...........1.....4.........9...2.....................7......8" features = [ *[ LiarsSandwichFeature(House.Type.ROW, row, total) for row, total in enumerate((5, 8, 5, 16, 12, 7, 5, 3, 1), start=1) ], LiarsSandwichFeature(House.Type.COLUMN, 1, 5), LiarsSandwichFeature(House.Type.COLUMN, 5, 4), LiarsSandwichFeature(House.Type.COLUMN, 9, 5), ] Sudoku().solve(puzzle, features=features, show=show)
def puzzle_09_05(*, show: bool = False) -> None: class DeltaFeature(AdjacentRelationshipFeature): delta: int def __init__(self, square: Square, delta: int, is_right: bool): row, column = square square2 = (row, column + 1) if is_right else (row + 1, column) self.delta = delta super().__init__("d", [square, square2]) def draw(self, context: dict) -> None: (r1, c1), (r2, c2) = self.squares plt.text((c1 + c2 + 1) / 2, (r1 + r2 + 1) / 2, str(self.delta), verticalalignment='center', horizontalalignment='center', fontsize=15, weight='bold', color='red') def match(self, digit1: int, digit2: int) -> bool: return abs(digit1 - digit2) == self.delta features = [ DeltaFeature((2, 3), 1, True), DeltaFeature((2, 6), 1, True), DeltaFeature((3, 3), 7, True), DeltaFeature((3, 6), 7, True), DeltaFeature((4, 3), 5, True), DeltaFeature((4, 6), 5, True), DeltaFeature((6, 2), 1, True), DeltaFeature((6, 7), 2, True), DeltaFeature((1, 5), 8, False), DeltaFeature((2, 1), 4, False), DeltaFeature((2, 9), 4, False), DeltaFeature((3, 2), 6, False), DeltaFeature((3, 8), 6, False), DeltaFeature((4, 5), 3, False), DeltaFeature((7, 1), 1, False), DeltaFeature((7, 9), 2, False), DeltaFeature((8, 2), 1, False), DeltaFeature((8, 8), 2, False), ] puzzle = "XXXXXX.921.738.-3.9-X".replace("X", "---").replace("-", "...") Sudoku().solve(puzzle, features=features, show=show)
def puzzle_09_06(*, show: bool = False) -> None: class CamelJumpFeature(SameValueAsMateFeature): OFFSETS = [(dr, dc) for dx in (-1, 1) for dy in (-3, 3) for (dr, dc) in ((dx, dy), (dy, dx))] def get_mates(self, cell: Cell, grid: Grid) -> Iterable[Cell]: return self.neighbors_from_offsets(grid, cell, self.OFFSETS) def draw(self, context: dict) -> None: if self.done: self.draw_outline([self.this_square], linestyle="-") features = [ CamelJumpFeature(square) for square in itertools.product(range(1, 10), repeat=2) ] puzzle = "........9.....85..7...2.1..35...............6.96.....7...........1.7.9......452.." Sudoku().solve(puzzle, features=features, show=show)
def puzzle8() -> None: puzzles = [ '925631847364578219718429365153964782249387156687215934472853691531796428896142573', # Diary, Red '398541672517263894642987513865372941123894756974156238289435167456718329731629485', # Ring, Purple '369248715152769438784531269843617952291854376675392184526973841438125697917486523', # Locket, Orangeish '817325496396487521524691783741952638963148257285763149158279364632814975479536812', # Cup, Yellow '527961384318742596694853217285619473473528169961437852152396748746285931839174625', # Crown, Blue '196842753275361489384759126963125847548937261721684935612578394837496512459213678', # Snake, Green '213845679976123854548976213361782945859314762724569381632458197185297436497631528', # Enigma, Gray ] grid = '+.y..o+.+...Gb.......p...r.+..+b.b+...........+g.g+..+.o...........ry...+.+g..g.+' features = [ ColorFeature(grid, 'rpoybgG', puzzles), SnakeFeature.major_diagonal(), SnakeFeature.minor_diagonal(), ] Sudoku().solve('.' * 81, features=features)
def slow_thermometer_puzzle1() -> None: puzzle = '.' * 81 thermos = [[(4, 5), (5, 5), (6, 6), (5, 6), (4, 6), (3, 7), (2, 7), (1, 6), (1, 5), (1, 4), (2, 3), (3, 3), (4, 4)], [(4, 5), (5, 5), (6, 6), (5, 7), (4, 7), (3, 8), (2, 8)], [(2, 2), (2, 1), (1, 1), (1, 2)], [(1, 7), (1, 8), (2, 9), (3, 9), (4, 8), (5, 8)], [(6, 4), (5, 4), (4, 3), (3, 2)], [(5, 3), (4, 2), (4, 1), (5, 2), (5, 1), (6, 1)], [(6, 8), (6, 9), (5, 9), (4, 9)], [(8, 4), (9, 3), (8, 2), (8, 3), (7, 4), (6, 3), (7, 3), (7, 2)], [(7, 6), (7, 7), (7, 8), (7, 9), (8, 8), (9, 8), (9, 7), (8, 6), (7, 5)]] thermometers = [ SlowThermometerFeature(f'Thermo#{i}', thermo) for i, thermo in enumerate(thermos, start=1) ] Sudoku().solve(puzzle, features=thermometers)