master
zart2007 2 years ago
parent a8b4073827
commit f09bceda49

@ -0,0 +1,86 @@
# -*- encoding: utf-8 -*-
'''
@File : data.py
@License : (C)Copyright 2018-2022
@Modify Time @Author @Version @Desciption
------------ ------- -------- -----------
2022/12/22 9:35 zart20 1.0 None
'''
import numpy as np
import random
from collections import Counter
def Init():
# 构建9*9数组
martix = np.zeros((9, 9), dtype='i1') # 初始化9*9数组并赋值0
for row in range(0, 9):
for col in range(0, 9):
value = random.randint(0,9)
martix[row, col] = value # 给9*9数组martix随机赋值
return martix
def Judge(martix):
# 计算整个数组是否符合要求
for row in range(0, 9):
for col in range(0, 9):
if martix[row][col] == 0:
continue
x, y = row // 3, col // 3 # [x, y] 为宫位置, 即九个小格子为一个宫
row_martix = martix[row, :] # [row, col] 所在行的数字数组
row_set = set(row_martix) # [row, col] 所在行的数字集合
col_martix = martix[:, col] # [row, col] 所在列的数字数组
col_set = set(col_martix) # [row, col] 所在列的数字集合
block_martix = martix[x * 3: x * 3 + 3, y * 3: y * 3 + 3].reshape(9) # [row, col] 所在的宫的数字数组
block_set = set(block_martix) # [row, col] 所在的宫的数字集合
if len(row_martix) != (len(row_set) + Counter(row_martix)[0]) or len(col_martix) != \
(len(col_set) + Counter(col_martix)[0]) or len(block_martix) != (
len(block_set) + Counter(block_martix)[0]):
return False
return True
def GetPossible(martix, row, col):
# 获取一个格子里可能可以填的值
Nums = {1, 2, 3, 4, 5, 6, 7, 8, 9}
x, y = row // 3, col // 3
rowSet = set(martix[row, :]) # [row, col] 所在行的数字集合
colSet = set(martix[:, col]) # [row, col] 所在列的数字集合
blockSet = set(martix[x * 3: x * 3 + 3, y * 3: y * 3 + 3].reshape(9)) # [row, col] 所在宫的数字集合
return Nums - rowSet - colSet - blockSet
def Solve(martix):
"""求解数组"""
for row in range(9):
for col in range(9):
if martix[row, col] == 0:
possible = GetPossible(martix, row, col) # 所有的可能的数字
for value in possible:
martix[row, col] = value # 将可能的数组填入
if Solve(martix): # 继续深度优先遍历填入数字
return True # 填完最后一个数字
martix[row, col] = 0 # 如果当前填入的数字会导致后面无解则依然填入0表示空白待填
return False
# 当所有的数字填完,数独求解完毕
return True
def InitMartix():
"""创建一个符合要求的带空数组"""
martix = np.zeros((9, 9), dtype='i1')
martix[0][0] = 1 # 手动设置一个初始值
martix[0][3] = 2
martix[3][3] = 1
martix[6][6] = 1
Solve(martix) # 求解整个数独
for i in range(9):
for j in range(9):
if i == j:
martix[i][j] = 0
return martix

@ -0,0 +1,7 @@
1、实训总结:(请描述遇到的问题,解决思路,以及问题是否解决)▁▁▁
11
2、反馈建议▁▁▁
答:

@ -0,0 +1,24 @@
# -*- encoding: utf-8 -*-
'''
@File : fkpc.py
@License : (C)Copyright 2018-2022
@Modify Time @Author @Version @Desciption
------------ ------- -------- -----------
2022/12/30 15:34 zart20 1.0 None
'''
old = [' 1、实训总结:(请描述遇到的问题,解决思路,以及问题是否解决)▁▁▁\n', ' 答:\n', '\n', '\n', '\n', ' 2、反馈建议▁▁▁\n', ' 答:']
count = 0
with open("example.txt", "r", encoding="utf8") as f:
text = f.readlines()
ol = ''.join(old)
ne = ''.join(text)
if ol != ne:
print("反馈添加成功。")
print("感谢反馈!")
print("恭喜通关!")
else:
print("请填写反馈!")

