八数码问题(DFS+BFS+A+A*+GUI)

(这是学校的一个小实验,核心内容除了八数码问题,更主要的是,自己用的是Python。。。特别慢,太慢了至少比java慢上了10倍,所以自己想了固定时间运行,优先队列,hash等方法慢弥补这种运行缓慢带来的不便)

算法部分:

import numpy as np
import copy
import queue
import time


class Node(object):  # 定义每一张图的状态
    def __init__(self, data, level, parent, score):
        self.data = data  # 二维的矩阵数据
        self.level = level  # 定义搜索深度
        self.parent = parent  # 定义父亲节点,用来递归进行搜索
        self.score = score  # 服务于A算法系列,用来给每一个状态进行打分估值

    def __lt__(self, other):  # 自定义比较函数,为后面的优先队列进行服务
        return self.score < other.score


class solution:  # 定义解决方法类
    def __init__(self, initial, goals):
        # 初始化初始节点与目标节点
        self.initial = Node(np.reshape(initial, (3, 3)), 0, "None", 0)  # 存入初始的Node状态
        self.goals = Node(np.reshape(goals, (3, 3)), 0, "None", 0)  # 存入终点的状态
        self.open_A = queue.PriorityQueue()  # 使用优先队列存储A启发性算法的表
        self.open_N = [self.initial]  # 暴搜系列就直接用list就好了
        self.visit = set()  # 用一个visit散列表记录所有的路径,这里用hash,会大大加快查询速度
        self.maxLength = 33  # 设置理论的最大的深度,为DFS服务,如果大于这个深度,便舍弃这个搜索分支。

    # 估价函数
    def scoreA(self, node, goals):  # 最朴素的计算方法,看是否在这个位子上
        """
        :param node: 现在的状态
        :param goals: 目标的状态
        :return:返回经过计算score的状态点
        """
        a = node.level  # 层数
        b = np.count_nonzero(node.data - goals.data)  # 计算不在位的数量
        node.score = a + b
        return node

    # 估价函数
    def scoreAStar(self, node, goals):  # 曼哈顿距离
        """
        :param node:现在的状态
        :param goals:目标状态
        :return:# 计算与目标所在为的数字的差值的绝对值之和
        """
        nowSt = node.data
        target = goals.data
        sum = np.abs(nowSt - target).sum()  # 各个位子上的点值的印象
        node.score = sum + node.level
        return node

    # 移动函数
    def moveStep(self, n, postion, row, col):
        """
        :param n:现在的状态
        :param postion:移动的方向,left,right,top,down四个方向
        :param row:现在可以移动的0的模块的列数
        :param col:现在可以移动的0的模块的行数
        :return:一个bool表示移动是否可以进行,一个二维矩阵表示移动后的状态
        """
        if (row == 0 and postion == "up") or (row == 2 and postion == "down") or (col == 0 and postion == "left") or (
                col == 2 and postion == "right"):
            return False, n
        if postion == "left":
            n[row, col], n[row, col - 1] = n[row, col - 1], n[row, col]
        elif postion == "right":
            n[row, col], n[row, col + 1] = n[row, col + 1], n[row, col]
        elif postion == "up":
            n[row, col], n[row - 1, col] = n[row - 1, col], n[row, col]
        elif postion == "down":
            n[row, col], n[row + 1, col] = n[row + 1, col], n[row, col]
        return True, n

    def getHash(self, arr):  # 传输进来二维数组
        """
        :param arr:传进来一个二维矩阵的一维状态表示
        :return:返回状态的hash数值
        """
        nowTag = str(arr[0, 0]) + str(arr[0, 1]) + str(arr[0, 2]) + str(arr[1, 0]) + str(arr[1, 1]) + str(
            arr[1, 2]) + str(arr[2, 0]) + str(arr[2, 1]) + str(arr[2, 2])
        return abs(hash(nowTag))  # 使用Python自带的hash函数+为了保证正数的abs绝对值函数

    def ifExist(self, three_result, visited):
        """
        :param three_result:当前的状态
        :param visited:访问记录表,哈希表
        :return:返回bool,查找到了true,没有查找到了False
        """
        if self.getHash(three_result) in visited:
            return True
        return False

    def havaSolution(self, arr):
        """
        :param arr:计算逆序对的就特性
        :return:0/1标志偶数,奇数特性
        """
        numList, sum = [], 0
        for i in range(3):
            for j in range(3):
                numList.append(arr[i, j])
        for index, val in enumerate(numList):
            if index < 9:
                for i in range(index, 9):
                    if val > numList[i] and numList[i] != 0:
                        sum += 1
        return sum % 2 == 1

    def FS(self, fType):
        """
        :param fType:搜索方法
        :return:bool,list,int 是否有解,有解的话返回丛起点到终点的路径,总的计算次数
        """
        countNum = 0  # 定义计算次数
        while self.open_N:
            countNum += 1
            # 初始化算子
            direction = ['up', 'down', 'right', 'left']  # 定义四个移动方向
            # 从open表中删除第一个状态并放入close表中
            n = self.open_N.pop(0)
            self.visit.add(self.getHash(n.data))  # 把访问过的点,放入vis表中,记录已经到达过这个点了
            if (n.data == self.goals.data).all():  # 寻找到最终的路径
                resultAll = []  # 最终的路径答案
                resultAll.append(n.data)
                while n.parent != "None":
                    n = n.parent
                    resultAll.append(n.data)
                resultAll.reverse()
                return True, resultAll, countNum
            # 生产n的所有子状态,并加入到open表后方
            postion = np.where(n.data == 0)  # 寻找到现在的
            if n.level >= self.maxLength:  # 如果大于了最大的深度,直接退出
                continue
            # 找到子状态
            for dire in direction:  # 移动四个方向
                copy_n = copy.deepcopy(n)  # 深拷贝一个状态,进行操作
                tag, nextNode = self.moveStep(copy_n.data, dire, postion[0], postion[1])  # 返回的二维矩阵信息
                if not tag or self.ifExist(nextNode, self.visit):  # 如果移动的方向错误或者已经在表中存在了,则跳过这个状态
                    continue
                if fType == "DFS":
                    self.open_N.insert(0, Node(nextNode, n.level + 1, n, 0))  # 从头插入,则直接就对应上来了栈的使用
                elif fType == "BFS":
                    self.open_N.append(Node(nextNode, n.level + 1, n, 0))  # 与DFS在这里不同,在后面插入
        return False, [], countNum

    def A(self, aType):
        """
        :param aType:A算法的分类
        :return:bool,list,int 是否有解,有解的话返回丛起点到终点的路径,总的计算次数
        """
        countNum = 0  # 定义计算次数
        self.open_A.put(self.initial)  # 用有限队列需要先push一个状态进去
        while not self.open_A.empty():
            countNum = countNum + 1
            direction = ['up', 'down', 'right', 'left']  # 定义四个方向
            n = self.open_A.get()
            self.visit.add(self.getHash(n.data))

            if (n.data == self.goals.data).all():  # 如果与目标状态完全相等,则进行return操作
                resultAll = []  # 设置答案列表
                resultAll.append(n.data)
                while n.parent != "None":
                    n = n.parent  # 递归向上寻找节点
                    resultAll.append(n.data)
                resultAll.reverse()  # 由于递归向上查找的过程时候,是反的,所以需要reverse一下
                return True, resultAll, countNum

            if n.level >= self.maxLength:
                continue
            postion = np.where(n.data == 0)
            # 找到子状态
            for p in direction:
                copy_n = copy.deepcopy(n)
                tag, nexNode = self.moveStep(copy_n.data, p, postion[0], postion[1])  # 输入现在的矩阵,移动方向,现在x与y坐标
                if not tag or self.ifExist(nexNode, self.visit):  # 直接跳出此次循环  不加入open表
                    continue
                if aType == "A":
                    score_t = self.scoreA(Node(nexNode, n.level + 1, n, 0), self.goals)  # A算法计算出评价分数
                    self.open_A.put(score_t)
                else:
                    score_t = self.scoreAStar(Node(nexNode, n.level + 1, n, 0), self.goals)  # A星宣发计算出评价分数
                    self.open_A.put(score_t)
        return False, [], countNum

    def startDo(self, type):
        """
        :param type:计算所使用的算法
        :return:bool,list,int,time 是否寻找了解,答案状态序列,状态搜寻的次数,运行所花费的时间
        """
        beginTime = time.time()
        resList = []
        tag = False
        countNum = 0
        if type == "DFS":
            print("运行中", type)
            tag, resList, countNum = self.FS(type)
        elif type == "BFS":
            print("运行中", type)
            tag, resList, countNum = self.FS(type)
        elif type == "A":
            print("运行中", type)
            tag, resList, countNum = self.A(type)
        elif type == "AStar":
            print("运行中", type)
            tag, resList, countNum = self.A(type)
        else:
            return False, resList, -1, 0  # 啥都没有返回False
        print("核心内部算法,运行时间:", time.time() - beginTime)
        print("计算次数:", countNum)
        return tag, resList, countNum, time.time() - beginTime
        # 返回信息介绍,int,list,int,double:表示是否找到解,一堆二维矩阵,计算的次数,计算所用时间

