moved into dedicated folder
This commit is contained in:
29
python/cell.py
Normal file
29
python/cell.py
Normal file
@@ -0,0 +1,29 @@
|
||||
class cell:
|
||||
row = []
|
||||
col = []
|
||||
square = []
|
||||
candidates = []
|
||||
is_set = False
|
||||
n = -1
|
||||
|
||||
def __init__(self, n):
|
||||
self.candidates = [1,2,3,4,5,6,7,8,9]
|
||||
self.n = n
|
||||
|
||||
def set(self, n):
|
||||
assert n in self.candidates
|
||||
self.candidates = [n]
|
||||
self._prune(n)
|
||||
self.is_set = True
|
||||
|
||||
def _prune(self, n):
|
||||
for c in self.row:
|
||||
if n in c.candidates:
|
||||
c.candidates.remove(n)
|
||||
for c in self.col:
|
||||
if n in c.candidates:
|
||||
c.candidates.remove(n)
|
||||
for c in self.square:
|
||||
if n in c.candidates:
|
||||
c.candidates.remove(n)
|
||||
|
||||
89
python/grid.py
Normal file
89
python/grid.py
Normal file
@@ -0,0 +1,89 @@
|
||||
from cell import *
|
||||
|
||||
class grid:
|
||||
cells = []
|
||||
rows = []
|
||||
cols = []
|
||||
squares = []
|
||||
|
||||
def __init__(self):
|
||||
self.cells = [cell(n) for n in range(81)]
|
||||
|
||||
for i in range(9):
|
||||
self.rows.append([_find_i(i, j) for j in range(9)])
|
||||
self.cols.append([_find_i(j, i) for j in range(9)])
|
||||
self.squares.append([_find_i((i//3)*3 +j, (i//3)*3 +k) for j in range(3) for k in range(3)])
|
||||
|
||||
for i, c in enumerate(self.cells):
|
||||
i_row, i_col = _find_coords(i)
|
||||
|
||||
row = [_find_i(i_row, j) for j in range(9)]
|
||||
col = [_find_i(j, i_col) for j in range(9)]
|
||||
square = [_find_i((i_row//3)*3 +j, (i_col//3)*3 +k) for j in range(3) for k in range(3)]
|
||||
|
||||
row.remove(i)
|
||||
col.remove(i)
|
||||
square.remove(i)
|
||||
|
||||
c.row = [self.cells[j] for j in row]
|
||||
c.col = [self.cells[j] for j in col]
|
||||
c.square = [self.cells[j] for j in square]
|
||||
|
||||
def get_cell(self, i_row, i_col):
|
||||
return self.cells[_find_i(i_row, i_col)]
|
||||
|
||||
def set_cells(self, *tuples):
|
||||
for t in tuples:
|
||||
a, b, n = t
|
||||
self.cells[_find_i(a, b)].set(n)
|
||||
|
||||
def parse_string(s):
|
||||
assert len(s) == 81+8
|
||||
tuples = []
|
||||
lines = s.split('.')
|
||||
for i, line in enumerate(lines):
|
||||
assert len(line) == 9
|
||||
for j, char in enumerate(line):
|
||||
if char == " ":
|
||||
pass
|
||||
elif char in "123456789":
|
||||
tuples.append((i, j, int(char)))
|
||||
else:
|
||||
print("incorrent string!")
|
||||
exit(1)
|
||||
G = grid()
|
||||
G.set_cells(*tuples)
|
||||
return G
|
||||
|
||||
def __repr__(self):
|
||||
row_str = "{}{}{} {}{}{} {}{}{} | {}{}{} {}{}{} {}{}{} | {}{}{} {}{}{} {}{}{}"
|
||||
format = lambda a, n: row_str.format(*[cell.candidates[i] if i < len(cell.candidates) else " " for cell in self.cells[9*a:9*(a+1)] for i in range(3*n,3*(n+1))])
|
||||
return "\n".join([
|
||||
format(0, 0), format(0, 1), format(0, 2),
|
||||
" "*12+"|"+" "*13+"|",
|
||||
format(1, 0), format(1, 1), format(1, 2),
|
||||
" "*12+"|"+" "*13+"|",
|
||||
format(2, 0), format(2, 1), format(2, 2),
|
||||
"-"*39,
|
||||
format(3, 0), format(3, 1), format(3, 2),
|
||||
" "*12+"|"+" "*13+"|",
|
||||
format(4, 0), format(4, 1), format(4, 2),
|
||||
" "*12+"|"+" "*13+"|",
|
||||
format(5, 0), format(5, 1), format(5, 2),
|
||||
"-"*39,
|
||||
format(6, 0), format(6, 1), format(6, 2),
|
||||
" "*12+"|"+" "*13+"|",
|
||||
format(7, 0), format(7, 1), format(7, 2),
|
||||
" "*12+"|"+" "*13+"|",
|
||||
format(8, 0), format(8, 1), format(8, 2),
|
||||
""
|
||||
])
|
||||
|
||||
def _find_coords(i):
|
||||
i_row = i//9
|
||||
i_col = i%9
|
||||
return i_row, i_col
|
||||
|
||||
def _find_i(i_row, i_col):
|
||||
return 9*i_row + i_col
|
||||
|
||||
151
python/solver.py
Normal file
151
python/solver.py
Normal file
@@ -0,0 +1,151 @@
|
||||
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
|
||||
|
||||
22
python/sudokusolver.py
Executable file
22
python/sudokusolver.py
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python3
|
||||
from grid import grid
|
||||
from solver import solve
|
||||
|
||||
medium = [
|
||||
(0, 3, 7), (0, 4, 9), (0, 5, 3),
|
||||
(1, 1, 9), (1, 3, 5), (1, 4, 2), (1, 5, 1), (1, 6, 4),
|
||||
(2, 0, 7), (2, 8, 9),
|
||||
(3, 0, 2), (3, 3, 4), (3, 4, 3), (3, 6, 7),
|
||||
(4, 2, 9), (4, 3, 8), (4, 4, 1), (4, 5, 7), (4, 6, 3), (4, 7, 5),
|
||||
(5, 0, 3), (5, 4, 5), (5, 8, 8),
|
||||
(6, 1, 6), (6, 4, 8), (6, 5, 5), (6, 7, 7),
|
||||
(7, 4, 6), (7, 5, 2), (7, 6, 8), (7, 7, 9), (7, 8, 1),
|
||||
(8, 1, 8), (8, 3, 9)
|
||||
]
|
||||
|
||||
hard = " 5 1 6.3 5 8 9 . 7 4 . 2 . 9 31 . 1 9. 8 36 9 5.92 .6 7 8 "
|
||||
extreme = " 1 7 . 1 485.84 6 3 .5 19 . 35 6. 5 . 593 64 .18 72 3.3 "
|
||||
|
||||
G = grid.parse_string(extreme)
|
||||
solve(G)
|
||||
|
||||
Reference in New Issue
Block a user