@ -0,0 +1,314 @@
# -*- encoding: utf-8 -*-
'''
@File : gameui.py
@License : (C)Copyright 2018-2022
@Modify Time @Author @Version @Desciption
------------ ------- -------- -----------
2022/12/22 10:01 zart20 1.0 None
'''
import time
from data import *
import pygame
# 定义颜色
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
ORANGE = (255, 140, 0) # 橘色
YELLOW = (250, 224, 103) # 蛋黄
SILVER = (192, 192, 192) # 银色
RED = (200, 0, 0)
bc = 40 # 定义全局边长
class MyTimer:
def __init__(self):
self.elapsed = 0.0
self.running = False
self.last_start_time = None
def start(self):
if not self.running:
self.running = True
self.last_start_time = time.time()
def pause(self):
if self.running:
self.running = False
self.elapsed += time.time() - self.last_start_time
def get_elapsed(self):
elapsed = self.elapsed
if self.running:
elapsed += time.time() - self.last_start_time
return '{:>2.0f}{:>2.0f}'.format(elapsed // 60, elapsed % 60)
def GuiForm():
pygame.init() # pygame 的初始化
pygame.display.set_caption("数独")
form = pygame.display.set_mode((840, 610)) # 主窗口
form.fill(ORANGE) # 填充橘色
pygame.display.update()
return form
# form = GuiForm()
def rect_draw(bc, row, col):
'''画一个小方格对象'''
# row = row-1
# col = col-1
face = pygame.Surface((bc, bc)) # 创建一个Surface对象
block_color = [3, 4, 5] # 显色宫格依据
logi_row = row in block_color and col in block_color # 显色逻辑
logi_col = row in block_color or col in block_color # 显色逻辑
if not logi_row and logi_col:
face.fill(YELLOW)
else:
face.fill(WHITE) # 为对象填充颜色
return face
def show_face(form, face, bc, row, col, ):
"""将小方格face在form上显示出来"""
form.blit(face, (row * (bc + 3) + 50, col * (bc + 3) + 50))
pygame.display.update()
def refresh(form:pygame.Surface,martix,u_martix, note_martix):
# 将整个数组刷新一遍
for i in range(9):
for j in range(9):
face = rect_draw(40, i, j) # 创建一个基于位置的小方格
if u_martix[j][i] != 0:
if u_martix[j][i] != 11:
face1 = number_draw(face, martix, u_martix, bc, i, j)
else:
face.fill(SILVER)
for note in note_martix: # 如果这个空格有笔记直接覆盖清空笔记
if note[0] == i and note[1] == j:
possible = note[2]
face1 = possible_num(bc, i, j, possible)
show_face(form, face1, bc, i, j)
else:
show_face(form, face, bc, i, j)
def xianse(form,martix, u_martix, x, y, note_martix=None):
# 更新单个单元格为银色
if note_martix is None:
note_martix = list()
if x >= 1 and y >= 1:
i = x - 1 # 映射坐标时加了一现在要减掉
j = y - 1
face = rect_draw(bc, i, j) # 创建一个基于位置的小方格
face.fill(SILVER, (3, 3, 34, 34))
if u_martix[j][i] != 0:
if u_martix[j][i] != 11:
number_draw(face, martix, u_martix, bc, i, j)
else:
# face.fill(SILVER)
for note in note_martix: # 如果这个空格有笔记直接覆盖清空笔记
if note[0] == i and note[1] == j:
possible = note[2]
face = possible_num(bc, x, y, possible)
# show_face(form,face,bc,i,j)
show_face(form, face, bc, i, j)
def mini_rect_draw(face, bc, possible):
"""单独一个格子里的小数字"""
num_font = pygame.font.SysFont('幼圆', 16, True) # 加载系统字体
bc1 = bc # 当出现空集时用于定位
bc = int(bc / 3)
n = 1
for i in range(3):
for j in range(3):
mini = pygame.Surface((bc, bc)) # 创建Surface对象
mini.set_colorkey([0, 0, 0]) # 设置透明色
mini = mini.convert_alpha() # 设置透明色
if possible: # 在用户已填的部分有可能导致部分格子无解,所以先加一个判断
for k in possible:
if n == k:
num_text = num_font.render(f"{k}", False, (109, 45, 250)) # 创建字体
rel = num_text.get_rect()
mini.blit(num_text, (int((bc - rel[2]) / 2), int((bc - rel[3]) / 2))) # 数字显示居中
n += 1
face.blit(mini, (i * bc, j * bc))
else:
num_text = num_font.render(f"{None}", False, (109, 45, 250))
rel = num_text.get_rect()
face.blit(num_text, (int((bc1 - rel[2]) / 2), int((bc1 - rel[3]) / 2)))
return face
def possible_num(bc, row, col, possible):
"""显示一个格子的可能值"""
row = row - 1
col = col - 1
face = rect_draw(bc, row, col)
face.fill(SILVER)
mface = mini_rect_draw(face, bc, possible)
return mface
def number_draw(face, martix, u_martix, bc, row, col):
"""向小格子里画数字"""
num_font = pygame.font.SysFont('幼圆', 32, True) # 加载系统字体
if martix[col,row] == 0:
if u_martix[col,row] not in GetPossible(martix,col,row): # 判断是否符合数组要求
print((col,row), GetPossible(martix, col, row))
num_text = num_font.render(f"{u_martix[col][row]}", True, RED) # 不符合要求显示红色
else:
num_text = num_font.render(f"{u_martix[col][row]}", True, BLACK) # 创建字体
else:
num_text = num_font.render(f"{u_martix[col][row]}", True, BLACK) # 创建字体
rect_l = num_text.get_rect() # 获取字体边长大小
face.blit(num_text, (int((bc - rect_l[2]) / 2), int(bc - rect_l[3]) / 2)) # 数字显示居中
return face
def control_number(form, bc, color1=SILVER, color2=WHITE):
# 0-9 按键控制
for num in range(9):
control_number_xs(form, bc, num, color1, color2)
def control_number_xs(form, bc, num, color1=SILVER, color2=WHITE):
ck = 6 # 边框
num_font = pygame.font.SysFont('幼圆', 32, True) # 加载系统字体
face = pygame.Surface((bc, bc))
# face1 = pygame.Surface((bc-ck, bc-ck))
face.fill(color1) # 外层银色
face.fill(color2, (ck // 2, ck // 2, bc - ck, bc - ck)) # 里层白色
num_text = num_font.render(f"{num + 1}", True, (0, 0, 0)) # 创建字体
rect_l = num_text.get_rect() # 获取字体边长大小
face.blit(num_text, (int((bc - rect_l[2]) / 2), int(bc - rect_l[3]) / 2)) # 数字显示居中
# face.blit(face,(int(ck/2),int(ck/2)))
form.blit(face, (num * (bc + 3) + 50, (bc + 3) * 12 + 10))
def control(form, bc):
# 5个控制按键
lon = 9 * (bc + 3) + 50
lon = lon // 5 - 12 # 控制按键长度
num_font = pygame.font.SysFont('幼圆', 18, True) # 加载系统字体
ctl = ["撤回", "擦除", "笔记", "一键笔记", "提示"]
for i in range(5):
face = pygame.Surface((lon, bc))
# face.set_colorkey([0,0,0])
# face = face.convert_alpha() # 透明色
face.fill(WHITE)
num_text = num_font.render(f"{ctl[i]}", False, (0, 0, 0)) # 创建字体
rel = num_text.get_size()
face.blit(num_text, (int((lon - rel[0]) / 2), int((bc - rel[1]) / 2))) # 数字显示居中
form.blit(face, ((lon + 2) * i + 50, (bc + 3) * 11 + 8))
def control_xs(form, bc, i):
lon = 9 * (bc + 3) + 50
lon = lon // 5 - 12 # 控制按键长度
num_font = pygame.font.SysFont('幼圆', 18, True) # 加载系统字体
ctl = ["撤回", "擦除", "笔记", "一键笔记", "提示"]
face = pygame.Surface((lon, bc))
face.fill(SILVER)
num_text = num_font.render(f"{ctl[i]}", False, (0, 0, 0)) # 创建字体
rel = num_text.get_size()
face.blit(num_text, (int((lon - rel[0]) / 2), int((bc - rel[1]) / 2))) # 数字显示居中
form.blit(face, ((lon + 2) * i + 50, (bc + 3) * 11 + 8))
def text_enter(bc):
"""文字框"""
top_x = (bc + 3) * 11 # 文本框顶点x
top_y = 50 # 文本框顶点y
bc_x = (bc + 3) * 7 + 20 # 文本框宽度
bc_y = (bc + 3) * 12 # 文本框高度
ck = 6 # 间隔
face = pygame.Surface((bc_x, bc_y))
face.fill(SILVER)
face.fill(WHITE, (ck // 2, ck // 2, bc_x - ck, bc_y - ck))
return face, (top_x, top_y)
def timer(face, time1, empty, *args):
"""
时间难度显示
:param face:
:param time1: 时间
:param empty: 原始空格数目
:return:
"""
num_font = pygame.font.SysFont('幼圆', 18, True) # 加载系统字体
info_time = num_font.render(f"运行时间:{time1.get_elapsed()}", False, BLACK)
w, h = info_time.get_size()
face.blit(info_time, (5, 5))
info_level = num_font.render("难度:{:.2f}".format(empty / 81), False, BLACK)
face.blit(info_level, (15 + w, 5))
return face
def noter(face, tag):
"""显示笔记提示"""
num_font = pygame.font.SysFont('幼圆', 18, True) # 加载系统字体
note_help1 = num_font.render(f"False 时保存笔记,当前笔记:{tag}", False, RED)
w1, h1 = note_help1.get_size()
face.blit(note_help1, (5, 15 + h1))
# note_tag = num_font.render(f"笔记模式:{tag}", False, BLACK)
# face.blit(note_tag, (5, 31+10+h1)) #
return face
def seq_recode(face: pygame.Surface, STEP):
num_font = pygame.font.SysFont('幼圆', 18, True) # 加载系统字体
note_help1 = num_font.render(f"步骤记录:", False, BLACK)
w1, h1 = note_help1.get_size()
face.blit(note_help1, (5, 15 + (3 + h1) * 2))
for i in range(len(STEP)):
if i != 0:
step = num_font.render(f"{STEP[i][:3]}", False, BLACK)
w, h = step.get_size()
wf, wh = face.get_size()
if 15 + (3 + h) * (i + 2) < wh:
face.blit(step, (5, 15 + (3 + h) * (i + 2)))
else:
face.blit(step, (15 + w, 16+h+(3 + h) * (i + 2 -22)))
return face
def win(face: pygame.Surface, u_martix, timer: MyTimer):
count = 0 # 计数
num_font = pygame.font.SysFont('幼圆', 18, True) # 加载系统字体
win_words = num_font.render(f"游戏结束,恭喜通过", False, BLACK)
w1, h1 = win_words.get_size()
for i in range(9):
for j in range(9):
if u_martix[i][j] == 0 or u_martix[i][j] == 11:
count += 1
if count == 0:
if Judge(u_martix):
time1 = timer.get_elapsed()
timer.pause()
time1_words = num_font.render(f"耗时:{time1}", False, BLACK)
wt, ht = time1_words.get_size()
face.fill(WHITE)
w, h = face.get_size()
face.blit(win_words, ((w - w1) // 2, (h - h1) // 2))
face.blit(time1_words, ((w - wt) // 2, (h - ht) // 2 - h1 - 5))
return face

Binary file not shown.

@ -0,0 +1,243 @@
# -*- encoding: utf-8 -*-
'''
@File : opera.py
@License : (C)Copyright 2018-2022
@Modify Time @Author @Version @Desciption
------------ ------- -------- -----------
2022/12/22 16:42 zart20 1.0 None
'''
from data import *
from gameui import *
def listen_add(pos, loca, **kwargs):
if loca != ():
i = loca[0]-1
j = loca[1]-1
num = num_map(pos)
global note_list, step, seq,form
if num: # 直接点击了数字按钮就添加num
if martix[j][i] == 0 and not note_mark: # 空格且笔记模式为False才可以填写
if u_martix[j][i] == 11: # 如果修改了这个格子的值,删除原来的记录
for note in note_martix: # 如果这个空格有笔记直接覆盖清空笔记
if note[0] == i and note[1] == j:
note_martix.remove(note)
u_martix[j][i] = num # 为用户数组添加数值
xianse(form, martix, u_martix, loca[0], loca[1]) # 更新显示用户数组
seq = STEP[-1][0] + 1 # 记录顺序
step=[seq, loca,num, u_martix.copy(),note_martix.copy()] # 记录一步
print(step)
print(loca, num, "添加")
elif martix[j][i] == 0 and note_mark: # 笔记模式打开时
note_list.append(num)
note_list = list(set(note_list))
face = possible_num(bc, loca[0], loca[1], note_list)
show_face(form,face,bc,i,j)
print(note_list)
print(note_martix)
def listen_del(pos,loca):
if loca != ():
i = loca[0] - 1
j = loca[1] - 1
tag = control_map(pos) # 控制号码
if tag==2: # 直接点击了数字按钮就添加num
if martix[j][i] == 0: # 空格才可以删除
u_martix[j][i] = 0
xianse(form, martix, u_martix, loca[0], loca[1], note_martix)
print(loca, tag,"删除")
for note in note_martix: # 如果这个空格有笔记直接覆盖清空笔记
if note[0] == i and note[1] == j:
note_martix.remove(note)
print(note_martix)
def listen_all_note(pos):
tag = control_map(pos) # 控制号码
if tag==4: # 直接点击了数字按钮就添加num
for i in range(9):
for j in range(9):
if u_martix[j][i] == 11: # 更新可能值
u_martix[j][i] = 0
if u_martix[j][i] == 0:
possible = GetPossible(u_martix,j,i)
face = possible_num(bc,i+1,j+1,possible)
show_face(form, face, bc, i, j)
u_martix[j][i] = 11
note_martix.append((i,j,possible))
def listen_hint(pos,loca):
if loca != ():
i = loca[0] - 1
j = loca[1] - 1
tag = control_map(pos) # 控制号码
if tag == 5:
if u_martix[j][i] == 0:
possible = GetPossible(u_martix, j, i)
face = possible_num(bc, i + 1, j + 1, possible)
show_face(form,face,bc,i, j)
def listen_note(pos,loca):
if loca != ():
i = loca[0] - 1
j = loca[1] - 1
tag = control_map(pos) # 控制号码
global note_mark , note_list, form # 函数内修改全局变量
if tag == 3:
note_mark = not note_mark
print(note_mark)
if u_martix[j][i] == 0 and note_mark: # 判断是否在笔记模式
xianse(form,martix, u_martix, i + 1, j + 1, note_martix) # 显示输入
if u_martix[j][i] == 0 and not note_mark and len(note_list)!=0: # 判断是否不是处于笔记模式
u_martix[j][i] = 11
note_martix.append((i,j,note_list))
note_list = []
xianse(form,martix, u_martix, i + 1, j + 1, note_martix)
print(note_martix)
def listen_backspace(pos):
tag = control_map(pos) # 控制号码
global u_martix, note_martix, step
if tag==1: # 直接点击了数字按钮,撤回
if len(STEP) > 1:
STEP.pop()
u_martix = STEP[-1][-2].copy()
note_martix = STEP[-1][-1].copy()
step = []
refresh(form,martix, u_martix, note_martix)
else:
u_martix = STEP[-1][-2].copy()
note_martix = STEP[-1][-1].copy()
step = []
print(STEP, '\n')
def martix_map(pos:tuple):
"""martix坐标映射"""
x = pos[0]
y = pos[1]
i = 0
j = 0
global note_list, STEP, step
# (n * (bc + 3) + 50, p * (bc + 3) + 50)
for n in range(9):
for p in range(9):
top_x, top_y = n * (bc + 3) + 50, p * (bc + 3) + 50
ud_x, ud_y = (n + 1) * (bc + 3) + 50, (p + 1) * (bc + 3) + 50
if x < ud_x and x > top_x:
i = n + 1
if y < ud_y and y > top_y:
j = p + 1
if i >= 1 and j >= 1:
note_list = []
xianse(form, martix, u_martix, i, j, note_martix)
if len(step) !=0: # 添加步骤
STEP.append(step)
step = []
return (i, j)
def num_map(pos:tuple):
"""数字按键坐标映射"""
x = pos[0]
y = pos[1]
for i in range(9):
top_x, top_y = i * (bc + 3) + 50, 12 * (bc + 3) + 10
ud_x, ud_y = (i + 1) * (bc + 3) + 50, 13 * (bc + 3) + 10
if x < ud_x and x > top_x:
if y < ud_y and y > top_y:
control_number_xs(form,bc,i,WHITE,SILVER)
num = i + 1
return num
def control_map(pos:tuple):
"""控制栏坐标映射函数"""
x = pos[0]
y = pos[1]
lon = 9 * (bc + 3) + 50
lon = lon // 5 - 12 # 控制按键长度
for i in range(5):
top_x, top_y = (lon + 2) * i + 50, (bc + 3) * 11 + 8
ud_x, ud_y = (i + 1) * (lon + 2) + 50, (bc + 3) * 12 + 8
if x < ud_x and x > top_x:
if y < ud_y and y > top_y:
control_xs(form,bc,i)
num = i + 1
return num
def empty(u_martix):
count = 0 # 计数
for i in range(9):
for j in range(9):
if u_martix[i][j] == 0 or u_martix[i][j] == 11:
count += 1
return count
if __name__ == '__main__':
# martix = InitMartix() # 初始化martix
martix = np.load("martix.npy")
u_martix = martix.copy() # 复制用户martix数组
form = GuiForm() # 构建主窗口
loca_o = tuple() # martix数组上次滞留坐标
note_mark = False # 笔记开启标志
note_list = [] # 笔记数字记录
note_martix = [] # 笔记位置记录列表
step = [] # 操作步骤
STEP = [[0, (0, 0), 0,martix,note_martix]] # 记录每一步的状态
seq = 1 # 全局操作次序初始化
time1 = MyTimer() # 实例计时器
time1.start() # 计时开始
control_number(form,bc,) # 显示输入键盘
control(form,bc) # 显示控制栏
face, top = text_enter(bc) # 返回信息框对象,和顶点坐标
empty_count = empty(martix) # 计算数组空格
face = timer(face,time1,empty_count) # 计时,空格显示
form.blit(face,top) # 显示信息框
refresh(form, martix, u_martix, note_martix) # 刷新屏幕
while True:
"""动态区"""
face, top = text_enter(bc) # 返回信息框对象,和顶点坐标
face = timer(face, time1, empty_count) # 显示时间到消息框对象
face = noter(face, note_mark) # 显示笔记模式到消息框对象
face = seq_recode(face,STEP) # 显示步骤记录到消息框对象
face = win(face,u_martix,time1) # 显示数独成功到消息框对象
form.blit(face, top) # 显示消息框对象
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYUP and event.key == 27):
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
pos = event.pos # 鼠标坐标
refresh(form,martix, u_martix, note_martix) # 下一次鼠标坐标更新前刷新屏幕
control(form,bc) # 跟随鼠标显示控制按钮
control_number(form, bc) # 更新数字按钮
loca = martix_map(pos) # 返回取选中的格子位置
if loca:
loca_o = loca # 保留上次点击过的坐标
listen_add(pos,loca_o) # 添加功能
listen_del(pos,loca_o) # 擦除功能
listen_all_note(pos) # 一键笔记功能
listen_hint(pos,loca_o) # 提示功能
listen_note(pos,loca_o) # 笔记功能
listen_backspace(pos) # 回撤功能
pygame.display.update()

@ -0,0 +1,42 @@
# -*- encoding: utf-8 -*-
'''
@File : slove_show.py
@License : (C)Copyright 2018-2022
@Modify Time @Author @Version @Desciption
------------ ------- -------- -----------
2022/12/28 11:50 zart20 1.0 None
'''
import numpy as np
martix = np.load("martix.npy")
from gameui import *
from data import *
from opera import *
form = GuiForm()
def Solve_show(martix):
"""求解数组"""
# refresh(form, martix, [])
# time.sleep(1)
for row in range(9):
for col in range(9):
if martix[row, col] == 0:
possible = GetPossible(martix, row, col) # 所有的可能的数字
for value in possible:
martix[row, col] = value # 将可能的数组填入
refresh(form,martix, martix, [])
time.sleep(0.5)
if Solve_show(martix): # 继续深度优先遍历填入数字
return True # 填完最后一个数字
martix[row, col] = 0 # 如果当前填入的数字会导致后面无解则依然填入0表示空白待填
return False
# 当所有的数字填完,数独求解完毕
return True
Solve_show(martix)
print(martix)
Loading…
Cancel
Save