Esempio n. 1
0
 def is_partial_solvable(self, sudoku):
     """Whether the sudoku can be solved by partial solver."""
     clone = sudoku_data.SudokuData()
     clone.copy(sudoku)
     for _ in range(80):
         partial_solution = self._solver.solve(clone, partial=True)
         if not partial_solution:
             break
     return clone.is_solved()
Esempio n. 2
0
 def __init__(self, randomize_type='random'):
   self._sudoku = sudoku_data.SudokuData()
   self._possible_values = [[set()] * 9 for _ in range(9)]
   # A list grouping locations by the number of possible values.
   self._location_groups = [set()] * 10
   # A dictionary mapping the possible locations of a number in a region.
   self._possible_locations = {}
   # A dictionary of unique locations for a number in a region.
   # The key is a tupe of the region type, region number, the value (number),
   # and the value is the only possible location.
   self._unique_locations = {}
   # Type of ranomizing, can be random, min or max.
   self.randomize_type = randomize_type
Esempio n. 3
0
 def generate_sudoku(self):
     """Generates a new sudoku and add it to the correct level."""
     min_nr_sudoku = min(
         [len(sudoku) for sudoku in self._sudoku_map.values()])
     # We already have enough sudoku in the cache.
     if min_nr_sudoku > 10:
         return
     nr_spaces = 56
     sudoku = sudoku_data.SudokuData()
     self._solver.solve(sudoku)
     full_sudoku = sudoku_data.SudokuData()
     full_sudoku.copy(sudoku)
     nr_removed = 0
     while nr_removed < nr_spaces:
         row = random.randrange(9)
         col = random.randrange(9)
         if sudoku.get(row, col) != ' ':
             sudoku.set(row, col, ' ')
             nr_removed += 1
     self.make_one_solution(sudoku, full_sudoku)
     curr_level = self.get_sudoku_level(sudoku)
     sudoku_list = self._sudoku_map[curr_level]
     if len(sudoku_list) < 100:
         sudoku_list.append(sudoku)
Esempio n. 4
0
 def make_one_solution(self, sudoku, full_sudoku):
     """Make a sudoku has only one solution."""
     for _ in range(80):
         clone1 = sudoku_data.SudokuData()
         clone1.copy(sudoku)
         self._max_solver.solve(clone1)
         clone2 = sudoku_data.SudokuData()
         clone2.copy(sudoku)
         self._min_solver.solve(clone2)
         is_same = True
         start_row = random.randrange(9)
         start_col = random.randrange(9)
         for i in range(9):
             for j in range(9):
                 row = int((start_row + i) % 9)
                 col = int((start_col + j) % 9)
                 if clone1.get(row, col) != clone2.get(row, col):
                     is_same = False
                     sudoku.set(row, col, full_sudoku.get(row, col))
                     break
             if not is_same:
                 break
         if is_same:
             return
Esempio n. 5
0
def read_data_file(file_name):
    expected_solutions = []
    sudoku = sudoku_data.SudokuData()
    with open(file_name, 'r') as f:
        lines = f.read().split('\n')
        sudoku.from_lines(lines)
        nr_solutions = int(lines[9])
        if nr_solutions == -1:
            expected_solutions = None
        else:
            for i in range(nr_solutions):
                expected_solutions.append(lines[i + 10])
    if expected_solutions is None:
        sorted_solutions = None
    else:
        sorted_solutions = sorted(expected_solutions)
    return sudoku, sorted_solutions
Esempio n. 6
0
 def __init__(self, stdscr):
     self.stdscr = stdscr
     self.height = 18
     self.width = 36
     self.curr_row = 4
     self.curr_col = 4
     self.curr_color = 1
     self.message = None
     self.confirm = None
     self.mouse_x = None
     self.mouse_y = None
     self.level = 'Easy'
     self.sudoku = sudoku_data.SudokuData()
     self.solver = sudoku_solver.SudokuSolver()
     self.generator = sudoku_generator.SudokuGenerator()
     self._setup_colors()
     self.data_file = '/tmp/magic_sudoku.data'
     self.changes = []
     self.redo_changes = []
Esempio n. 7
0
def test_solver(path, type):
    if type == 'partial':
        partial = True
        simple = False
    elif type == 'simple':
        partial = False
        simple = True
    else:
        partial = False
        simple = False
    for file_name in os.listdir(path):
        full_name = os.path.join(path, file_name)
        sudoku, expected_solution = read_data_file(full_name)
        original = sudoku_data.SudokuData()
        original.copy(sudoku)
        solution = sudoku_solver.SudokuSolver().solve(sudoku,
                                                      partial=partial,
                                                      simple=simple)
        compare_solutions(full_name, solution, expected_solution)
        compare_sudoku(full_name, sudoku, original, solution)
    print('Tests in {!r} with type {!r} passed.'.format(path, type))
