python实现创建数独与验证数独是否合法

sudoku类来实现一个数独的基本方法

import math
import random

class Sudoku(object):
    def __init__(self,num):
        self.num = num
    # 随机生成一个坐标
    def getPositionXY(self)->list:
        # 运用随机数生成0到8中间的数有个向下取整的操作
        x = math.floor(random.random() * 9)
        y = math.floor(random.random() * 9)
        return [x, y]

    # 获取不重复的坐标(去重)
    def getPosition(self,num:int)->list:
        # 存储坐标的列表
        position = []
        # 随机生成num个坐标存储到列表中
        for _ in range(num):
            position.append(self.getPositionXY())

        # 复制一个空列表用来存放去重后的坐标
        positionCopy = []
        # 坐标去重
        while(len(positionCopy) < len(position)):
            # 获取每一项
            for item in position:
                # 判断每一项是否在去重后的坐标里
                if( item not in positionCopy):
                    # 如果不在去重后的列表就添加到列表
                    positionCopy.append(item)
                else:
                    # 如果在列表中那么重新生成一个坐标
                    position.remove(item)
                    position.append(self.getPositionXY())

                    # 当去重后的坐标的长度为生成的坐标的长度
                if(len(positionCopy) == len(position)):
                    break
        # 返回去重后的拷贝坐标列表
        return positionCopy

    # 运用列表解析生成n个随机的数
    def getSudoku(self,num:int)->list:
        list = [math.floor(random.random() * 9 + 1) for _ in range(num)]
        return list

    # 获取数独的位置
    def pairPosition(self)->list:
        # 配对后的键值对列表
        pairList = []
        # 将获取的不重复的坐标存储到坐标列表中
        positionList = self.getPosition(self.num)
        sudokuList = self.getSudoku(self.num)
        # 将随机生成的数与随机生成的坐标进行配对
        for index in range(self.num):
            # 数字作为键坐标作为值存储到字典中
            pairList.append({sudokuList[index]: positionList[index]})
        return pairList

    # 设置数独的位置
    def setPosition(self,position)->list:
        # 列表解析生成数独盘
        sudokuDisk = [[0 for _ in range(9)] for _ in range(9)]
        
        for item in position:
            for (k,v) in item.items():
                sudokuDisk[v[0]][v[1]] = k
        print("-"*27+"耿洪雨"+"-"*28)
        return sudokuDisk

    # 判断每一行是否是合法的
    def rowIsVaild(self,sudokuDisk:list,mark=False)->list:
        numList = []
        emptyList = []
        for _index in range(len(sudokuDisk)):
            # 判断每一行是否有相同的数
            for _ in sudokuDisk[_index]:
                if (_ != 0):
                    numList.append(_)
            # 是否打印每一行的数字
            if (mark == True):
                print(numList)
            # 遍历数字列表去重
            for _item in numList:
                # 如果该数字不在空列表里就添加进去
                if (_item not in emptyList):
                    emptyList.append(_item)
                # 一旦出现在空列表里的就证明是重复的数字直接return False
                else:
                    print(f"第{_index+1}行出现相同数字{_item}")
                    return False
            # 遍历完每一列之后所有列表置空等待下一列的遍历
            numList = []
            emptyList = []
        return True
    # 判断每一列是否是合法的
    def colIsVaild(self, sudokuDisk:list,mark=False)->list:
        # 存储每一列的空列表
        # colList = []
        # 存储每一列的生成的随机数字
        numList = []
        # 数字去重后的列表
        emptyList = []
        # 因为每一列只有9个数 所以遍历9次
        for index in range(9):
            # 双层循环拿到每一列
            for _index in  range(9):
                # colList.append(sudokuDisk[_index][index])
                if (sudokuDisk[_index][index]!= 0):
                    numList.append(sudokuDisk[_index][index])
            '''
            # 遍历生成的每一列的列表
            for _ in colList:
                # 如果不为0就添加到生成的随机数的列表
                if (_ != 0):
                    numList.append(_)
            '''
            # 是否打印每一列的数字
            if (mark == True):
                print(numList)
             # 遍历数字列表去重
            for _item in numList:
                # 如果该数字不在空列表里就添加进去
                if (_item not in emptyList):
                    emptyList.append(_item)
                # 一旦出现在空列表里的就证明是重复的数字直接return False
                else:
                    print(f"第{index+1}列出现相同数字{_item}")
                    return False
            # 遍历完每一列之后所有列表置空等待下一列的遍历
            numList = []
            # colList = []
            emptyList = []
        return True

        # 判断每一个宫格是否合法
    # 判断每一宫是否是合法的
    def unitIsVaild(self,sudokuDisk:list,mark =False)->list:
        # 存储每宫的数
        # unitList = []
        # 存储每一宫的数字
        numList = []
        # 数字去重后的列表
        emptyList = []
        # 行号的基数
        rowIndex = 0
        # 列号的基数
        colIndex = 0
        # 循环退出的标志
        flag = True
        # 第几个宫出现相同
        count = 1
        while(flag):
            # 首先生成0行0列1列2列,然后1行0列1列2列就可以拿到第一个宫
            for index in range(rowIndex*3,(rowIndex*3) + 3):
                for _index in range(colIndex*3,(colIndex*3) + 3):
                    # 将第一个宫的数存储起来
                    # unitList.append(sudokuDisk[index][_index])
                    if (sudokuDisk[index][_index] != 0):
                        numList.append(sudokuDisk[index][_index])
            '''
            # 遍历第一个宫
            for _ in unitList:
                # 如果不为零就将其加入到数字列表中,也就是自己随机生成的数字
                if (_ != 0):
                    numList.append(_)
            '''
            # 是否打印每一宫
            if(mark == True):
                print(numList)
            # 遍历数字列表去重
            for _item in numList:
                # 如果该数字不在空列表里就添加进去
                if (_item not in emptyList):
                    emptyList.append(_item)
                # 一旦出现在空列表里的就证明是重复的数字直接return False
                else:
                    print(f"第{count}宫出现相同数字{_item}(左上角为第一个宫,左下角为第三个宫,右上角为第七个宫,右下角为第九个宫以此类推)")
                    return False
            # 此处可以打印每一宫的数字numList
            # print(numList)

            # 遍历完每一宫之后所有列表置空
            # unitList = []
            numList = []
            emptyList = []
            # 第一宫遍历完成后如果行号基数小于2那么久自增1
            if(rowIndex<2):
                rowIndex += 1
                count += 1
            # 如果行号基数等于2并且列号基数小于2那么列号基数自增1,
            # 并且行号基数归零,因此才可以从上面往下遍历
            elif(rowIndex==2 and colIndex<2):
                colIndex += 1
                rowIndex = 0
                # 宫的序号加1
                count += 1
            # 如果列号基数和行号基数都为2证明所有宫格遍历完毕将标志置为false退出循环
            elif(rowIndex==2 and colIndex ==2):
                flag = False
        # 只要能退出循环的就证明一定是True
        return True

    # 判断是否是一个合法的数独
    def isVaild(self,sudokuDisk:list)->list:
        # 当每一行每一列每一宫都返回True时就是合法的就返回True否则返回False
        if(self.rowIsVaild(sudokuDisk) and self.colIsVaild(sudokuDisk) and self.unitIsVaild(sudokuDisk)):
            return True
        return False

主程序


from sudoku import Sudoku

if __name__=="__main__":
    again = "Y"
    while (again =="Y" or again =="y"):
        num = input("请输入一个25-70之间的数字来生成N个随机数")
        try:
            int(num)
            if(int(num)<25 or int(num) >70):
                print("请确保数字位于25-70之间!!!")
                continue
        except:
            print("请确定输入的是数字!!!")
            continue
        
        # 生成n个随机的数
        sudoku = Sudoku(int(num))
        # 随机生成n个数的随机坐标
        position = sudoku.pairPosition()
        # 拿到数独的每个数的位置
        sudokuDisk = sudoku.setPosition(position)
        print("-----------------------生成的数独样式------------------------")
        # 遍历数独盘展示在控制台
        for item in sudokuDisk:
            print(f"                {item}")
        
        print("-----------------------此数独是否合法------------------------")
        print(sudoku.isVaild(sudokuDisk))
        again = input("是否重新生成? 请输入 Y/N")

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值