add py files, not working yet
This commit is contained in:
165
sudoku.py
Normal file
165
sudoku.py
Normal file
@@ -0,0 +1,165 @@
|
||||
from copy import deepcopy
|
||||
import random
|
||||
|
||||
class sudoku_grid():
|
||||
def __init__(self, prefilled_cells):
|
||||
# cell = {'possible': set([i for i in range(1,10)]), 'solution': 0}
|
||||
self.grid = [[{'possible': set([i for i in range(1,10)]), 'solution': 0} for _ in range(9)] for _ in range(9)]
|
||||
|
||||
# prefilled_cells is a nested list (9x9) of values (1-9), 0 specifies an empty cell
|
||||
try:
|
||||
ctr = 0
|
||||
if len(prefilled_cells) != 9:
|
||||
raise ValueError.add_note(f'wrong number of rows')
|
||||
for i in range(9):
|
||||
if len(prefilled_cells[i]) != 9:
|
||||
raise ValueError.add_note(f'wrong number of cells in row {i}')
|
||||
for j in range(9):
|
||||
# if prefilled_cell in valid range: fill in matching cell an mark as solved
|
||||
if 1 <= prefilled_cells[i][j] <= 9:
|
||||
self.grid[i][j]['possible'] = {prefilled_cells[i][j]}
|
||||
self.grid[i][j]['solution'] = prefilled_cells[i][j]
|
||||
ctr += 1
|
||||
|
||||
if ctr == 0:
|
||||
raise ValueError.add_note(f'prefilled_cells is empty')
|
||||
except ValueError as e:
|
||||
print(f'{e}')
|
||||
|
||||
def __str__(self):
|
||||
retstr = 'sudoku: \n'
|
||||
for i in range(9):
|
||||
for j in range(9):
|
||||
if self.grid[i][j]['solution']:
|
||||
current_val = self.grid[i][j]['solution']
|
||||
retstr += f'{current_val} '
|
||||
else:
|
||||
retstr += '_ '
|
||||
if j == 2 or j == 5:
|
||||
retstr += '# '
|
||||
if i == 2 or i == 5:
|
||||
retstr += '\n# # # # # # # # # # # '
|
||||
retstr += '\n'
|
||||
return retstr
|
||||
|
||||
def removeValue(self, row, col, value):
|
||||
if self.grid[row][col]['possible']:
|
||||
self.grid[row][col]['possible'].discard(value)
|
||||
pass
|
||||
|
||||
def iterate(self):
|
||||
# iterate over all cells
|
||||
for i in range(9):
|
||||
for j in range(9):
|
||||
|
||||
# get the value
|
||||
current_value = self.grid[i][j]['solution']
|
||||
if current_value:
|
||||
for k in range(9):
|
||||
self.removeValue(i, k, current_value) # remove value from current row
|
||||
self.removeValue(k, j, current_value) # remove value from current column
|
||||
for k in range(3):
|
||||
for l in range(3):
|
||||
self.removeValue((i//3)*3+(i+k)%3, (j//3)*3+(j+l)%3, current_value) # remove value from current 3x3 box
|
||||
|
||||
current_set = set()
|
||||
add = 0
|
||||
for k in range(8):
|
||||
current_set = current_set and self.grid[i][(j+k)%9]['possible']
|
||||
current_set = current_set and self.grid[(i+k)%9][j]['possible']
|
||||
if (i//3)*3+k//3 == i and (j//3)*3+k%3 == j:
|
||||
add = 1
|
||||
l = k + add
|
||||
row = (i//3)*3+l//3
|
||||
col = (j//3)*3+l%3
|
||||
current_set = current_set and self.grid[row][col]['possible']
|
||||
|
||||
new_set = self.grid[i][j]['possible']-self.grid[i][j]['possible'].intersection(current_set)
|
||||
if new_set:
|
||||
self.grid[i][j]['possible'] = new_set
|
||||
|
||||
for i in range(9):
|
||||
for j in range(9):
|
||||
if len(self.grid[i][j]['possible']) == 1:
|
||||
self.grid[i][j]['solution'] = list(self.grid[i][j]['possible'])[0]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def find_lowest_entropy(self):
|
||||
lowest_i = -1
|
||||
lowest_j = -1
|
||||
sols = None
|
||||
lowest_e = 10
|
||||
for i in range(9):
|
||||
for j in range(9):
|
||||
if self.grid[i][j]['solution']:
|
||||
continue
|
||||
e = len(self.grid[i][j]['possible'])
|
||||
if e < lowest_e:
|
||||
sols = list(self.grid[i][j]['possible'])
|
||||
lowest_i = i
|
||||
lowest_j = j
|
||||
lowest_e = e
|
||||
if lowest_e == 0:
|
||||
lowest_i = -1
|
||||
lowest_j = -1
|
||||
sols = None
|
||||
lowest_e = 10
|
||||
return (lowest_i, lowest_j, lowest_e, sols)
|
||||
return (lowest_i, lowest_j, lowest_e, sols)
|
||||
|
||||
def collapse_cell(self, row, col):
|
||||
if self.grid[row][col]['solution']:
|
||||
return None
|
||||
possible = self.grid[row][col]['possible']
|
||||
if len(possible) == 1:
|
||||
self.grid[row][col]['solution'] = list(possible)[0]
|
||||
|
||||
|
||||
def single_solutions_exist(self):
|
||||
for i in range(9):
|
||||
for j in range(9):
|
||||
if self.grid[i][j]['possible']:
|
||||
if len(self.grid[i][j]['possible']) == 1:
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_solved(self):
|
||||
for i in range(9):
|
||||
for j in range(9):
|
||||
if not self.grid[i][j]['solution']:
|
||||
return False
|
||||
return True
|
||||
|
||||
iteration = 1
|
||||
if __name__ == '__main__':
|
||||
prefilled = [ [0,4,9,7,0,5,0,0,0],
|
||||
[0,0,0,0,0,4,0,0,3],
|
||||
[6,0,1,2,0,0,0,7,0],
|
||||
[0,0,0,0,9,1,0,0,5],
|
||||
[0,2,4,0,6,8,7,3,1],
|
||||
[1,5,8,0,2,7,4,9,0],
|
||||
[0,0,0,0,0,2,6,4,0],
|
||||
[0,6,0,1,0,0,0,0,0],
|
||||
[4,0,5,0,0,0,3,0,2]]
|
||||
sudoku = sudoku_grid(prefilled)
|
||||
print(sudoku)
|
||||
while not sudoku.is_solved():
|
||||
sudoku.iterate()
|
||||
# cnt = 0
|
||||
# [row, col, entropy, solutions] = sudoku.find_lowest_entropy()
|
||||
# if row == -1:
|
||||
# print(f'No solution found! Iteration {iteration}')
|
||||
# break
|
||||
# print(f'Lowest Entropy in Iteration {iteration} ({cnt}): {entropy} in ({row},{col}) with solutions {solutions}')
|
||||
# sudoku.collapse_cell(row, col)
|
||||
# while sudoku.single_solutions_exist():
|
||||
# cnt += 1
|
||||
# [row, col, entropy, solutions] = sudoku.find_lowest_entropy()
|
||||
# print(f'Lowest Entropy in Iteration {iteration} ({cnt}): {entropy} in ({row},{col}) with solutions {solutions}')
|
||||
# sudoku.collapse_cell(row,col)
|
||||
# print(sudoku)
|
||||
iteration += 1
|
||||
print(sudoku)
|
||||
Reference in New Issue
Block a user