Esempio n. 8
0
 def _process_key(self, key):
     """Process the key and mouse events."""
     if self.message:
         if self.message == _WIN_MSG:
             self.message = _NEW_SUDOKU_MSG
             self.confirm = _NEW_SUDOKU_CONFIRM
             return
         self.message = None
         curses.curs_set(1)
         if self.confirm is not None:
             if self.confirm == _NEW_SUDOKU_CONFIRM:
                 self.confirm = None
                 if key == ord('0'):
                     self.level = 'Easy'
                 elif key == ord('1'):
                     self.level = 'Easy'
                 elif key == ord('2'):
                     self.level = 'Medium'
                 elif key == ord('3'):
                     self.level = 'Hard'
                 elif key == ord('4'):
                     self.level = 'Challenger'
                 else:
                     return
                 if key == ord('0'):
                     self._change_sudoku(sudoku_data.SudokuData())
                 else:
                     self._change_sudoku(
                         self.generator.get_sudoku(level=self.level))
     elif key == ord('-') or key == ord('_'):
         # Reduce size of the sudoku board.
         if self.height > 18:
             self.height -= 9
             self.width -= 18
     elif key == ord('+') or key == ord('='):
         # Increase size of the sudoku board.
         self.height += 9
         self.width += 18
     elif key == curses.KEY_DOWN:
         # Move cursor down.
         self.curr_row = min(8, self.curr_row + 1)
     elif key == curses.KEY_UP:
         # Move cursor up.
         self.curr_row = max(0, self.curr_row - 1)
     elif key == curses.KEY_RIGHT:
         # Move cursor right.
         self.curr_col = min(8, self.curr_col + 1)
     elif key == curses.KEY_LEFT:
         # Move cursor left.
         self.curr_col = max(0, self.curr_col - 1)
     elif key == curses.KEY_MOUSE:
         # Move cursor to the location of the mouse.
         try:
             _, self.mouse_x, self.mouse_y, _, _ = curses.getmouse()
         except Exception:
             curses.beep()
     elif key == ord('a') or key == ord('A'):
         # Automatically solve the sudoku.
         clone = sudoku_data.SudokuData()
         clone.copy(self.sudoku)
         solution = self.solver.solve(clone)
         if solution:
             self._change_color(self.curr_color + 1)
             for row, col, value in solution:
                 self._change_number(row, col, value)
         else:
             self.message = 'Not solvable'
     elif key == ord('h') or key == ord('H'):
         # Give hint of the next move.
         clone = sudoku_data.SudokuData()
         clone.copy(self.sudoku)
         solution = self.solver.solve(clone, partial=True)
         if not solution:
             solution = self.solver.solve(clone)
         if solution:
             for row, col, value in solution:
                 self._change_number(row, col, value)
                 break
         else:
             self.message = 'Not solvable'
     elif key == ord('n') or key == ord('N'):
         # Generates a new sudoku.
         self.message = _NEW_SUDOKU_MSG
         self.confirm = _NEW_SUDOKU_CONFIRM
     elif key == ord('c') or key == ord('C'):
         # Change current color use for new numbers fill in the board.
         self._change_color(self.curr_color + 1)
     elif key == ord('b') or key == ord('B'):
         # Change current color to previous one.
         self._change_color(self.curr_color - 1)
     elif key == ord('m') or key == ord('M'):
         # Show or hide menu.
         self.message = _MENU
     elif key == ord('u') or key == ord('U'):
         # Undo changes.
         if self.changes:
             change_type, content = self.changes[-1]
             if change_type == _NUMBER_CHANGE:
                 row, col, original_value, _ = content
                 self.sudoku.set(row, col, original_value)
                 self.curr_row = row
                 self.curr_col = col
             elif change_type == _COLOR_CHANGE:
                 original_color, _ = content
                 self.curr_color = original_color
             else:
                 (original_sudoku, original_colors,
                  original_curr_color), _ = content
                 self.sudoku = original_sudoku
                 self.colors = original_colors
                 self.curr_color = original_curr_color
             del self.changes[-1]
             self.redo_changes.append((change_type, content))
             self._auto_save()
         else:
             self.message = 'Nothing to undo'
     elif key == ord('r') or key == ord('R'):
         # Redo changes.
         if self.redo_changes:
             change_type, content = self.redo_changes[-1]
             if change_type == _NUMBER_CHANGE:
                 row, col, _, new_value = content
                 self.sudoku.set(row, col, new_value)
                 self.curr_row = row
                 self.curr_col = col
             elif change_type == _COLOR_CHANGE:
                 _, new_color = content
                 self.curr_color = new_color
             else:
                 _, (new_sudoku, new_colors, new_curr_color) = content
                 self.sudoku = new_sudoku
                 self.colors = new_colors
                 self.curr_color = new_curr_color
             del self.redo_changes[-1]
             self.changes.append((change_type, content))
             self._auto_save()
         else:
             self.message = 'Nothing to redo'
     elif key >= ord('1') and key <= ord('9') or key == ord(' '):
         # Fill in a new number in the board. Space erases existing number.
         if self._change_number(self.curr_row, self.curr_col,
                                chr(key)) and self.sudoku.is_solved():
             self.message = _WIN_MSG