moved into dedicated folder

This commit is contained in:
Maxime Vorwerk
2024-10-03 15:39:31 +02:00
parent fde087dec7
commit c716f3c774
4 changed files with 0 additions and 0 deletions

29
python/cell.py Normal file
View 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
View 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
View 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
View 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)