Beispiel #1
0
 def impossible_test(self):
     # impossible
     puzzles = [
         # From https://norvig.com/sudoku.html  -> column 4, no 1 possible because of triple 5-6 doubles and triple 1s
         '.....5.8....6.1.43..........1.5........1.6...3.......553.....61........4.........',
         # obvious doubles
         '12.......34...............5...........5..........................................',
         '11.......34...............5......................................................',
     ]
     for puzzle in puzzles:
         puzzle = str2grid(puzzle)
         s = Sudoku(puzzle)
         s.flush_candidates()
         self.assertFalse(s.check_possible()[0])
     # possible
     puzzles = [
         '280070309600104007745080006064830100102009800000201930006050701508090020070402050',
         '000010030009005008804006025000000600008004000120087000300900200065008000900000000',
         '1.....................................5..........................................',
     ]
     for puzzle in [puzzles[1]]:
         puzzle = str2grid(puzzle)
         s = Sudoku(puzzle)
         s.flush_candidates()
         self.assertTrue(s.check_possible()[0])
Beispiel #2
0
 def check_done(self):
     # Easy
     puzzle = '280070309600104007745080006064830100102009800000201930006050701508090020070402050'
     solution = '281576349693124587745983216964835172132749865857261934426358791518697423379412658'
     puzzle, solution = str2grid(puzzle), str2grid(solution)
     s = Sudoku(puzzle)
     self.assertFalse(s.check_done())
     s = Sudoku(solution)
     self.assertTrue(s.check_done())
     # Medium
     puzzle = '100020400035040900704000001800000000091032080000100097070900600000000000000450000'
     solution = '189327465235641978764895321827569143491732586653184297372918654546273819918456732'
     puzzle, solution = str2grid(puzzle), str2grid(solution)
     s = Sudoku(puzzle)
     self.assertFalse(s.check_done())
     s = Sudoku(solution)
     self.assertTrue(s.check_done())
Beispiel #3
0
 def solve_X_sudoku(self):
     puzzles = [
         ('060050200000000060532008000000049103000100050000000007005010008004000006000006500',
          '968751234741392865532468719257649183493187652186235497675914328814523976329876541'
          ),
         ('030040200520006700000000000080020170000070000050000003400000032000600000000080691',
          '638547219521936748749218365984325176362179584157864923496751832813692457275483691'
          )
     ]
     for puzzle, solution in puzzles:
         puzzle, solution = str2grid(puzzle), str2grid(solution)
         solution_set, done, info = solveSudoku(puzzle,
                                                verbose=False,
                                                all_solutions=False,
                                                is_X_Sudoku=True)
         self.assertTrue(done)
         solver_sol = str2grid(solution_set[0])
         self.assertTrue(grid_equal(solution, solver_sol))
Beispiel #4
0
 def check_solver(self):
     # check sovler using manually solved puzzles
     # easy Sudokus (no backtracking required). From New York Times, 31 May 2020 - 2 June 2020
     puzzles = [
         ('280070309600104007745080006064830100102009800000201930006050701508090020070402050',
          '281576349693124587745983216964835172132749865857261934426358791518697423379412658'
          ),
         ('910780200027001894684000300000846001740059080009000050106093008000500706002070130',
          '913784265527361894684925317235846971741259683869137452176493528398512746452678139'
          )
     ]
     for puzzle, solution in puzzles:
         puzzle, solution = list(map(str2grid, [puzzle, solution]))
         solution_set, done, _ = solveSudoku(puzzle,
                                             verbose=False,
                                             all_solutions=False)
         self.assertTrue(done)
         solver_sol = str2grid(solution_set[0])
         self.assertTrue(grid_equal(solution, solver_sol))
     # medium to hard Sudoku (some backtracking). From New York Times, 31 May 2020 - 2 June 2020
     puzzles = [
         ('100020400035040900704000001800000000091032080000100097070900600000000000000450000',
          '189327465235641978764895321827569143491732586653184297372918654546273819918456732'
          ),
         ('000832067000600200800700010010020000509004700000008000007000940000005000402000500',
          '195832467743651298826749315318927654569314782274568139657283941931475826482196573'
          ),
         ('000010030009005008804006025000000600008004000120087000300900200065008000900000000',
          '752819436639245718814736925473592681598164372126387549387951264265478193941623857'
          )
     ]
     for puzzle, solution in puzzles:
         puzzle, solution = list(map(str2grid, [puzzle, solution]))
         solution_set, done, _ = solveSudoku(puzzle,
                                             verbose=False,
                                             all_solutions=False)
         self.assertTrue(done)
         solver_sol = str2grid(solution_set[0])
         self.assertTrue(grid_equal(solution, solver_sol))
