SudokuGame/gameplay/Sudoku_Generator.py

140 lines
4.0 KiB
Python

"""
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)))