152 lines
3.6 KiB
Python
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
|
|
|