def solveIt(puzzle):
    try:
        grid = str2grid(puzzle)
        solution_set, done, info = solveSudoku(grid,
                                               verbose=False,
                                               all_solutions=False)
        if not done:
            return ""

        # print(solution_set[0])
        return (solution_set[0])
    except IndexError:
        return ""
Beispiel #6
0
 def check_solved_puzzles(self):
     # these puzzles were sovled with the solver. This is to check solutions still hold.
     puzzles = [
         # from https://dev.to/aspittel/how-i-finally-wrote-a-sudoku-solver-177g
         (
             # very easy puzzle
             '530070000600195000098000060800060003400803001700020006060000280000419005000080079',
             '534678912672195348198342567859761423426853791713924856961537284287419635345286179'
         ),
         # https://www.nytimes.com/puzzles/sudoku/
         ('106000050070030004090005200002060007000108000047020000000000803003200006000000002',
          '186742359275839164394615278812564937639178425547923681721456893953281746468397512'
          ),
         # Arto Inkala Puzzles from  https://norvig.com/sudoku.html
         (
             # not that hard actually
             '85...24..72......9..4.........1.7..23.5...9...4...........8..7..17..........36.4.',
             '859612437723854169164379528986147352375268914241593786432981675617425893598736241'
         ),
         (
             # have to make at least 3 guesses
             '..53.....8......2..7..1.5..4....53...1..7...6..32...8..6.5....9..4....3......97..',
             '145327698839654127672918543496185372218473956753296481367542819984761235521839764'
         ),
         (
             # have to make at least 3 guesses
             '800000000003600000070090200050007000000045700000100030001000068008500010090000400',
             '812753649943682175675491283154237896369845721287169534521974368438526917796318452'
         ),
         # 17 clue puzzle from https://theconversation.com/good-at-sudoku-heres-some-youll-never-complete-5234
         (
             #  1 unique solution. Very fun to do
             '000700000100000000000430200000000006000509000000000418000081000002000050040000300',
             '264715839137892645598436271423178596816549723759623418375281964982364157641957382'
         ),
         # 17 clue puzzle from  https://cracking-the-cryptic.web.app/sudoku/PMhgbbQRRb
         ('029000400000500100040000000000042000600000070500000000700300005010090000000000060',
          '329816457867534192145279638931742586684153279572968314796321845418695723253487961'
          ),
         # https://www.sudokuwiki.org/Weekly_Sudoku.asp
         (  # May 24 2020 Extreme -> requires multiple diabolical+extreme strategies
             '003100720700000500050240030000720000006000800000014000060095080005000009049002600',
             '693158724724963518851247936538726491416539872972814365267495183385671249149382657'
         ),
         (
             #403 'unsolvable' - no known logical solution
             '100200000065074800070006900004000000050008704000030000000000600080000057006007089',
             '138259476965374821472186935824761593653928714791435268517893642389642157246517389'
         ),
         (
             #404 'unsolvable' - no known logical solution
             '400009200000010080005400006004200001050030060700005300500007600090060000002800007',
             '468579213279613485135428796384296571951734862726185349513947628897362154642851937'
         ),
         (
             # June 7 2020 Extreme
             '080001206000020000020305040060010900002050400008000010030704050000030000406100080',
             '785941236143628795629375841564213978912857463378469512231784659897536124456192387'
         )
     ]
     for puzzle, solution in puzzles:
         puzzle, solution = str2grid(puzzle), str2grid(solution)
         solution_set, done, _ = solveSudoku(puzzle,
                                             verbose=False,
                                             all_solutions=False)
         self.assertTrue(done)
         solver_sol = str2grid(solution_set[0])
         self.assertTrue(grid_equal(solution, solver_sol))
    with open(folder + file_name, 'r') as f:
        puzzles = f.read().strip().split('\n')

    verbose = False
    all_solutions = False

    t0 = time.time()
    metrics = {'times': [], 'calls': [], 'max depths': [], 'nsolutions': []}
    num_solved = 0
    for k, puzzle in enumerate(puzzles):
        # if k != 86:
        #     continue
        tk0 = time.time()
        ## solve
        puzzle = str2grid(puzzle)
        my_solution, done, info = solveSudoku(puzzle,
                                              verbose=verbose,
                                              all_solutions=all_solutions)
        # my_solution, done, info = solveSudokuBrute(puzzle)
        deltaTk = time.time() - tk0
        ## update metrics
        num_solved += done
        metrics['times'].append(deltaTk)
        metrics['calls'].append(info['calls'])
        metrics['max depths'].append(info['max depth'])
        metrics['nsolutions'].append(info['nsolutions'])
    deltaT = time.time() - t0

    pm = '\u00b1'  #plus or minus symbol