-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
159 lines (124 loc) · 3.71 KB
/
Copy pathmain.py
File metadata and controls
159 lines (124 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import copy
import time
COLUMNS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
def init():
_sudoku = {}
for c in COLUMNS:
_sudoku[c] = {}
for r in range(9):
_sudoku[c][r] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
return _sudoku
def draw(_sudoku):
screen = ""
for r in range(9):
for c in COLUMNS:
# screen += f"{c}{r}:"
screen += f"{_sudoku[c][r]} "
screen += "\n"
return screen
def lock(_sudoku, column, row, value):
# Ignore value = 0
if value == 0:
return _sudoku
solved = isinstance(_sudoku[column][row], int)
if not solved and not (value in _sudoku[column][row]):
print(f"Cell [{column}{row}] can not be set to: {value}")
exit(1)
# Lock in row
for r in range(9):
solved = isinstance(_sudoku[column][r], int)
if not solved and value in _sudoku[column][r]:
_sudoku[column][r].remove(value)
# Lock in column
for c in COLUMNS:
solved = isinstance(_sudoku[c][row], int)
if not solved and value in _sudoku[c][row]:
_sudoku[c][row].remove(value)
# Lock in box
square_column = int(COLUMNS.index(column) / 3) * 3
square_row = int(row / 3) * 3
for row_carry in range(3):
r = square_row + row_carry
for column_carry in range(3):
c = COLUMNS[square_column + column_carry]
solved = isinstance(_sudoku[c][r], int)
if not solved and value in _sudoku[c][r]:
_sudoku[c][r].remove(value)
_sudoku[column][row] = value
return _sudoku
def load(_sudoku, filename):
f = open(filename, "r")
for r in range(9):
for c in COLUMNS:
v = int(f.readline())
_sudoku = lock(_sudoku, c, r, v)
return _sudoku
def completed(_sudoku):
for r in range(9):
for c in COLUMNS:
solved = isinstance(_sudoku[c][r], int)
if not solved:
return False
return True
def impossible(_sudoku):
for r in range(9):
for c in COLUMNS:
solved = isinstance(_sudoku[c][r], int)
if not solved and len(_sudoku[c][r]) == 0:
return True
return False
def shortest(_sudoku):
minimum = 9
length = 9
column = None
row = None
for r in range(9):
for c in COLUMNS:
solved = isinstance(_sudoku[c][r], int)
if not solved and len(_sudoku[c][r]) < minimum:
minimum = len(_sudoku[c][r])
column = c
row = r
return {
'column': column,
'row': row,
'length': length
}
def backtrack(_sudoku):
srt = shortest(_sudoku)
c = srt['column']
r = srt['row']
for v in _sudoku[c][r]:
tmp = copy.deepcopy(_sudoku)
tmp = lock(tmp, c, r, v)
if impossible(tmp):
return False
solve(tmp)
def solve(_sudoku):
# Solve cells with only one solution
for r in range(9):
for c in COLUMNS:
cell = _sudoku[c][r]
solved = isinstance(cell, int)
if not solved and len(cell) == 1:
v = cell[0]
_sudoku = lock(_sudoku, c, r, v)
return solve(_sudoku)
if completed(_sudoku):
print(draw(_sudoku))
return _sudoku
# Once here we need to use backtracking
backtrack(_sudoku)
# Sudoku has been taken from https://www.sudokumania.com.ar/juegos/sudoku
# veryeasy: SD1OVCNW
# easy: SD2POYFO
# medium.txt: SD3NCQXP
# hard: SD4CDQGU
# veryhard: SD5FEKLR
# superveryhard: SD6GAUMK
# Imposible: SD9FDOPM
t = time.time_ns()
sudoku = init()
sudoku = load(sudoku, "hard.txt")
solve(sudoku)
print(f"Solved in {time.time_ns() - t} ns")