""" Module that generates a valid Sudoku Puzzle Credits for Solver : http://norvig.com/sudoku.html Credits for Generator: http://zhangroup.aporc.org/images/files/Paper_3485.pdf """ import random import re import numpy as np from . import Sudoku_Solver as solver #import Sudoku_Solver as solver filledcell = re.compile('(?!0)') def check_for_nonzeros(seq): return len([m.start() for m in filledcell.finditer(seq)]) def generate_completed_grid(n): # Generate a board by randomly picking n cells and # fill them a random digit from 1-9 values = solver.parse_grid('0' * 81) valid_assignments = 0 while valid_assignments < n: # display(values) cell_to_assign = solver.squares[random.randint(0, 80)] valid_values = values[cell_to_assign] if len(valid_values): value_to_assign = valid_values[random.randint(0, len(valid_values) - 1)] solver.assign(values, cell_to_assign, value_to_assign) valid_assignments += 1 complete_values = solver.solve(values) grid = '' for s in solver.squares: grid += complete_values[s] return grid def generate_dig_sequence(difficulty): # TODO: Determine the number of givens and lower bound of given if difficulty <= 1: random_number = list(range(81)) while len(random_number) > 0: #print(len(random_number)) yield random_number.pop(random.randint(0, len(random_number)-1)) elif difficulty == 2: current = 0 while current < 162: actual = current % 81 row = int(actual / 9) if not row % 2: yield actual else: yield (row+1) * 9 - 1 - (actual % 9) % 81 current += 2 elif difficulty == 3: current = 0 while current < 81: row = int(current / 9) if not row % 2: yield current else: yield (row+1) * 9 - 1 - (current % 9) current += 1 elif difficulty == 4: current = 0 while current < 81: yield current current += 1 def specify_grid_properties(difficulty): if difficulty == 0: n_givens = random.randint(50, 60) lower_bound = 5 elif difficulty == 1: n_givens = random.randint(36, 49) lower_bound = 4 elif difficulty == 2: n_givens = random.randint(32, 35) lower_bound = 3 elif difficulty == 3: n_givens = random.randint(28, 31) lower_bound = 2 elif difficulty == 4: n_givens = random.randint(22, 27) lower_bound = 0 return n_givens, lower_bound def grid_to_array(grid): assert len(grid) == 81 sudoku_array = np.zeros((9,9)) for i in range(81): r = int(i / 9) c = i % 9 sudoku_array[r, c] = int(grid[i]) return sudoku_array def generate_sudoku_puzzle(difficulty): grid = generate_completed_grid(11) n_givens, lower_bound = specify_grid_properties(difficulty) dig_sequence = generate_dig_sequence(difficulty) holes = 0 while holes < 81-n_givens: try: i = next(dig_sequence) except StopIteration: print("Reach end of Sequence") break row = i % 9 if check_for_nonzeros(grid[row:row+9]) > lower_bound: current_number = grid[i] other_numbers = solver.digits.replace(current_number, '') unique = True for digit in other_numbers: grid_check = grid[:i] + digit + grid[i+1:] if solver.solve(solver.parse_grid(grid_check)): unique = False break if unique: grid = grid[:i] + '0' + grid[i+1:] holes += 1 # TODO: Propagate and Output return grid if __name__ == "__main__": puzzle = generate_sudoku_puzzle(2) print(check_for_nonzeros(puzzle)) solver.display_grid(puzzle) solver.display(solver.solve(solver.parse_grid(puzzle)))