-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path096.py
231 lines (211 loc) · 5.63 KB
/
096.py
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#!/usr/bin/python
counter = 0
tot = 0
def check(sudoku,opts): # check if sudoku is valid
for i in range(9):
for j in range(9):
if sudoku[i][j]==0 and opts[i][j]==[]:
return False
for i in range(9): # check rows
row = []
for j in range(9):
if sudoku[i][j]!=0:
if sudoku[i][j] in row:
return False
else:
row.append(sudoku[i][j])
for j in range(9): # check columns
col = []
for i in range(9):
if sudoku[i][j]!=0:
if sudoku[i][j] in col:
return False
else:
col.append(sudoku[i][j])
for i in range(3): # check blocks
for j in range(3):
block = []
for k in range(i*3, i*3+3):
for l in range(j*3, j*3+3):
if sudoku[k][l]!=0:
if sudoku[k][l] in block:
return False
else:
block.append(sudoku[k][l])
return True
def done(sudoku): # check if sudoku is filled out entirely
for i in range(9):
for j in range(9):
if sudoku[i][j]==0:
return False
return True
def crossout(opts, i, j, elem): # crosses out options if one is filled in
for k in range(9): # cross out in rows and columns
if elem in opts[i][k]:
opts[i][k].remove(elem)
if elem in opts[k][j]:
opts[k][j].remove(elem)
for k in range(i/3*3, i/3*3+3): # cross out in 3x3 blocks
for l in range(j/3*3, j/3*3+3):
if elem in opts[k][l]:
opts[k][l].remove(elem)
return opts
def sweep(sudoku, opts): # sweeps rows and columns until no longer possible
found = True
while found and not done(sudoku):
found = False
for i in range(9):
for j in range(9):
if len(opts[i][j]) == 1: # only one possibility
sudoku[i][j] = opts[i][j][0] # fill it in
opts[i][j] = []
opts = crossout(opts, i, j, sudoku[i][j])
found = True
return sudoku, opts
def uniques(sudoku, opts): #finds unique elements in a row and column
# row
for i in range(9):
multip = [0 for _ in range(10)] # counter
for j in range(9):
for k in opts[i][j]:
multip[k] += 1
for k in range(1,10):
if multip[k] == 1: # element occurs only once
for j in range(9):
if k in opts[i][j]:
sudoku[i][j]=k
opts[i][j]=[]
opts = crossout(opts, i, j, k)
# column
for i in range(9):
multip = [0 for _ in range(10)] # counter
for j in range(9):
for k in opts[j][i]:
multip[k] += 1
for k in range(1,10):
if multip[k] == 1: # element occurs only once
for j in range(9):
if k in opts[j][i]:
sudoku[j][i]=k
opts[j][i]=[]
opts = crossout(opts, j, i, k)
# block
for i in range(3):
for j in range(3):
multip = [0 for _ in range(10)]
for k in range(3*i,3*i+3):
for l in range(3*j,3*j+3):
for m in opts[k][l]:
multip[m] += 1
for k in range(1,10):
if multip[k] == 1:
for l in range(3*i,3*i+3):
for m in range(3*j,3*j+3):
if k in opts[l][m]:
sudoku[l][m]=k
opts[l][m]=[]
opts = crossout(opts,l,m,k)
return sudoku, opts
def twins(sudoku, opts):
for row in opts: # look for twins in a row
pairs = []
foundpair = False
for i in row:
if len(i)==2:
if i in pairs:
# we found twins!
foundpair = i
break
else:
pairs.append(i)
if foundpair: # cross out twins
for i in row:
if i!=foundpair:
for k in foundpair:
if k in i:
i.remove(k)
sudoku, opts = sweep(sudoku, opts) # sweep everything
sudoku, opts = uniques(sudoku, opts)
for i in range(9): # look for twins in column
pairs = []
foundpair = False
for j in range(9):
if len(opts[j][i])==2:
if opts[j][i] in pairs:
foundpair = opts[j][i]
break
else:
pairs.append(opts[j][i])
if foundpair:
for j in range(9):
if opts[j][i]!=foundpair:
for k in foundpair:
if k in opts[j][i]:
opts[j][i].remove(k)
sudoku, opts = sweep(sudoku, opts) # sweep everything
sudoku, opts = uniques(sudoku, opts)
for i in range(3): # look for twins in a block
for j in range(3):
# we are in a block
foundpair = False
pairs = []
for k in range(3*i,3*i+3):
for l in range(3*j,3*j+3):
if len(opts[k][l])==2:
if opts[k][l] in pairs:
foundpair = opts[k][l]
break
else:
pairs.append(opts[k][l])
if foundpair:
for k in range(3*i,3*i+3):
for l in range(3*j,3*j+3):
if opts[k][l] != foundpair:
for m in foundpair:
if m in opts[k][l]:
opts[k][l].remove(m)
sudoku, opts = sweep(sudoku, opts) # sweep everything
sudoku, opts = uniques(sudoku, opts)
return sudoku, opts
def solve(sudoku):
#print "\n".join(["".join(str(i)) for i in sudoku])
opts = [[range(1,10) for _ in range(9)] for _ in range(9)]
# initial filling in opts
for i in range(9):
for j in range(9):
if sudoku[i][j] != 0:
opts[i][j] = []
opts = crossout(opts, i, j, sudoku[i][j])
for _ in range(20):
sudoku, opts = twins(sudoku, opts) # look for twins
if done(sudoku):
break
sudoku, opts = uniques(sudoku, opts)
if check(sudoku,opts):
if done(sudoku):
global counter, tot
counter += 1
#print "done!"
tot += sudoku[0][0]*100+sudoku[0][1]*10+sudoku[0][2]
else:
print "not done!"
print "\n".join(["\t".join([str(j) if j!=0 else " " for j in i]) for i in sudoku])
print "-"*70
else:
print "not valid!"
print "\n".join(["\t".join([str(j) if j!=0 else " " for j in i]) for i in sudoku])
print "-"*70
# read in the sudokus
with open("096_sudoku.txt", "r") as f:
sudokus = []
for line in f:
if line[0]=="G":
sudoku = []
sudokus.append(sudoku)
else:
sudoku.append([int(i) for i in line.strip()])
for sudoku in sudokus:
solve(sudoku)
print counter, tot
# 6 sudokus were not solved
# tried filling in a random number somewhere and see if it were valid