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")