Compare commits

...

7 Commits

@ -4,11 +4,9 @@
Version:1.0 Version:1.0
Description:None Description:None
""" """
import pickle
from PySide6.QtCore import QTimer, QPropertyAnimation, QRect, QPoint
import random
from PySide6.QtCore import QTimer
from PySide6.QtWidgets import * from PySide6.QtWidgets import *
from PySide6.QtGui import QIcon from PySide6.QtGui import QIcon
from win.win import Ui_Form as Form1 from win.win import Ui_Form as Form1
@ -39,14 +37,27 @@ class Form(Form1):
super().__init__() super().__init__()
self.setupUi(self) self.setupUi(self)
self.total_seconds = 0 self.total_seconds = 0
self.change_flag = 0
self.B_save.setDisabled(True)
# self.test() # self.test()
self.konami_code = [65, 66, 65, 66]
# self.lll =[]
self.konami_index = 0
self.pushButton.clicked.connect(self.B_back) self.pushButton.clicked.connect(self.B_back)
self.B_S.clicked.connect(self.translate) self.B_S.clicked.connect(self.B_S_fun)
self.B_save.clicked.connect(self.B_save_fun)
self.B_read.clicked.connect(self.B_read_fun)
self.B_rule.clicked.connect(self.B_rule_fun)
self.timer = QTimer() self.timer = QTimer()
self.shake_timer = QTimer(self)
self.shake_times = 0
self.shake_timer.timeout.connect(self.shake_window)
self.timer.setInterval(1000) self.timer.setInterval(1000)
self.timer.timeout.connect(self.update_time) self.timer.timeout.connect(self.update_time)
self.init_bt()
def init_bt(self):
self.B0_0.clicked.connect(self.put_num) self.B0_0.clicked.connect(self.put_num)
self.B0_1.clicked.connect(self.put_num) self.B0_1.clicked.connect(self.put_num)
self.B0_2.clicked.connect(self.put_num) self.B0_2.clicked.connect(self.put_num)
@ -129,6 +140,38 @@ class Form(Form1):
self.B8_7.clicked.connect(self.put_num) self.B8_7.clicked.connect(self.put_num)
self.B8_8.clicked.connect(self.put_num) self.B8_8.clicked.connect(self.put_num)
def closeEvent(self, event):
if self.change_flag == 1:
message_box = QMessageBox()
message_box.setWindowTitle("提示")
message_box.setText("是否要保存进度?")
message_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
message_box.setDefaultButton(QMessageBox.No)
yes_button = message_box.button(QMessageBox.Yes)
yes_button.clicked.connect(self.B_save_fun)
no_button = message_box.button(QMessageBox.No)
message_box.exec()
# 重写窗口按键事件
def keyPressEvent(self, event):
global sudo
key = event.key()
try:
if key == self.konami_code[self.konami_index]:
self.konami_index += 1
if self.konami_index == len(self.konami_code):
sudo.print_sudo()
self.konami_index = 0
else:
self.konami_index = 0
except Exception as e:
self.konami_index = 0
# self.lll.append(key)
# print(self.lll)
def update_time(self): def update_time(self):
self.total_seconds += 1 self.total_seconds += 1
@ -139,61 +182,141 @@ class Form(Form1):
time_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}" time_str = f"{hours:02d}:{minutes:02d}:{seconds:02d}"
self.lcdNumber.display(time_str) self.lcdNumber.display(time_str)
def B_rule_fun(self):
rules = """
以下是数独游戏的规则
1. 每个数独游戏由一个9x9的方格组成共计81个小方格
2. 方格被划分为9个3x3的小方格每个小方格内的数字不得重复
3. 每行必须包含数字1到9且不能重复
4. 每列必须包含数字1到9且不能重复
5. 每个3x3的小方格内必须包含数字1到9且不能重复
6. 游戏开始时一些方格内可能包含了一些已知的数字称为提示数字玩家需要根据这些提示数字来推理并填充其余的方格
7. 玩家通过逻辑推理和试错来填充空白方格直到所有方格都填满且符合数独规则为止
8. 如果玩家填写的数字与已有的数字冲突或者某一行或小方格内存在重复的数字则游戏失败
9. 当所有方格都填满且符合数独规则时游戏胜利
"""
QMessageBox.information(self, '提示', rules)
def B_save_fun(self):
global sudo, cnt, del_cnt
try:
# 保存已填处,第一位用于记录cnt,第二位记录delcnt第三位记录time
answer_list = [cnt, del_cnt, self.total_seconds]
with open('as.pickle', 'wb') as f:
# 使用pickle的dump函数将对象写入文件
pickle.dump(answer_list, f)
with open('sudo.pickle', 'wb') as f:
# 使用pickle的dump函数将对象写入文件
pickle.dump(sudo, f)
QMessageBox.information(self, '提示', '保存成功')
self.change_flag = 0
except Exception as e:
QMessageBox.information(self, '提示', f'保存发生错误:{e}')
def B_read_fun(self):
global sudo, cnt, subject_with_answer, del_cnt
self.change_flag = 0
self.B_save.setDisabled(False)
answer_list = None
with open('as.pickle', 'rb') as f:
# 使用pickle的load函数从文件中读取对象
answer_list = pickle.load(f)
with open('sudo.pickle', 'rb') as f:
# 使用pickle的load函数从文件中读取对象
sudo = pickle.load(f)
# 配置计数器和计时器
cnt = answer_list[0]
del_cnt = answer_list[1]
print(cnt)
stack.clear()
self.total_seconds = answer_list[2]
self.timer.start()
# 映射题目并配置答案进度
self.translate(sudo.subject)
subject_with_answer = sudo.subject_with_answer
i = 1
self.translate(subject_with_answer, 1)
def B_back(self): def B_back(self):
global stack,cnt global stack, cnt, subject_with_answer
self.change_flag = 1
try: try:
top = stack.pop() top = stack.pop()
info = top.split(",", 1) info = top.split(",", 1)
b = self.findChild(QPushButton, info[0]) b = self.findChild(QPushButton, info[0])
if info[1] == ' ': if info[1] == ' ':
info[1] = 0
b.setText(' ') b.setText(' ')
cnt = cnt - 1 cnt = cnt - 1
else: else:
b.setText(info[1]) b.setText(info[1])
subject[info[0][1], info[0][3]] = int(info[1]) subject_with_answer[int(info[0][1]), int(info[0][3])] = int(info[1])
except Exception:
print("Stack Empty")
except Exception as e:
print(e)
def check_sudo(self): def check_sudo(self, mode=0):
global cnt, del_cnt, subject global cnt, del_cnt, subject_with_answer
f = 1 f = 1
for row_index in range(9): for row_index in range(9):
for col_index in range(9): for col_index in range(9):
num = subject[row_index, col_index] num = subject_with_answer[row_index, col_index]
if num == 0:
# 获取该格子对应的行、列、九宫格 pass
sudo_row = sd.get_row(subject, row_index) else:
sudo_col = sd.get_col(subject, col_index) # 获取该格子对应的行、列、九宫格
sudo_block = sd.get_block(subject, row_index, col_index) sudo_row = sd.get_row(subject_with_answer, row_index)
# print(num) sudo_col = sd.get_col(subject_with_answer, col_index)
# print(sudo_row) sudo_block = sd.get_block(subject_with_answer, row_index, col_index)
# print(sudo_col)
# print(sudo_block) cnt_oc1 = count_occurrences(sudo_row, num, 0)
cnt_oc2 = count_occurrences(sudo_col, num, 0)
cnt_oc1 = count_occurrences(sudo_row, num, 0) cnt_oc3 = count_occurrences(sudo_block, num, 1)
cnt_oc2 = count_occurrences(sudo_col, num, 0) # print(cnt_oc1, cnt_oc2, cnt_oc3)
cnt_oc3 = count_occurrences(sudo_block, num, 1) if cnt_oc1 != 1 or cnt_oc2 != 1 or cnt_oc3 != 1:
if cnt_oc1 != 1 or cnt_oc2 != 1 or cnt_oc3 != 1: f = 0
f = 0 break
break
if f == 0: if f == 0:
break break
if f == 1: if f == 1:
print("yes") # print("yes")
QMessageBox.information(self, '提示','成功') if del_cnt == cnt:
self.timer.stop() QMessageBox.information(self, '提示', '成功')
self.change_flag = 0
self.timer.stop()
else: else:
print("no") # print("no")
QMessageBox.information(self, '提示','失败') if mode == 1:
self.shake_timer.start(30)
else:
QMessageBox.information(self, '提示', '失败')
def shake_window(self):
self.shake_times += 1
if self.shake_times == 5:
self.shake_times = 0
self.shake_timer.stop()
else:
if self.shake_times % 2 == 0:
self.move(self.x() + 7, self.y())
else:
self.move(self.x() - 7, self.y())
def put_num(self): def put_num(self):
global cnt, del_cnt, subject, stack global cnt, del_cnt, subject_with_answer, stack
b = self.sender() b = self.sender()
x = int(b.objectName()[1]) x = int(b.objectName()[1])
@ -204,43 +327,48 @@ class Form(Form1):
cnt = cnt + 1 cnt = cnt + 1
stack.append(f'B{x}_{y},{old_text}') stack.append(f'B{x}_{y},{old_text}')
print(stack) # print(stack)
if self.R_1.isChecked(): if self.R_1.isChecked():
b.setText("1") b.setText("1")
subject[x, y] = 1 subject_with_answer[x, y] = 1
if self.R_2.isChecked(): if self.R_2.isChecked():
b.setText("2") b.setText("2")
subject[x, y] = 2 subject_with_answer[x, y] = 2
if self.R_3.isChecked(): if self.R_3.isChecked():
b.setText("3") b.setText("3")
subject[x, y] = 3 subject_with_answer[x, y] = 3
if self.R_4.isChecked(): if self.R_4.isChecked():
b.setText("4") b.setText("4")
subject[x, y] = 4 subject_with_answer[x, y] = 4
if self.R_5.isChecked(): if self.R_5.isChecked():
b.setText("5") b.setText("5")
subject[x, y] = 5 subject_with_answer[x, y] = 5
if self.R_6.isChecked(): if self.R_6.isChecked():
b.setText("6") b.setText("6")
subject[x, y] = 6 subject_with_answer[x, y] = 6
if self.R_7.isChecked(): if self.R_7.isChecked():
b.setText("7") b.setText("7")
subject[x, y] = 7 subject_with_answer[x, y] = 7
if self.R_8.isChecked(): if self.R_8.isChecked():
b.setText("8") b.setText("8")
subject[x, y] = 8 subject_with_answer[x, y] = 8
if self.R_9.isChecked(): if self.R_9.isChecked():
b.setText("9") b.setText("9")
subject[x, y] = 9 subject_with_answer[x, y] = 9
if cnt == del_cnt: if cnt == del_cnt:
self.check_sudo() self.check_sudo()
else:
self.check_sudo(1)
self.change_flag = 1
def translate(self): def B_S_fun(self):
global cnt, del_cnt, subject, stack global cnt, del_cnt, stack, sudo, subject_with_answer
# 清零 # 清零
self.change_flag = 1
self.B_save.setDisabled(False)
cnt = 0 cnt = 0
stack.clear() stack.clear()
self.total_seconds = 0 self.total_seconds = 0
@ -253,39 +381,43 @@ class Form(Form1):
level = 2 level = 2
if self.R_h.isChecked(): if self.R_h.isChecked():
level = 3 level = 3
max_clear_count = 64
min_clear_count = 14
each_level_count = (max_clear_count - min_clear_count) / 5
level_start = min_clear_count + (level - 1) * each_level_count
del_cnt = del_nums = random.randrange(level_start, level_start + each_level_count)
# 生成数独
sudo = sd.create_base_sudo()
sd.random_sudo(sudo, 50)
# 这里可以用多线程
sudo = sd.Sudo()
subject_with_answer = sudo.createSubjectByLevel(level).subject_with_answer
del_cnt = sudo.get_del_cnt()
# 打印参考答案 # 打印参考答案
sd.print_sudo(sudo) # sudo.print_sudo()
# 出题 # print(sudo)
subject = sd.get_sudo_subject(sudo, del_nums) self.translate(sudo.subject)
for row_index, row in enumerate(subject): def translate(self, nparray, mode=0):
# 将np数组内容映射到按钮上
for row_index, row in enumerate(nparray):
row_list = list(map(str, row.tolist())) row_list = list(map(str, row.tolist()))
row_list = replace_element(row_list, '0', ' ') row_list = replace_element(row_list, '0', ' ')
for single_index, single in enumerate(row_list): for single_index, single in enumerate(row_list):
# 找到对象名为对应坐标的按钮
b = self.findChild(QPushButton, 'B' + str(row_index) + '_' + str(single_index)) b = self.findChild(QPushButton, 'B' + str(row_index) + '_' + str(single_index))
# 将值映射到按钮上
b.setText(single) b.setText(single)
if single != ' ': # 禁用空值按钮
b.setDisabled(True) if mode == 0:
else: if single != ' ':
b.setDisabled(False) b.setDisabled(True)
else:
b.setDisabled(False)
if __name__ == '__main__': if __name__ == '__main__':
cnt = 0 cnt = 0
del_cnt = 0 del_cnt = 0
stack = [] stack = []
subject_with_answer = None
sudo = None
app = QApplication() app = QApplication()
win = Form() win = Form()
# app.setStyleSheet(qdarkstyle.load_stylesheet())
win.setWindowIcon(QIcon('src/sudo32.png')) win.setWindowIcon(QIcon('src/sudo32.png'))
win.show() win.show()
app.exec() app.exec()

