Files
sudokusolver/python/solver.py
2024-10-03 15:39:31 +02:00

152 lines
3.6 KiB
Python

from grid import *
from copy import deepcopy
def solve(G):
stack = [G]
while len(stack) > 0:
grid = stack.pop()
ret = simplify(grid)
if ret == 0:
branch(grid, stack)
print(G)
printn("unsolvable!")
def simplify(G):
sum = 1
while sum > 0:
sum = 0
ret = check_rows(G)
if ret < 0:
return -1
else:
sum += ret
ret = check_cols(G)
if ret < 0:
return -1
else:
sum += ret
ret = check_squares(G)
if ret < 0:
return -1
else:
sum += ret
ret = reduce(G)
if ret < 0:
return -1
else:
sum += ret
return 0
def branch(G, stack):
min_cell = None
min_cell_size = 10
for cell in G.cells:
if cell.is_set == False and len(cell.candidates) < min_cell_size:
min_cell = cell
min_cell_size = len(cell.candidates)
candidates = min_cell.candidates
for candidate in candidates:
copy = deepcopy(G)
copy.cells[min_cell.n].set(candidate)
stack.append(copy)
def reduce(G):
n_steps = 0
while True:
val = reduce_step(G)
if val == 0:
print(G)
print("done")
exit(0)
elif val == 1:
return n_steps
n_steps += 1
def reduce_step(G):
all_set = True
nochange = True
for cell in G.cells:
l = len(cell.candidates)
if not cell.is_set:
if l == 1:
cell.set(cell.candidates[0])
nochange = False
else:
all_set = False
if all_set:
return 0
elif nochange:
return 1
else:
return 2
def check_rows(G):
res = 0
for row in G.rows:
finds = [0]*9
to_set = []
for cell in row:
cell = G.cells[cell]
for candidate in cell.candidates:
finds[candidate-1] += 1
for i, find in enumerate(finds):
if find == 1:
to_set.append(i+1)
elif find == 0:
return -1
for cell in row:
cell = G.cells[cell]
for i in to_set:
if i in cell.candidates and not cell.is_set:
cell.set(i)
res += 1
return res
def check_cols(G):
res = 0
for col in G.cols:
finds = [0]*9
to_set = []
for cell in col:
cell = G.cells[cell]
for candidate in cell.candidates:
finds[candidate-1] += 1
for i, find in enumerate(finds):
if find == 1:
to_set.append(i+1)
elif find == 0:
return -1
for cell in col:
cell = G.cells[cell]
for i in to_set:
if i in cell.candidates and not cell.is_set:
cell.set(i)
res += 1
return res
def check_squares(G):
res = 0
for square in G.squares:
finds = [0]*9
to_set = []
for cell in square:
cell = G.cells[cell]
for candidate in cell.candidates:
finds[candidate-1] += 1
for i, find in enumerate(finds):
if find == 1:
to_set.append(i+1)
elif find == 0:
return -1
for cell in square:
cell = G.cells[cell]
for i in to_set:
if i in cell.candidates and not cell.is_set:
cell.set(i)
res += 1
return res