GUI部分:

import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtGui
import numpy as np
from multiprocessing.pool import ThreadPool
from concurrent.futures import ThreadPoolExecutor, as_completed
from algorithm import *


class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.pools = ThreadPoolExecutor(max_workers=100)  # 设置线程池的最大容量

        self.ranS = QPushButton("随机生成", self)
        self.S1 = QLineEdit(self)
        self.S2 = QLineEdit(self)
        self.S3 = QLineEdit(self)
        self.S4 = QLineEdit(self)
        self.S5 = QLineEdit(self)
        self.S6 = QLineEdit(self)
        self.S7 = QLineEdit(self)
        self.S8 = QLineEdit(self)
        self.S9 = QLineEdit(self)
        self.ranE = QPushButton("随机生成", self)
        self.E1 = QLineEdit(self)
        self.E2 = QLineEdit(self)
        self.E3 = QLineEdit(self)
        self.E4 = QLineEdit(self)
        self.E5 = QLineEdit(self)
        self.E9 = QLineEdit(self)
        self.E8 = QLineEdit(self)
        self.E7 = QLineEdit(self)
        self.E6 = QLineEdit(self)  # 上面全是九宫格的设置

        self.clear = QPushButton("ClearAll", self)

        self.DFSButton = QPushButton("DFS", self)
        self.BFSButton = QPushButton("BFS", self)
        self.AButton = QPushButton("A", self)
        self.AStarButton = QPushButton("A*", self)  # 算法选择计算的button
        self.BFSTimeError = QLabel(self)
        self.ATimeError = QLabel(self)
        self.AStarTimeError = QLabel(self)
        self.DFSTimeError = QLabel(self)  # 提示计算超时的error
        self.label1 = QLabel("起|\n始|\n位|\n置|\n", self)
        self.label2 = QLabel("终|\n点|\n位|\n置|\n", self)
        self.label3 = QLabel("步|\n骤|\n显|\n示|\n", self)
        self.label4 = QLabel("算|\n法|\n具|\n体|\n细|\n节|\n", self)

        self.errorMess = "TimeLimitError!\nLastRuntime>60s"  # 超时错误信息显示
        self.stepShow = QTextBrowser(self)  # 显示每一步的走向
        self.detailShow = QTextBrowser(self)  # 显示使用这个算法后的计算过程详情
        self.buttonFont = QtGui.QFont()
        self.inputFont = QtGui.QFont()
        self.labelFont = QtGui.QFont()  # 设置三种不同的字体
        self.initUI()

    def initUI(self):
        """
        :return:初始化各种配置
        """
        self.inputFont.setFamily("Arial")  # 括号里可以设置成自己想要的其它字体
        self.inputFont.setPointSize(15)  # 括号里的数字可以设置成自己想要的字体大小

        self.buttonFont.setFamily("Arial")  # 括号里可以设置成自己想要的其它字体
        self.buttonFont.setPointSize(12)  # 括号里的数字可以设置成自己想要的字体大小

        self.labelFont.setPointSize(10)

        self.ranS.resize(130, 70)
        self.ranS.move(40, 50)
        self.ranS.setFont(self.buttonFont)

        self.S1.resize(100, 100)
        self.S1.move(200, 30)
        self.S1.setTextMargins(40, 25, 25, 25)
        self.S1.setFont(self.inputFont)

        self.S2.resize(100, 100)
        self.S2.move(300, 30)
        self.S2.setTextMargins(40, 25, 25, 25)
        self.S2.setFont(self.inputFont)

        self.S3.resize(100, 100)
        self.S3.move(400, 30)
        self.S3.setTextMargins(40, 25, 25, 25)
        self.S3.setFont(self.inputFont)

        self.S4.resize(100, 100)
        self.S4.move(200, 130)
        self.S4.setTextMargins(40, 25, 25, 25)
        self.S4.setFont(self.inputFont)

        self.S5.resize(100, 100)
        self.S5.move(300, 130)
        self.S5.setTextMargins(40, 25, 25, 25)
        self.S5.setFont(self.inputFont)

        self.label1.resize(50, 150)
        self.label1.move(172, 24)
        self.label1.setFont(self.labelFont)

        self.label2.resize(50, 150)
        self.label2.move(772, 24)
        self.label2.setFont(self.labelFont)

        self.label3.resize(50, 150)
        self.label3.move(265, 350)
        self.label3.setFont(self.labelFont)

        self.label4.resize(50, 180)
        self.label4.move(865, 350)
        self.label4.setFont(self.labelFont)

        self.S6.resize(100, 100)
        self.S6.move(400, 130)
        self.S6.setTextMargins(40, 25, 25, 25)
        self.S6.setFont(self.inputFont)

        self.S7.resize(100, 100)
        self.S7.move(200, 230)
        self.S7.setTextMargins(40, 25, 25, 25)
        self.S7.setFont(self.inputFont)

        self.S8.resize(100, 100)
        self.S8.move(300, 230)
        self.S8.setTextMargins(40, 25, 25, 25)
        self.S8.setFont(self.inputFont)

        self.S9.resize(100, 100)
        self.S9.move(400, 230)
        self.S9.setTextMargins(40, 25, 25, 25)
        self.S9.setFont(self.inputFont)

        self.ranE.move(640, 50)
        self.ranE.resize(130, 70)
        self.ranE.setFont(self.buttonFont)

        self.clear.move(640, 250)
        self.clear.resize(130, 70)
        self.clear.setFont(self.buttonFont)

        self.E1.resize(100, 100)
        self.E1.move(800, 30)
        self.E1.setTextMargins(40, 25, 25, 25)
        self.E1.setFont(self.inputFont)

        self.E2.resize(100, 100)
        self.E2.move(900, 30)
        self.E2.setTextMargins(40, 25, 25, 25)
        self.E2.setFont(self.inputFont)

        self.E3.resize(100, 100)
        self.E3.move(1000, 30)
        self.E3.setTextMargins(40, 25, 25, 25)
        self.E3.setFont(self.inputFont)

        self.E4.resize(100, 100)
        self.E4.move(800, 130)
        self.E4.setTextMargins(40, 25, 25, 25)
        self.E4.setFont(self.inputFont)

        self.E5.resize(100, 100)
        self.E5.move(900, 130)
        self.E5.setTextMargins(40, 25, 25, 25)
        self.E5.setFont(self.inputFont)

        self.E6.resize(100, 100)
        self.E6.move(1000, 130)
        self.E6.setTextMargins(40, 25, 25, 25)
        self.E6.setFont(self.inputFont)

        self.E7.resize(100, 100)
        self.E7.move(800, 230)
        self.E7.setTextMargins(40, 25, 25, 25)
        self.E7.setFont(self.inputFont)

        self.E8.resize(100, 100)
        self.E8.move(900, 230)
        self.E8.setTextMargins(40, 25, 25, 25)
        self.E8.setFont(self.inputFont)

        self.E9.resize(100, 100)
        self.E9.move(1000, 230)
        self.E9.setTextMargins(40, 25, 25, 25)
        self.E9.setFont(self.inputFont)

        self.DFSButton.move(50, 380)
        self.DFSButton.resize(130, 70)
        self.DFSButton.setFont(self.buttonFont)

        self.DFSTimeError.move(50, 450)
        self.DFSTimeError.resize(200, 50)
        # self.DFSTimeError.setText("TimeLimitError!\nRuntime>60s")
        self.DFSTimeError.setStyleSheet("color:red")

        self.BFSButton.move(50, 530)
        self.BFSButton.resize(130, 70)
        self.BFSButton.setFont(self.buttonFont)

        self.BFSTimeError.move(50, 600)
        self.BFSTimeError.resize(200, 50)
        # self.BFSTimeError.setText("TimeLimitError!\nRuntime>60s")
        self.BFSTimeError.setStyleSheet("color:red")

        self.AButton.move(50, 680)
        self.AButton.resize(130, 70)
        self.AButton.setFont(self.buttonFont)

        self.ATimeError.move(50, 750)
        self.ATimeError.resize(200, 50)
        # self.ATimeError.setText("TimeLimitError!\nRuntime>60s")
        self.ATimeError.setStyleSheet("color:red")

        self.AStarButton.move(50, 830)
        self.AStarButton.resize(130, 70)
        self.AStarButton.setFont(self.buttonFont)

        self.AStarTimeError.move(50, 900)
        self.AStarTimeError.resize(200, 50)
        # self.AStarTimeError.setText("TimeLimitError!\nRuntime>60s")
        self.AStarTimeError.setStyleSheet("color:red")

        self.stepShow.resize(470, 620)
        self.stepShow.move(300, 350)

        self.detailShow.resize(470, 620)
        self.detailShow.move(900, 350)

        # btn1.clicked.connect(self.buttonClicked)
        # btn2.clicked.connect(self.buttonClicked)

        self.ranS.clicked.connect(self.ranSClicked)
        self.ranE.clicked.connect(self.ranEClicked)

        self.DFSButton.clicked.connect(lambda: self.calcu("DFS"))
        self.BFSButton.clicked.connect(lambda: self.calcu("BFS"))
        self.AButton.clicked.connect(lambda: self.calcu("A"))
        self.AStarButton.clicked.connect(lambda: self.calcu("AStar"))
        self.clear.clicked.connect(self.clearAll)
        # self.AStarButton.clicked.connect(self.test)

        self.setGeometry(300, 200, 1400, 1000)
        self.setWindowTitle('八数码问题解决工具')  # 设置框框的名称
        self.show()  # 显示总的框框

    def getS(self):
        """
        :return:bool,list 是否成功获得九个数字,并且这九个数字是否是合理的;这九个数字
        """
        try:
            tempS1 = int(self.S1.text())
            tempS2 = int(self.S2.text())
            tempS3 = int(self.S3.text())
            tempS4 = int(self.S4.text())
            tempS5 = int(self.S5.text())
            tempS6 = int(self.S6.text())
            tempS7 = int(self.S7.text())
            tempS8 = int(self.S8.text())
            tempS9 = int(self.S9.text())
            if ((8 < tempS1 < 0) or (8 < tempS2 < 0) or (8 < tempS3 < 0) or (8 < tempS4 < 0) or (8 < tempS5 < 0) or (
                    8 < tempS6 < 0) or (8 < tempS7 < 0) or (8 < tempS8 < 0) or (
                    8 < tempS9 < 0)):
                return False, []
            nums = [tempS1, tempS2, tempS3, tempS4, tempS5, tempS6, tempS7, tempS8, tempS9]
            return True, nums
        except:
            return False, []

    def setS(self, nums):  # 通过一维数组设置GUI界面上的终止位置
        """
        :param nums:设置的初始矩阵信息
        :return:null
        """
        self.S1.setText(str(nums[0]))
        self.S2.setText(str(nums[1]))
        self.S3.setText(str(nums[2]))
        self.S4.setText(str(nums[3]))
        self.S5.setText(str(nums[4]))
        self.S6.setText(str(nums[5]))
        self.S7.setText(str(nums[6]))
        self.S8.setText(str(nums[7]))
        self.S9.setText(str(nums[8]))

    def getE(self):
        """
        :return:bool,list 是否成功获得九个数字,并且这九个数字是否是合理的;这九个数字
        """
        try:
            tempS1 = int(self.E1.text())
            tempS2 = int(self.E2.text())
            tempS3 = int(self.E3.text())
            tempS4 = int(self.E4.text())
            tempS5 = int(self.E5.text())
            tempS6 = int(self.E6.text())
            tempS7 = int(self.E7.text())
            tempS8 = int(self.E8.text())
            tempS9 = int(self.E9.text())
            if ((8 < tempS1 < 0) or (8 < tempS2 < 0) or (8 < tempS3 < 0) or (8 < tempS4 < 0) or (8 < tempS5 < 0) or (
                    8 < tempS6 < 0) or (8 < tempS7 < 0) or (8 < tempS8 < 0) or (
                    8 < tempS9 < 0)):  # 如果得到的数字不在0~9这个范围内,返回错误
                return False, []
            nums = [tempS1, tempS2, tempS3, tempS4, tempS5, tempS6, tempS7, tempS8, tempS9]
            return True, nums
        except:
            return False, []

    def setE(self, nums):  # 通过一维数组设置GUI界面上的其实数组
        """
        :param nums:设置的终点矩阵信息
        :return:null
        """
        self.E1.setText(str(nums[0]))
        self.E2.setText(str(nums[1]))
        self.E3.setText(str(nums[2]))
        self.E4.setText(str(nums[3]))
        self.E5.setText(str(nums[4]))
        self.E6.setText(str(nums[5]))
        self.E7.setText(str(nums[6]))
        self.E8.setText(str(nums[7]))
        self.E9.setText(str(nums[8]))

    def veriNum(self, nums):  # 检查数组是否合理
        """
        :param nums:一维九个数字的矩阵
        :return:bool,表示数组是否合理
        """
        try:
            tags = [False, False, False, False, False, False, False, False, False]  # 使用类似桶排序的方法,一个位子表示一个数字
            for a in nums:
                tags[a] = True
            for a in tags:
                if not a:
                    return False  # 0~9有一个数字没有,则返回错误
            return True
        except:  # 中间只要有哪一步无法进行直接退出报错
            return False

    def ranSClicked(self):
        """
        :return:随机生成起始矩阵
        """
        tag, numsE = self.getE()  # 初始矩阵与终点矩阵还是具有相对的联系的,随意设置的话很可能导致浪费使用者的时间
        if tag and self.veriNum(numsE):
            arr = np.array(range(0, 9, 1))
            np.random.shuffle(arr)
            while abs(arr - numsE).sum() > 9:  # 如果终点矩阵存在,则随机设置的起始矩阵需要让曼哈顿距离小于9,确保搜索的深度与简单性
                np.random.shuffle(arr)
            self.setS(arr.data)
        else:
            arr = np.array(range(0, 9, 1))  # 如果终点矩阵不满足题设要求,起始矩阵就真随机生成
            np.random.shuffle(arr)
            self.setS(arr.data)

    def ranEClicked(self):
        """
        :return:随机生成终止数组
        """
        tag, numsS = self.getS()  # 初始矩阵与终点矩阵还是具有相对的联系的,随意设置的话很可能导致浪费使用者的时间
        if tag and self.veriNum(numsS):
            arr = np.array(range(0, 9, 1))
            np.random.shuffle(arr)
            while abs(arr - numsS).sum() > 9:  # 如果起始矩阵存在,则随机设置的起始矩阵需要让曼哈顿距离小于9,确保搜索的深度与简单性
                np.random.shuffle(arr)
            self.setE(arr.data)
        else:
            arr = np.array(range(0, 9, 1))  # 如果起始矩阵不满足题设要求,终点纠正就真随机生成
            np.random.shuffle(arr)
            self.setE(arr.data)

    def setError(self, cType, data):
        """
        :param cType:哪一个算法报的错误
        :param data:需要设置的提示信息
        :return:
        """
        if cType == "DFS":
            self.DFSTimeError.setText(data)
        elif cType == "BFS":
            self.BFSTimeError.setText(data)
        elif cType == "A":
            self.ATimeError.setText(data)
        elif cType == "AStar":
            self.AStarTimeError.setText(data)

    def clearAll(self):
        """
        :return:把所有的框框全部清空
        """
        self.detailShow.setText("")
        self.stepShow.setText("")
        self.setE(["", "", "", "", "", "", "", "", ""])
        self.setS(["", "", "", "", "", "", "", "", ""])

    def Task(self, S, E, cType):
        """
        :param S:初始矩阵
        :param E:终点矩阵
        :param cType:计算所使用的算法
        :return:bool,list,int,time 是否搜寻到了解,答案list,搜索的次数,运算所使用的的时间
        """
        temp = solution(S, E)
        tag, resList, countNum, timeLen = temp.startDo(cType)
        return tag, resList, countNum, timeLen

    def getOneStep(self, nums):
        """
        :param nums:一个一维数组,表示现在的状态
        :return:String 表示当前这个状态下的string表示
        """
        ans = str(nums[0]) + " " + str(nums[1]) + " " + str(nums[2]) + "\n"
        ans += str(nums[3]) + " " + str(nums[4]) + " " + str(nums[5]) + "\n"
        ans += str(nums[6]) + " " + str(nums[7]) + " " + str(nums[8]) + "\n"
        return ans

    def getAllSteps(self, nums):
        """
        :param nums:答案序列,是一堆二维矩阵
        :return:String 一长串窗台转移答案序列
        """
        ans = ""
        cnt = 0
        for x in nums:
            ans += "step" + str(cnt) + "->\n"
            ans += str(x[0, 0]) + " " + str(x[0, 1]) + " " + str(x[0, 2]) + "\n"
            ans += str(x[1, 0]) + " " + str(x[1, 1]) + " " + str(x[1, 2]) + "\n"
            ans += str(x[2, 0]) + " " + str(x[2, 1]) + " " + str(x[2, 2]) + "\n"
            cnt += 1
        return ans

    def startTask(self, numsS, numsE, cType):
        """
        :param numsS:起始矩阵
        :param numsE:终点矩阵
        :param cType:所使用的算法类型
        :return:bool 判断在限定时间内,计算是否成功
        """
        temp = self.pools.submit(self.Task, numsS, numsE, cType)  # 把计算放到一个线程中
        strS = self.getOneStep(numsS)
        strE = self.getOneStep(numsE)
        simpleDetail = "使用算法:" + cType + "\n"
        simpleDetail += "起始矩阵:\n" + strS
        simpleDetail += "终止矩阵:\n" + strE  # 以上都是获得GUI显示的信息
        try:  # 这里会阻塞,不可以放在这里!
            tag, resList, countNum, timeLen = temp.result(timeout=60)  # 使用threadpool中的timeout参数实现阻塞等待
            timeLen = round(timeLen, 3)
            print("所计算次数:", countNum)
            print("所花费时间:", timeLen)
            tagSepa = "------------------------------------------------"
            allSteps = "使用算法:" + cType + "\n" + self.getAllSteps(resList) + tagSepa
            allDetail = simpleDetail
            allDetail += "移动步骤:" + str(len(resList) - 1) + "\n"
            allDetail += "计算次数:" + str(countNum) + "\n"
            allDetail += "花费时间:" + str(timeLen) + "s\n"
            allDetail += tagSepa
            print(allDetail)
            self.stepShow.append(allSteps)  # 设置步骤的细节
            self.detailShow.append(allDetail)  # 设置算法运行的细节,可以运行到这里说明,在限定的时间运行完毕了
            return True
        except:  # 触发这里的条件:线程的运行时间过长,超过了60s
            print("运行超时!!!")
            self.setError(cType, self.errorMess)
            return False

    def calcu(self, cType):
        """
        :param cType:计算所使用的算法
        :return:null
        使用线程里面套用线程+线程池的方式,实现阻塞定时!
        """
        tag1, numsS = self.getS()  # 获得初始矩阵
        tag2, numsE = self.getE()  # 获得终点矩阵
        print(numsS)
        print(numsE)
        self.setError(cType, "")  # 在启动计算之前,把之前的error框框清空
        if tag1 and tag2 and self.veriNum(numsS) and self.veriNum(numsE):  # 通过了第一步验算,这两个矩阵是不是可以通过验算
            way = solution(numsS, numsE)
            if (way.havaSolution(way.initial.data) != way.havaSolution(way.goals.data)):  # 判断是有有解
                errorBox = QMessageBox(QMessageBox.Warning, '错误', '该情况没有解!')
                errorBox.resize(60, 60)
                errorBox.exec_()
            else:  # 下面开始进行计算了
                self.pools.submit(self.startTask, numsS, numsE, cType)  # 把计算过程放到一个线程中
        else:  # 提示没有解
            errorBox = QMessageBox(QMessageBox.Warning, '错误', '起点和终点矩阵错误!')
            errorBox.resize(80, 60)
            errorBox.exec_()


if __name__ == '__main__':
    app = QApplication(sys.argv)  # 开始运行整个窗口
    ex = Example()
    sys.exit(app.exec_())

自己GUI界面做的是真的简洁呀。。。不忍吐槽自己了,大家凑合着看吧。

为了满足学校的实验要求,注释已经全部打上去了,应该是面面俱到了吧? 

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值