分享 数独 Python算法 话不多说,脚本如下:
代码可以直接用python运行。
__author__ = u"maxdong"
import numpy as np
import time
import copy
from Queue import Queue, LifoQueue
class Recoder():
point = None
point_index = 0
value = None
class Sudo():
def __init__(self, data):
self.value = np.array([[0] * 9] * 9, dtype=object)
self.base_points = [[0, 0], [0, 3], [0, 6], [3, 0], [3, 3], [3, 6], [6, 0], [6, 3], [6, 6]]
self.guess_times = 0
self.new_points = Queue()
self.recoder = LifoQueue()
data = np.array(data).reshape(9, -1)
for r in range(0, 9):
for c in range(0, 9):
if data[r, c]:
self.value[r, c] = data[r, c]
self.new_points.put((r, c))
else:
self.value[r, c] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
def _cut_num(self, point):
r, c = point
val = self.value[r, c]
for i, item in enumerate(self.value[r]):
if isinstance(item, list):
if item.count(val):
item.remove(val)
if len(item) == 1:
self.new_points.put((r, i))
self.value[r, i] = item[0]
for i, item in enumerate(self.value[:, c]):
if isinstance(item, list):
if item.count(val):
item.remove(val)
if len(item) == 1:
self.new_points.put((i, c))
self.value[i, c] = item[0]
b_r, b_c = map(lambda x: x / 3 * 3, point)
for m_r, row in enumerate(self.value[b_r:b_r + 3, b_c:b_c + 3]):
for m_c, item in enumerate(row):
if isinstance(item, list):
if item.count(val):
item.remove(val)
if len(item) == 1:
r = b_r + m_r
c = b_c + m_c
self.new_points.put((r, c))
self.value[r, c] = item[0]
def _check_one_possbile(self):
for r in range(0, 9):
values = filter(lambda x: isinstance(x, list), self.value[r])
for c, item in enumerate(self.value[r]):
if isinstance(item, list):
for value in item:
if sum(map(lambda x: x.count(value), values)) == 1:
self.value[r, c] = value
self.new_points.put((r, c))
return True
for c in range(0, 9):
values = filter(lambda x: isinstance(x, list), self.value[:, c])
for r, item in enumerate(self.value[:, c]):
if isinstance(item, list):
for value in item:
if sum(map(lambda x: x.count(value), values)) == 1:
self.value[r, c] = value
self.new_points.put((r, c))
return True
for r, c in self.base_points:
values = filter(lambda x: isinstance(x, list), self.value[r:r + 3, c:c + 3].reshape(1, -1)[0])
for m_r, row in enumerate(self.value[r:r + 3, c:c + 3]):
for m_c, item in enumerate(row):
if isinstance(item, list):
for value in item:
if sum(map(lambda x: x.count(value), values)) == 1:
self.value[r + m_r, c + m_c] = value
self.new_points.put((r + m_r, c + m_c))
return True
def _check_same_num(self):
for b_r, b_c in self.base_points:
block = self.value[b_r:b_r + 3, b_c:b_c + 3]
data = block.reshape(1, -1)[0]
for i in range(1, 10):
result = map(lambda x: 0 if not isinstance(x[1], list) else x[0] + 1 if x[1].count(i) else 0,
enumerate(data))
result = filter(lambda x: x > 0, result)
r_count = len(result)
if r_count in [2, 3]:
rows = map(lambda x: (x - 1) / 3, result)
cols = map(lambda x: (x - 1) % 3, result)
if len(set(rows)) == 1:
result = map(lambda x: b_c + (x - 1) % 3, result)
row = b_r + rows[0]
for col in range(0, 9):
if not col in result:
item = self.value[row, col]
if isinstance(item, list):
if item.count(i):
item.remove(i)
if len(item) == 1:
self.new_points.put((row, col))
self.value[row, col] = item[0]
return True
elif len(set(cols)) == 1:
result = map(lambda x: b_r + (x - 1) / 3, result)
col = b_c + cols[0]
for row in range(0, 9):
if not row in result:
item = self.value[row, col]
if isinstance(item, list):
if item.count(i):
item.remove(i)
if len(item) == 1:
self.new_points.put((row, col))
self.value[row, col] = item[0]
return True
def solve_sudu(self):
is_run_same = True
is_run_one = True
while is_run_same:
while is_run_one:
while not self.new_points.empty():
point = self.new_points.get()
self._cut_num(point)
is_run_one = self._check_one_possbile()
is_run_same = self._check_same_num()
is_run_one = True
def get_num_count(self):
return sum(map(lambda x: 1 if isinstance(x, int) else 0, self.value.reshape(1, -1)[0]))
def get_best_point(self):
best_score = 0
best_point = (0, 0)
for r, row in enumerate(self.value):
for c, item in enumerate(row):
point_score = self._get_point_score((r, c))
if best_score < point_score:
best_score = point_score
best_point = (r, c)
return best_point
def _get_point_score(self, point):
r, c = point
item = self.value[r, c]
if isinstance(item, list):
score = 10 - len(item)
score += sum(map(lambda x: 1 if isinstance(x, int) else 0, self.value[r]))
score += sum(map(lambda x: 1 if isinstance(x, int) else 0, self.value[:, c]))
return score
else:
return 0
def check_value(self):
for row in self.value:
nums = []
lists = []
for item in row:
(lists if isinstance(item, list) else nums).append(item)
if len(set(nums)) != len(nums):
return False
if len(filter(lambda x: len(x) == 0, lists)):
return False
for c in range(0, 9):
nums = []
lists = []
col = self.value[:, c]
for item in col:
(lists if isinstance(item, list) else nums).append(item)
if len(set(nums)) != len(nums):
return False
if len(filter(lambda x: len(x) == 0, lists)):
return False
for b_r, b_c in self.base_points:
nums = []
lists = []
block = self.value[b_r:b_r + 3, b_c:b_c + 3].reshape(1, -1)[0]
for item in block:
(lists if isinstance(item, list) else nums).append(item)
if len(set(nums)) != len(nums):
return False
if len(filter(lambda x: len(x) == 0, lists)):
return False
return True
def recode_guess(self, point, index=0):
recoder = Recoder()
recoder.point = point
recoder.point_index = index
recoder.value = copy.deepcopy(self.value)
self.recoder.put(recoder)
self.guess_times += 1
item = self.value[point]
self.value[point] = item[index]
self.new_points.put(point)
self.solve_sudu()
def reback(self):
while True:
if self.recoder.empty():
raise Exception('sudo is wrong')
else:
recoder = self.recoder.get()
point = recoder.point
index = recoder.point_index + 1
item = recoder.value[point]
if index < len(item):
break
self.value = recoder.value
self.recode_guess(point, index)
def calc(self):
self.solve_sudu()
while True:
if self.check_value():
if self.get_num_count() == 81:
break
else:
point = self.get_best_point()
self.recode_guess(point)
else:
self.reback()
if __name__ == '__main__':
data = [8, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 3, 6, 0, 0, 0, 0, 0,
0, 7, 0, 0, 9, 0, 2, 0, 0,
0, 5, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 4, 5, 7, 0, 0,
0, 0, 0, 1, 0, 0, 0, 3, 0,
0, 0, 1, 0, 0, 0, 0, 6, 8,
0, 0, 8, 5, 0, 0, 0, 1, 0,
0, 9, 0, 0, 0, 0, 4, 0, 0]
try:
t1 = time.time()
sudo = Sudo(data)
sudo.calc()
t2 = time.time()
print(u"完成,猜测了%s次" % sudo.guess_times)
print(sudo.value)
print(u"耗时:%.3fs" % (t2 - t1))
except Exception as e:
print(e)