python 数独解

秒杀世界上最难的九宫数独题!

网传11级的数独题   problems\test.txt:

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

代码部分    main.py:

# -*- coding: utf-8 -*-
"""数独解法解决方案  """
from __future__ import print_function, division
import os
import copy
import time


testfile = "test.txt"

class Sudo:
    def __init__(self):
        self.workout = False
        self.init_problem = []        # 原始题目
        self.versions = []           # 记录各版本信息
        self.current_version = []
        self.unusable = None          # 记录各单元格已用过的值
        self.unusable_versions = []     # 记录各版本已用过值的信息
        self.readproblem()

    def readproblem(self):
        problemdir = os.getcwd() + os.sep + "problems"
        problemfile = open(problemdir + os.sep + testfile)

        for line in problemfile.readlines():
            line = line.strip()
            line_list = [int(item) for item in line.split(" ")]
            self.init_problem.append(line_list)
        self.unusable = [[set() for i in range(0, 9)] for j in range(0, 9)]
        self.current_version = self.init_problem[:]
        self.versions.append(copy.deepcopy(self.current_version))
        self.unusable_versions.append(copy.deepcopy(self.unusable))

    def get_next_cell(self):
        """检测行,列,宫不同元素最多的非零单元格,没有则完成"""
        self.print_result()
        print("=====================")
        this_version = self.current_version
        max_items_row = None
        max_items_col = None
        max_items = set()
        for row in range(0, 9):
            for col in range(0, 9):
                if not this_version[row][col]:
                    row_intems = set(this_version[row])
                    col_items = set([_row[col] for _row in this_version])
                    palace_items = self._palace_item(row, col, this_version)
                    all_items = (row_intems | col_items | palace_items) - set([0])
                    if len(all_items) > len(max_items):
                        max_items_row, max_items_col, max_items = row, col, all_items
        if max_items:
            userable_items = set(range(1, 10)) - max_items
            self.voluation_cell(max_items_row, max_items_col, userable_items)
        else:
            self.workout = True

    def voluation_cell(self, row, col, userable_items):
        """1 单元格赋合适的值, 记录此单元格其余可用值
           2 记录该版本
           3 如无合适的值,回退版本
        """

        this_userable_items = userable_items - self.unusable[row][col]
        if this_userable_items:
            value = this_userable_items.pop()
            self.current_version[row][col] = value
            self.unusable[row][col].add(value)
            self.unusable_versions.append(copy.deepcopy(self.unusable))
            self.versions.append(copy.deepcopy(self.current_version))
            # if self.versions[-1] == self.versions[-2]:
            #     print("the same version !!!")
            #     print(row, col, value)
            #     for item in self.versions:
            #         print("-------------------")
            #         self.print_result(item)
            #     print("current_version-------------------")
            #     self.print_result()
            #     exit(1)
        else:
            self.back_last_version()

    def back_last_version(self):
        s = self.versions.pop()
        if not self.versions:
            print("No solution")
            exit(1)
        self.current_version = copy.deepcopy(self.versions[-1])
        u = self.unusable_versions.pop()
        self.unusable = copy.deepcopy(u)
        # if s == self.current_version:
        #     print("The version is not unicity!")
        #     self.print_result(s)
        #     print("#############")
        #     self.print_result()
        #     exit(1)

    def _palace_item(self, row, col, sudo):
        palace_row = int((row / 3))
        palace_col = int((col / 3))
        m = range(palace_row * 3, (palace_row + 1) * 3)
        n = range(palace_col * 3, (palace_col + 1) * 3)
        l = [sudo[i][j] for i in m for j in n]
        return set(l)

    def print_result(self, version=None):
        if version:
            this_version = version
        else:
            this_version = self.current_version
        for item in this_version:
            print(str(item).replace("[", "").replace("]", "").replace(",", ""))

    def run(self):
        while not self.workout:
            self.get_next_cell()
        print("workout!! the result is ......")
        self.print_result()


if __name__ == "__main__":
    Sudo().run()

posted @ 2012-11-09 13:44  flamedancer  阅读(329)  评论(0编辑  收藏  举报