@ -2,6 +2,106 @@ import random
import numpy as np import numpy as np
class Sudo:
def __init__(self):
self.sudo = np.zeros((9, 9), dtype=int)
self.subject = None
self.subject_with_answer = None
self.del_cnt = 0
def get_del_cnt(self):
return self.del_cnt
def createSubjectByLevel(self, level):
max_clear_count = 64
min_clear_count = 14
each_level_count = (max_clear_count - min_clear_count) // 3
# 难度对应删除数
level_start = min_clear_count + (level - 1) * each_level_count
self.del_cnt = random.randrange(level_start, level_start + each_level_count)
self.create_base_sudo()
self.__random_sudo(50)
self.__get_sudo_subject(self.del_cnt)
self.subject_with_answer = self.subject.copy()
return self
def create_base_sudo(self):
# 9*9的二维矩阵每个格子默认值为0
self.sudo = np.zeros((9, 9), dtype=int)
# 随机生成起始的基数(1 ~ 9)
num = random.randrange(9) + 1
# 遍历从左到右,从上到下逐个遍历
for row_index in range(9):
for col_index in range(9):
# 获取该格子对应的行、列、九宫格
sudo_row = self.get_row(row_index)
sudo_col = self.get_col(col_index)
sudo_block = self.get_block(row_index, col_index)
# 如果该数字已经存在于对应的行、列、九宫格
# 则继续判断下一个候选数字,直到没有重复
while num in sudo_row or num in sudo_col or num in sudo_block:
num = num % 9 + 1
# 赋值
self.sudo[row_index, col_index] = num
num = num % 9 + 1
return self.sudo
def get_row(self, row):
return self.sudo[row, :]
def get_col(self, col):
return self.sudo[:, col]
def get_block(self, row, col):
row_start = row // 3 * 3
col_start = col // 3 * 3
return self.sudo[row_start: row_start + 3, col_start: col_start + 3]
def print_sudo(self):
for row_index, row in enumerate(self.sudo):
if row_index % 3 == 0 and row_index != 0:
print('-' * (9 + 8 + 4))
row = list(map(str, row.tolist()))
row.insert(6, '|')
row.insert(3, '|')
row_str = ' '.join(row)
print(row_str.replace('0', ' '))
def __random_sudo(self, times):
for _ in range(times):
# 随机交换两行
rand_row_base = random.randrange(3) * 3 # 从036 随机取一个
rand_rows = random.sample(range(3), 2) # 从 012中随机取两个数
row_1 = rand_row_base + rand_rows[0]
row_2 = rand_row_base + rand_rows[1]
self.sudo[[row_1, row_2], :] = self.sudo[[row_2, row_1], :]
# 随机交换两列
rand_col_base = random.randrange(3) * 3
rand_cols = random.sample(range(3), 2)
col_1 = rand_col_base + rand_cols[0]
col_2 = rand_col_base + rand_cols[1]
self.sudo[:, [col_1, col_2]] = self.sudo[:, [col_2, col_1]]
def __get_sudo_subject(self, del_nums):
self.subject = self.sudo.copy()
# 随机擦除从0到80随机取要删除的个数
clears = random.sample(range(81), del_nums)
for clear_index in clears:
# 把0到80的坐标转化成行和列索引
# 这样就不会重复删除同一个格子的数字
row_index = clear_index // 9
col_index = clear_index % 9
self.subject[row_index, col_index] = 0
return self.subject
# 获取格子所在的行的全部格子 # 获取格子所在的行的全部格子
def get_row(sudo, row): def get_row(sudo, row):
return sudo[row, :] return sudo[row, :]
@ -17,100 +117,3 @@ def get_block(sudo, row, col):
row_start = row // 3 * 3 row_start = row // 3 * 3
col_start = col // 3 * 3 col_start = col // 3 * 3
return sudo[row_start: row_start + 3, col_start: col_start + 3] return sudo[row_start: row_start + 3, col_start: col_start + 3]
# 打印数独
def print_sudo(sudo):
for row_index, row in enumerate(sudo):
if row_index % 3 == 0 and row_index != 0:
print('-' * (9 + 8 + 4))
row = list(map(str, row.tolist()))
row.insert(6, '|')
row.insert(3, '|')
row_str = ' '.join(row)
print(row_str.replace('0', ' '))
def create_base_sudo():
# 9*9的二维矩阵每个格子默认值为0
sudo = np.zeros((9, 9), dtype=int)
# 随机生成起始的基数(1 ~ 9)
num = random.randrange(9) + 1
# 遍历从左到右,从上到下逐个遍历
for row_index in range(9):
for col_index in range(9):
# 获取该格子对应的行、列、九宫格
sudo_row = get_row(sudo, row_index)
sudo_col = get_col(sudo, col_index)
sudo_block = get_block(sudo, row_index, col_index)
# 如果该数字已经存在于对应的行、列、九宫格
# 则继续判断下一个候选数字,直到没有重复
while num in sudo_row or num in sudo_col or num in sudo_block:
num = num % 9 + 1
# 赋值
sudo[row_index, col_index] = num
num = num % 9 + 1
return sudo
def random_sudo(sudo, times):
for _ in range(times):
# 随机交换两行
rand_row_base = random.randrange(3) * 3 # 从036 随机取一个
rand_rows = random.sample(range(3), 2) # 从 012中随机取两个数
row_1 = rand_row_base + rand_rows[0]
row_2 = rand_row_base + rand_rows[1]
sudo[[row_1, row_2], :] = sudo[[row_2, row_1], :]
# 随机交换两列
rand_col_base = random.randrange(3) * 3
rand_cols = random.sample(range(3), 2)
col_1 = rand_col_base + rand_cols[0]
col_2 = rand_col_base + rand_cols[1]
sudo[:, [col_1, col_2]] = sudo[:, [col_2, col_1]]
def get_sudo_subject(sudo, del_nums):
subject = sudo.copy()
# 随机擦除从0到80随机取要删除的个数
clears = random.sample(range(81), del_nums)
for clear_index in clears:
# 把0到80的坐标转化成行和列索引
# 这样就不会重复删除同一个格子的数字
row_index = clear_index // 9
col_index = clear_index % 9
subject[row_index, col_index] = 0
return subject
if __name__ == '__main__':
max_clear_count = 64 # 最多清除个数
min_clear_count = 14 # 最少清除个数
# 设置难度等级1~55个等级入门、初级、熟练、精通、大神
level = 3
# 每个等级的个数
each_level_count = (max_clear_count - min_clear_count) / 5
# 该等级最小数
level_start = min_clear_count + (level - 1) * each_level_count
# 该等级范围内的随机数
del_nums = random.randrange(level_start, level_start + each_level_count)
# 生成基本盘
sudo = create_base_sudo()
# 生成终盘
random_sudo(sudo, 50)
# 获取数独题目
subject = get_sudo_subject(sudo, del_nums)
print('题目:')
print('=' * 26)
print_sudo(subject)
print('\n答案:')
print('=' * 26)
print_sudo(sudo)

File diff suppressed because it is too large Load Diff

@ -3388,6 +3388,32 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="B_save">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>保存进度</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="B_read">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>读取进度</string>
</property>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer_3"> <spacer name="verticalSpacer_3">
<property name="orientation"> <property name="orientation">
@ -3626,7 +3652,7 @@
<resources/> <resources/>
<connections/> <connections/>
<buttongroups> <buttongroups>
<buttongroup name="buttonGroup"/>
<buttongroup name="buttonGroup_2"/> <buttongroup name="buttonGroup_2"/>
<buttongroup name="buttonGroup"/>
</buttongroups> </buttongroups>
</ui> </ui>
Loading…
Cancel
Save