|
|
|
|
# -*- encoding: utf-8 -*-
|
|
|
|
|
"""
|
|
|
|
|
@File : new_UI.py
|
|
|
|
|
@License : (C)Copyright 2021-2023
|
|
|
|
|
|
|
|
|
|
@Modify Time @Author @Version @Description
|
|
|
|
|
------------ ------- -------- -----------
|
|
|
|
|
2023/10/11 16:14 zart20 1.0 None
|
|
|
|
|
"""
|
|
|
|
|
import re
|
|
|
|
|
import time
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
from pprint import pprint
|
|
|
|
|
from tkinter import scrolledtext
|
|
|
|
|
from typing import List
|
|
|
|
|
|
|
|
|
|
import data
|
|
|
|
|
from data import *
|
|
|
|
|
|
|
|
|
|
BLACK = "#000000"
|
|
|
|
|
HINT = '#6D2DFA'
|
|
|
|
|
SILVER = '#FFFFFF'
|
|
|
|
|
u_NUMBER = '#6D2DFA'
|
|
|
|
|
WHITE = "#FFFFFF"
|
|
|
|
|
ORANGE = '#FF8C00'
|
|
|
|
|
RED = "#C80000"
|
|
|
|
|
YELLOW = "#FAE067"
|
|
|
|
|
GREY = '#808080'
|
|
|
|
|
GREYLESS = '#CCCCCC'
|
|
|
|
|
|
|
|
|
|
martix_position_mapping = dict()
|
|
|
|
|
side = 40 # 方格边长
|
|
|
|
|
# martix = np.load("martix.npy")
|
|
|
|
|
|
|
|
|
|
quest = [[0, 1, 0, 8, 5, 2, 0, 6, 9],
|
|
|
|
|
[0, 6, 5, 7, 9, 3, 0, 0, 0],
|
|
|
|
|
[9, 0, 8, 0, 0, 4, 0, 5, 7],
|
|
|
|
|
[0, 7, 2, 4, 3, 0, 9, 0, 0],
|
|
|
|
|
[6, 0, 9, 2, 0, 8, 1, 3, 0],
|
|
|
|
|
[0, 8, 0, 1, 0, 0, 0, 2, 5],
|
|
|
|
|
[7, 9, 1, 5, 2, 6, 8, 4, 3],
|
|
|
|
|
[5, 4, 0, 9, 0, 1, 6, 7, 2],
|
|
|
|
|
[8, 0, 0, 3, 4, 7, 0, 0, 0]]
|
|
|
|
|
|
|
|
|
|
martix = np.array(quest)
|
|
|
|
|
|
|
|
|
|
u_martix = martix.copy()
|
|
|
|
|
info_labels = [] # label对象列表
|
|
|
|
|
note_mark = False # 笔记标志
|
|
|
|
|
all_hint_mark = False # 一键笔记标记
|
|
|
|
|
STEP = [] # 回撤存储列表
|
|
|
|
|
wait_time = 0.1 # 运行阻滞时间
|
|
|
|
|
set_question_mark = False # 手动修改数组标志
|
|
|
|
|
running = True # 运行状态
|
|
|
|
|
r_step = list() # 单步记录列表
|
|
|
|
|
hint_mark = None # 提示状态
|
|
|
|
|
possible_num_mark = False # 手动预期功能标志
|
|
|
|
|
|
|
|
|
|
row = None
|
|
|
|
|
col = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def creat_note_dict():
|
|
|
|
|
usr_note_dict = dict()
|
|
|
|
|
for i in range(9):
|
|
|
|
|
for n in range(9):
|
|
|
|
|
usr_note_dict[i, n] = set()
|
|
|
|
|
return usr_note_dict
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
usr_note_dict = creat_note_dict() # 记录对应单元格笔记数字
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def creat_martix_mapping(side):
|
|
|
|
|
mapping_dict = dict()
|
|
|
|
|
offeset_x = 50
|
|
|
|
|
side = side + 3
|
|
|
|
|
for i in range(9): # 坐标映射
|
|
|
|
|
for n in range(9):
|
|
|
|
|
x = side * i + offeset_x
|
|
|
|
|
y = side * n + offeset_x
|
|
|
|
|
mapping_dict[n, i] = [x, y]
|
|
|
|
|
return mapping_dict
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping = creat_martix_mapping(side)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MyTimer:
|
|
|
|
|
# 计时器
|
|
|
|
|
def __init__(self, root):
|
|
|
|
|
self.root = root
|
|
|
|
|
self.elapsed = 0.0
|
|
|
|
|
self.running = False
|
|
|
|
|
self.last_start_time = None
|
|
|
|
|
self.timestr = tk.IntVar() # 创建可变数据类型
|
|
|
|
|
self.min = tk.IntVar() # 创建可变数据类型
|
|
|
|
|
self.sec = tk.IntVar() # 创建可变数据类型
|
|
|
|
|
self.timestr.set(0) # 只能数值不能等于号
|
|
|
|
|
|
|
|
|
|
self.starttime = 0 # 开始计时时间
|
|
|
|
|
self.elapsedtime = 0.0 # 计时器统计到的时间
|
|
|
|
|
self.timer = None
|
|
|
|
|
self.starttime = time.time() - self.elapsedtime
|
|
|
|
|
self.update()
|
|
|
|
|
self.win = 0
|
|
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
|
self.elapsedtime = int(time.time() - self.starttime)
|
|
|
|
|
self.timestr.set(self.elapsedtime)
|
|
|
|
|
self.min.set(self.elapsedtime // 60)
|
|
|
|
|
self.sec.set(self.elapsedtime - self.min.get() * 60)
|
|
|
|
|
self.timer = self.root.after(100, self.update)
|
|
|
|
|
|
|
|
|
|
def restart(self):
|
|
|
|
|
self.win = 0
|
|
|
|
|
self.elapsedtime = 0.0
|
|
|
|
|
self.starttime = time.time() - self.elapsedtime
|
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
|
if self.win:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
self.win = 1
|
|
|
|
|
self.root.after_cancel(self.timer)
|
|
|
|
|
self.elapsedtime = int(time.time() - self.starttime)
|
|
|
|
|
now = int(time.time() - self.starttime)
|
|
|
|
|
self.timestr.set(now)
|
|
|
|
|
self.min.set(now // 60)
|
|
|
|
|
self.sec.set(now - self.min.get() * 60)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def draw_all_rect(canvas):
|
|
|
|
|
rect_mapping = dict()
|
|
|
|
|
block_color = [3, 4, 5] # 显色宫格依据
|
|
|
|
|
for row in range(9):
|
|
|
|
|
for col in range(9):
|
|
|
|
|
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:
|
|
|
|
|
color = "#FAE067"
|
|
|
|
|
else:
|
|
|
|
|
color = 'white'
|
|
|
|
|
x, y = mapping[row, col]
|
|
|
|
|
rect = canvas.create_rectangle(x, y, x + side, y + side, fill=color, width=0) # 绘制一个方格
|
|
|
|
|
rect_mapping[row, col] = rect
|
|
|
|
|
return rect_mapping
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def draw_info(canvas):
|
|
|
|
|
top_x = (side + 3) * 11 # 文本框顶点x
|
|
|
|
|
top_y = 50 # 文本框顶点y
|
|
|
|
|
bc_x = (side + 3) * 7 + 20 # 文本框宽度
|
|
|
|
|
bc_y = (side + 3) * 12 # 文本框高度
|
|
|
|
|
|
|
|
|
|
info = tk.Frame(canvas, bg=WHITE, relief="sunken", width=bc_x, height=bc_y)
|
|
|
|
|
info.place(x=top_x, y=top_y, anchor=tk.NW) # 右边栏
|
|
|
|
|
info_labels.append(info)
|
|
|
|
|
return info
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# def label_destroy_info(labels: list[tk.Label], canvas):
|
|
|
|
|
# """销毁label"""
|
|
|
|
|
# for label in labels:
|
|
|
|
|
# label.destroy()
|
|
|
|
|
# draw_info(canvas)
|
|
|
|
|
|
|
|
|
|
def label_destroy_info(labels: List[tk.Label], canvas):
|
|
|
|
|
"""销毁label"""
|
|
|
|
|
for label in labels:
|
|
|
|
|
label.destroy()
|
|
|
|
|
draw_info(canvas)
|
|
|
|
|
|
|
|
|
|
def show_Time(right: tk.Frame, timer: MyTimer):
|
|
|
|
|
'''
|
|
|
|
|
显示计时器
|
|
|
|
|
:param timer:计时器示例
|
|
|
|
|
:return:
|
|
|
|
|
'''
|
|
|
|
|
Time = tk.Label(right, text="运行时间: 分 秒", bg=WHITE, fg=BLACK, font=('幼圆', 16, 'bold'), anchor=tk.W)
|
|
|
|
|
Time.place(x=30, y=30, width=340, height=30)
|
|
|
|
|
Min = tk.Label(right, textvariable=timer.min, bg=WHITE, fg=BLACK, font=('幼圆', 16, 'bold')) # 分钟计数
|
|
|
|
|
Min.place(x=150, y=30, width=30, height=30)
|
|
|
|
|
Sec = tk.Label(right, textvariable=timer.sec, bg=WHITE, fg=BLACK, font=('幼圆', 16, 'bold')) # 秒钟计数
|
|
|
|
|
Sec.place(x=220, y=30, width=30, height=30)
|
|
|
|
|
info_labels.append(Time)
|
|
|
|
|
info_labels.append(Min)
|
|
|
|
|
info_labels.append(Sec)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def difficulty():
|
|
|
|
|
"""
|
|
|
|
|
难度显示:
|
|
|
|
|
:param empty: 原始空格数目
|
|
|
|
|
:return:
|
|
|
|
|
"""
|
|
|
|
|
count = 0 # 计数
|
|
|
|
|
for i in range(9):
|
|
|
|
|
for j in range(9):
|
|
|
|
|
if martix[i][j] == 0 or martix[i][j] == 10:
|
|
|
|
|
count += 1
|
|
|
|
|
Level = tk.Label(info, text="难度:{:.2f}".format(count / 81), bg=WHITE, fg=BLACK, font=('幼圆', 16, 'bold'),
|
|
|
|
|
anchor=tk.W)
|
|
|
|
|
Level.place(x=30, y=60, width=300, height=30)
|
|
|
|
|
info_labels.append(Level)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def noter():
|
|
|
|
|
'''
|
|
|
|
|
显示笔记提示
|
|
|
|
|
:param mark: 笔记模式是否开启
|
|
|
|
|
:return:
|
|
|
|
|
'''
|
|
|
|
|
note_help1 = tk.Label(info, text=f"False 时保存笔记,当前笔记:{note_mark}", bg=WHITE, fg=RED,
|
|
|
|
|
font=('幼圆', 12, 'bold'), anchor=tk.W)
|
|
|
|
|
note_help1.place(x=30, y=90, width=300, height=30)
|
|
|
|
|
info_labels.append(note_help1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def seq_recode():
|
|
|
|
|
'''
|
|
|
|
|
显示步骤
|
|
|
|
|
'''
|
|
|
|
|
note_help1 = tk.Label(info, text=f"步骤记录:", bg=WHITE, fg=RED, font=('幼圆', 12, 'bold'), anchor=tk.W)
|
|
|
|
|
note_help1.place(x=30, y=120, width=300, height=30)
|
|
|
|
|
scr = scrolledtext.ScrolledText(info, fg='red', font=('幼圆', 16, 'bold')) # 设置一个可滚动文本框
|
|
|
|
|
scr.place(x=30, y=150, width=280, height=300) #
|
|
|
|
|
|
|
|
|
|
for i in range(len(STEP)):
|
|
|
|
|
scr.insert('end', f"{i + 1} {STEP[i][:2]}\n") # 末尾插入
|
|
|
|
|
scr.config(state=tk.DISABLED) # 设置文本框为 “不能编辑”
|
|
|
|
|
scr.see(tk.END) # 将视图移到末尾
|
|
|
|
|
|
|
|
|
|
info_labels.append(note_help1)
|
|
|
|
|
info_labels.append(scr)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def basics_info():
|
|
|
|
|
difficulty()
|
|
|
|
|
noter()
|
|
|
|
|
seq_recode()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def draw_one_num(x, y, num, color="black", tags=None):
|
|
|
|
|
"""显示一个数字"""
|
|
|
|
|
if num != 0:
|
|
|
|
|
canvas.create_text(x + side / 2, y + side / 2, text=num,
|
|
|
|
|
font=('幼圆', 18, 'bold'), fill=color, tags=tags)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def show_usr_num():
|
|
|
|
|
"""显示所有用户数字"""
|
|
|
|
|
canvas.delete("usr_input")
|
|
|
|
|
canvas.delete("usr_num")
|
|
|
|
|
for row in range(9):
|
|
|
|
|
for col in range(9):
|
|
|
|
|
if martix[row, col] == 0:
|
|
|
|
|
x, y = mapping[row, col]
|
|
|
|
|
draw_one_num(x, y, u_martix[row, col], "blue", tags="usr_num")
|
|
|
|
|
if all_hint_mark:
|
|
|
|
|
show_all_hint()
|
|
|
|
|
|
|
|
|
|
def show_fixa_num():
|
|
|
|
|
"""显示固定数字"""
|
|
|
|
|
canvas.delete("fixa_num")
|
|
|
|
|
canvas.delete("set_fixa_num")
|
|
|
|
|
for i in range(9):
|
|
|
|
|
for n in range(9):
|
|
|
|
|
x, y = mapping[i, n]
|
|
|
|
|
draw_one_num(x, y, martix[i, n], tags="fixa_num")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def show_set_all_num():
|
|
|
|
|
global set_martix
|
|
|
|
|
canvas.delete("fixa_num")
|
|
|
|
|
canvas.delete("set_fixa_num")
|
|
|
|
|
for i in range(9):
|
|
|
|
|
for n in range(9):
|
|
|
|
|
x, y = mapping[i, n]
|
|
|
|
|
draw_one_num(x, y, set_martix[i, n], tags="set_fixa_num")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def click_event(event):
|
|
|
|
|
print(event.x, event.y)
|
|
|
|
|
global row, col, set_martix, cell_info_label # 全局坐标映射,方便其他功能知道操作单元格
|
|
|
|
|
x = event.x
|
|
|
|
|
y = event.y
|
|
|
|
|
for key, posit_lt in mapping.items():
|
|
|
|
|
if posit_lt[0] < x < posit_lt[0] + side and posit_lt[1] < y < posit_lt[1] + side:
|
|
|
|
|
row, col = key[0], key[1]
|
|
|
|
|
if set_question_mark:
|
|
|
|
|
set_martix[row, col] = 0
|
|
|
|
|
show_set_all_num()
|
|
|
|
|
else:
|
|
|
|
|
draw(row, col)
|
|
|
|
|
print(key)
|
|
|
|
|
if possible_num_mark:
|
|
|
|
|
if row >= 0:
|
|
|
|
|
if cell_info_label:
|
|
|
|
|
# cell_info_label = tk.Label(info, text=f"当前选中单元格:{row}-{col}", bg=WHITE, font=("幼圆", 12, "bold"))
|
|
|
|
|
cell_info_label.config(text=f"当前选中单元格:{row}-{col}")
|
|
|
|
|
lebel_width = cell_info_label.winfo_reqwidth()
|
|
|
|
|
x = 160
|
|
|
|
|
x = x - lebel_width / 2
|
|
|
|
|
cell_info_label.place(x=x, y=105, )
|
|
|
|
|
else:
|
|
|
|
|
if cell_info_label:
|
|
|
|
|
cell_info_label.config(text=f"请选中一个单元格以开始实验")
|
|
|
|
|
lebel_width = cell_info_label.winfo_reqwidth()
|
|
|
|
|
x = 160
|
|
|
|
|
x = x - lebel_width / 2
|
|
|
|
|
cell_info_label.place(x=x, y=105, )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def draw_mini_num(row, col, possible: set, color: str, tags="mini_num"):
|
|
|
|
|
hint_bc = int(side // 3) # 小数字的间距
|
|
|
|
|
x, y = mapping[row, col]
|
|
|
|
|
x, y = x + side / 2, y + side / 2 # 计算大方格中点坐标
|
|
|
|
|
x = x - hint_bc # 计算左上角第一个数字坐标
|
|
|
|
|
y = y - hint_bc # 计算左上角第一个数字坐标
|
|
|
|
|
for ii in range(3): # 按照九宫格显示小数字
|
|
|
|
|
for jj in range(3):
|
|
|
|
|
n = ii * 3 + jj + 1 # 遍历1~9
|
|
|
|
|
if len(possible) != 0: # 在用户已填的部分有可能导致部分格子无解,所以先加一个判断
|
|
|
|
|
for k in possible:
|
|
|
|
|
if n == k: # 如果possible[row][col]中含有k,则说明该格子可以填k,则将k显示在方格中
|
|
|
|
|
canvas.create_text(x + ii * hint_bc, y + jj * hint_bc,
|
|
|
|
|
text=f"{n}", font=('hei', 12, "bold"), fill=color, tags=tags)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def hint_on_off():
|
|
|
|
|
global hint_mark
|
|
|
|
|
if hint_mark == None:
|
|
|
|
|
show_hint()
|
|
|
|
|
hint_mark = 1
|
|
|
|
|
else:
|
|
|
|
|
canvas.delete("one_hint")
|
|
|
|
|
hint_mark = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def show_hint():
|
|
|
|
|
"""提示"""
|
|
|
|
|
global row, col
|
|
|
|
|
tags = "one_hint"
|
|
|
|
|
canvas.delete(tags)
|
|
|
|
|
if row != None and u_martix[row, col] == 0:
|
|
|
|
|
possible = GetPossible(u_martix, row, col)
|
|
|
|
|
draw_mini_num(row, col, possible, "green", tags)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def all_note_on_off():
|
|
|
|
|
"""一键笔记控制"""
|
|
|
|
|
global all_hint_mark
|
|
|
|
|
if not all_hint_mark:
|
|
|
|
|
show_all_hint()
|
|
|
|
|
all_hint_mark = True
|
|
|
|
|
else:
|
|
|
|
|
canvas.delete("mini_num")
|
|
|
|
|
all_hint_mark = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def show_all_hint():
|
|
|
|
|
"""一键笔记"""
|
|
|
|
|
canvas.delete("mini_num")
|
|
|
|
|
for row in range(9):
|
|
|
|
|
for col in range(9):
|
|
|
|
|
if set_question_mark:
|
|
|
|
|
if set_martix[row, col] == 0:
|
|
|
|
|
possible = GetPossible(set_martix, row, col)
|
|
|
|
|
draw_mini_num(row, col, possible, "grey")
|
|
|
|
|
else:
|
|
|
|
|
if u_martix[row, col] == 0:
|
|
|
|
|
possible = GetPossible(u_martix, row, col)
|
|
|
|
|
draw_mini_num(row, col, possible, "grey")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def note_on_off():
|
|
|
|
|
global note_mark, usr_note_dict
|
|
|
|
|
if not note_mark:
|
|
|
|
|
note_mark = True
|
|
|
|
|
else:
|
|
|
|
|
note_mark = False
|
|
|
|
|
noter()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def number_button(root):
|
|
|
|
|
'''
|
|
|
|
|
绘制数字按钮
|
|
|
|
|
:param side: 全局按钮大小
|
|
|
|
|
:return:
|
|
|
|
|
'''
|
|
|
|
|
for i in range(9): # 遍历0~9
|
|
|
|
|
top_x, top_y = i * (side + 3) + 50, 12 * (side + 3) + 10 # 计算每个按钮左上角坐标
|
|
|
|
|
B = tk.Button(root, text=f"{i + 1}", bg='white', fg='black',
|
|
|
|
|
font=('幼圆', 14, 'bold'), command=lambda num=i + 1: usr_input(row, col, num))
|
|
|
|
|
B.place(x=top_x, y=top_y, width=side + 3, height=side + 3) # 绘制按钮到图上
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def control_button(root, side):
|
|
|
|
|
'''
|
|
|
|
|
绘制五个控制按键
|
|
|
|
|
:param side:全局按钮大小
|
|
|
|
|
:return:
|
|
|
|
|
'''
|
|
|
|
|
global loca, loca_o
|
|
|
|
|
lon = 9 * (side + 3) + 50
|
|
|
|
|
lon = lon // 5 - 12 # 控制按键长度
|
|
|
|
|
ctl = ["撤回", "擦除", "笔记", "一键笔记", "提示"]
|
|
|
|
|
# 撤回
|
|
|
|
|
B1 = tk.Button(root, text=f"撤回", bg='white', fg='black',
|
|
|
|
|
font=('幼圆', 12, 'bold'), command=backspace)
|
|
|
|
|
B1.place(x=(lon + 2) * 0 + 50, y=(side + 3) * 11 + 8, width=lon, height=side)
|
|
|
|
|
# 擦除
|
|
|
|
|
B2 = tk.Button(root, text=f"擦除", bg='white', fg='black',
|
|
|
|
|
font=('幼圆', 12, 'bold'), command=delete_ctrl)
|
|
|
|
|
B2.place(x=(lon + 2) * 1 + 50, y=(side + 3) * 11 + 8, width=lon, height=side)
|
|
|
|
|
# 笔记
|
|
|
|
|
B3 = tk.Button(root, text=f"笔记", bg='white', fg='black',
|
|
|
|
|
font=('幼圆', 12, 'bold'), command=note_on_off)
|
|
|
|
|
B3.place(x=(lon + 2) * 2 + 50, y=(side + 3) * 11 + 8, width=lon, height=side)
|
|
|
|
|
# 一键笔记
|
|
|
|
|
B4 = tk.Button(root, text=f"一键笔记", bg='white', fg='black',
|
|
|
|
|
font=('幼圆', 12, 'bold'), command=all_note_on_off)
|
|
|
|
|
B4.place(x=(lon + 2) * 3 + 50, y=(side + 3) * 11 + 8, width=lon, height=side)
|
|
|
|
|
# 提示
|
|
|
|
|
B5 = tk.Button(root, text=f"提示", bg='white', fg='black',
|
|
|
|
|
font=('幼圆', 12, 'bold'), command=hint_on_off)
|
|
|
|
|
B5.place(x=(lon + 2) * 4 + 50, y=(side + 3) * 11 + 8, width=lon, height=side)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def restart():
|
|
|
|
|
for child in info.winfo_children():
|
|
|
|
|
child.destroy()
|
|
|
|
|
canvas.delete("usr_input")
|
|
|
|
|
global u_martix, info_labels, note_mark, all_hint_mark, STEP, row, col
|
|
|
|
|
global usr_note_dict, mapping, time1, set_question_mark, r_step, hint_mark
|
|
|
|
|
global possible_num_mark
|
|
|
|
|
u_martix = martix.copy()
|
|
|
|
|
info_labels = [] # label对象列表
|
|
|
|
|
note_mark = False # 笔记标志
|
|
|
|
|
all_hint_mark = False # 一键笔记标记
|
|
|
|
|
STEP = [] # 回撤存储列表
|
|
|
|
|
set_question_mark = False # 手动挖空标志
|
|
|
|
|
r_step = list() # 单步记录列表
|
|
|
|
|
hint_mark = None # 提示状态
|
|
|
|
|
possible_num_mark = False
|
|
|
|
|
|
|
|
|
|
row = None
|
|
|
|
|
col = None
|
|
|
|
|
|
|
|
|
|
usr_note_dict = creat_note_dict() # 记录对应单元格笔记数字
|
|
|
|
|
mapping = creat_martix_mapping(side)
|
|
|
|
|
basics_info()
|
|
|
|
|
|
|
|
|
|
seq_recode()
|
|
|
|
|
show_usr_num()
|
|
|
|
|
show_fixa_num()
|
|
|
|
|
canvas.delete("mini_num")
|
|
|
|
|
time1 = MyTimer(root)
|
|
|
|
|
show_Time(info, time1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def game_menu(menu: tk.Menu):
|
|
|
|
|
"""游戏菜单显示"""
|
|
|
|
|
menu_node = tk.Menu(menu, tearoff=False)
|
|
|
|
|
menu_node.add_command(label="重新开始", command=lambda: restart())
|
|
|
|
|
menu_node.add_command(label="暂停计时", command=lambda: time1.stop())
|
|
|
|
|
menu_node.add_command(label="载入题目", command=lambda: load_game())
|
|
|
|
|
# 在主目录菜单上新增"菜单"选项,并通过menu参数与下拉菜单绑定
|
|
|
|
|
menu.add_cascade(label="游戏设置", menu=menu_node)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def auto_menu(menu: tk.Menu):
|
|
|
|
|
"""自动求解菜单显示"""
|
|
|
|
|
menu_node = tk.Menu(menu, tearoff=False)
|
|
|
|
|
menu_node.add_command(label="自动求解-顺序求解", command=launch_auto)
|
|
|
|
|
menu_node.add_command(label="自动求解-优化", command=launch_auto_better)
|
|
|
|
|
fmenu = tk.Menu(menu, tearoff=False)
|
|
|
|
|
fmenu.add_command(label='低速', command=lambda: speed_set(0.5))
|
|
|
|
|
fmenu.add_command(label='中速', command=lambda: speed_set(0.2))
|
|
|
|
|
fmenu.add_command(label='高速', command=lambda: speed_set(0))
|
|
|
|
|
menu_node.add_cascade(label="求解速度选择", menu=fmenu)
|
|
|
|
|
# 在主目录菜单上新增"菜单"选项,并通过menu参数与下拉菜单绑定
|
|
|
|
|
menu.add_cascade(label="自动求解", menu=menu_node)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def question_menu(menu: tk.Menu):
|
|
|
|
|
menu_node = tk.Menu(menu, tearoff=False)
|
|
|
|
|
menu_node.add_command(label="手动出题", command=lambda: auto_question())
|
|
|
|
|
menu_node.add_command(label="挖空出题", command=lambda: set_question())
|
|
|
|
|
menu_node.add_command(label="单步求解模式", command=lambda: one_step_ctrl())
|
|
|
|
|
menu_node.add_command(label="手动解预期数", command=lambda: show_possible_num())
|
|
|
|
|
menu.add_cascade(label="手动模式", menu=menu_node)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def one_step_ctrl():
|
|
|
|
|
global martix, u_martix
|
|
|
|
|
for w in info.winfo_children():
|
|
|
|
|
w.destroy()
|
|
|
|
|
|
|
|
|
|
info_label = tk.Label(info, text="单步求解模式", bg=WHITE, font=("幼圆", 12, "bold"))
|
|
|
|
|
info_label.place(x=120, y=21)
|
|
|
|
|
|
|
|
|
|
next_step_button = tk.Button(info, text="下一步", font=("幼圆", 12, "bold"), command=lambda: one_step_start(1))
|
|
|
|
|
next_step_button.place(x=100, y=60)
|
|
|
|
|
|
|
|
|
|
next_step_button = tk.Button(info, text="上一步", font=("幼圆", 12, "bold"), command=lambda: one_step_start(-1))
|
|
|
|
|
next_step_button.place(x=180, y=60)
|
|
|
|
|
|
|
|
|
|
one_martix = martix.copy()
|
|
|
|
|
one_step_solve(one_martix) # 运行单步求解函数,获得满记录的r_step列表
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def one_step_start(step):
|
|
|
|
|
global STEP, u_martix, row, col
|
|
|
|
|
index = len(STEP) - 1
|
|
|
|
|
if step == 1 and index + 1 < len(r_step):
|
|
|
|
|
item = r_step[index + 1]
|
|
|
|
|
u_martix = item[2]
|
|
|
|
|
row, col = item[0][0], item[0][1]
|
|
|
|
|
STEP.append(item)
|
|
|
|
|
seq_recode()
|
|
|
|
|
draw(row, col)
|
|
|
|
|
show_usr_num()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
elif step == -1:
|
|
|
|
|
if len(STEP) > 1:
|
|
|
|
|
item = r_step[index - 1]
|
|
|
|
|
u_martix = item[2]
|
|
|
|
|
row, col = item[0][0], item[0][1]
|
|
|
|
|
else:
|
|
|
|
|
u_martix = martix
|
|
|
|
|
try:
|
|
|
|
|
STEP.pop()
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
seq_recode()
|
|
|
|
|
draw(row, col)
|
|
|
|
|
show_usr_num()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def one_step_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 # 将可能的数组填入
|
|
|
|
|
recoder_one(row, col, value, martix)
|
|
|
|
|
if one_step_solve(martix): # 继续深度优先遍历填入数字
|
|
|
|
|
return True # 填完最后一个数字
|
|
|
|
|
martix[row, col] = 0 # 如果当前状况无解则归位,然后回溯
|
|
|
|
|
recoder_one(row, col, value, martix)
|
|
|
|
|
return False
|
|
|
|
|
# 当所有的数字填完,数独求解完毕
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_user_input(entry: tk.Entry):
|
|
|
|
|
global martix, u_martix
|
|
|
|
|
num = entry.get()
|
|
|
|
|
martix = data.InitMartix(int(num))
|
|
|
|
|
u_martix = martix.copy()
|
|
|
|
|
restart()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def auto_question():
|
|
|
|
|
global martix, u_martix
|
|
|
|
|
for w in info.winfo_children():
|
|
|
|
|
w.destroy()
|
|
|
|
|
num_info = tk.Label(info, text="输入挖空数", bg=WHITE, font=('幼圆', 12, 'bold'), anchor=tk.W)
|
|
|
|
|
num_info.place(x=15, y=21)
|
|
|
|
|
num_entry = tk.Entry(info)
|
|
|
|
|
num_entry.config(font=('幼圆', 12, 'bold'), width=10)
|
|
|
|
|
num_entry.place(x=110, y=23)
|
|
|
|
|
get_input_button = tk.Button(info, text="出题", font=('幼圆', 12, 'bold'),
|
|
|
|
|
command=lambda: get_user_input(num_entry))
|
|
|
|
|
get_input_button.place(x=90, y=60)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def question_ok(set_martix):
|
|
|
|
|
global martix, u_martix, set_question_mark
|
|
|
|
|
martix = set_martix
|
|
|
|
|
set_question_mark = False
|
|
|
|
|
restart()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def set_question():
|
|
|
|
|
global martix, u_martix, set_question_mark, set_martix
|
|
|
|
|
martix = data.InitMartix(0)
|
|
|
|
|
set_martix = martix.copy()
|
|
|
|
|
show_fixa_num()
|
|
|
|
|
|
|
|
|
|
for w in info.winfo_children():
|
|
|
|
|
w.destroy()
|
|
|
|
|
num_info = tk.Label(info, text="鼠标左键点击你想挖空的单元格", bg=WHITE, font=('幼圆', 12, 'bold'), anchor=tk.W)
|
|
|
|
|
num_info.place(x=30, y=21)
|
|
|
|
|
|
|
|
|
|
set_question_mark = True
|
|
|
|
|
|
|
|
|
|
get_input_button = tk.Button(info, text="确认", font=('幼圆', 12, 'bold'),
|
|
|
|
|
command=lambda: question_ok(set_martix=set_martix))
|
|
|
|
|
get_input_button.place(x=90, y=60)
|
|
|
|
|
|
|
|
|
|
get_input_button = tk.Button(info, text="取消", font=('幼圆', 12, 'bold'),
|
|
|
|
|
command=set_question)
|
|
|
|
|
get_input_button.place(x=150, y=60)
|
|
|
|
|
|
|
|
|
|
# pprint(martix)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def show_possible_num():
|
|
|
|
|
global martix, u_martix, row_entry, col_entry, big_cell_entry, cell_entry, cell_info_label
|
|
|
|
|
global possible_num_mark
|
|
|
|
|
|
|
|
|
|
possible_num_mark = True
|
|
|
|
|
for w in info.winfo_children():
|
|
|
|
|
w.destroy()
|
|
|
|
|
jx = 75
|
|
|
|
|
info_label = tk.Label(info, text="手动解预期数", bg=WHITE, font=("幼圆", 12, "bold"))
|
|
|
|
|
info_label.place(x=120, y=21)
|
|
|
|
|
|
|
|
|
|
if row and col:
|
|
|
|
|
cell_info_label = tk.Label(info, text=f"当前选中单元格:{row}-{col}", bg=WHITE, font=("幼圆", 12, "bold"))
|
|
|
|
|
lebel_width = cell_info_label.winfo_reqwidth()
|
|
|
|
|
x = 160
|
|
|
|
|
x = x - lebel_width / 2
|
|
|
|
|
cell_info_label.place(x=x, y=105, )
|
|
|
|
|
else:
|
|
|
|
|
cell_info_label = tk.Label(info, text=f"请选中一个单元格以开始实验", bg=WHITE, fg=RED,
|
|
|
|
|
font=("幼圆", 12, "bold"))
|
|
|
|
|
lebel_width = cell_info_label.winfo_reqwidth()
|
|
|
|
|
x = 160
|
|
|
|
|
x = x - lebel_width / 2
|
|
|
|
|
cell_info_label.place(x=x, y=105, )
|
|
|
|
|
|
|
|
|
|
next_cell_button = tk.Button(info, text="自动解", font=("幼圆", 12, "bold"), command=lambda: auto_possible_verify())
|
|
|
|
|
next_cell_button.place(x=100, y=60)
|
|
|
|
|
|
|
|
|
|
next_cell_button1 = tk.Button(info, text="验证", font=("幼圆", 12, "bold"), command=lambda: possible_verify())
|
|
|
|
|
next_cell_button1.place(x=180, y=60)
|
|
|
|
|
|
|
|
|
|
row_label = tk.Label(info, text=f"当前行可填数字:", bg=WHITE, font=("幼圆", 12, "bold"))
|
|
|
|
|
row_label.place(x=20, y=150)
|
|
|
|
|
|
|
|
|
|
row_entry = tk.Entry(info)
|
|
|
|
|
row_entry.place(x=20, y=175)
|
|
|
|
|
row_entry.config(font=('幼圆', 12, 'bold'), width=10)
|
|
|
|
|
|
|
|
|
|
col_label = tk.Label(info, text=f"当前列可填数字:", bg=WHITE, font=("幼圆", 12, "bold"))
|
|
|
|
|
col_label.place(x=20, y=150 + jx)
|
|
|
|
|
|
|
|
|
|
col_entry = tk.Entry(info)
|
|
|
|
|
col_entry.place(x=20, y=175 + jx)
|
|
|
|
|
col_entry.config(font=('幼圆', 12, 'bold'), width=10)
|
|
|
|
|
|
|
|
|
|
big_cell = tk.Label(info, text=f"当前宫格可填数字:", bg=WHITE, font=("幼圆", 12, "bold"))
|
|
|
|
|
big_cell.place(x=20, y=150 + 2 * jx)
|
|
|
|
|
|
|
|
|
|
big_cell_entry = tk.Entry(info)
|
|
|
|
|
big_cell_entry.place(x=20, y=175 + 2 * jx)
|
|
|
|
|
big_cell_entry.config(font=("幼圆", 12, "bold"), width=10)
|
|
|
|
|
|
|
|
|
|
cell = tk.Label(info, text=f"当前格可能填写数字:", bg=WHITE, font=("幼圆", 12, "bold"))
|
|
|
|
|
cell.place(x=20, y=150 + 3 * jx)
|
|
|
|
|
|
|
|
|
|
cell_entry = tk.Entry(info)
|
|
|
|
|
cell_entry.place(x=20, y=175 + 3 * jx)
|
|
|
|
|
cell_entry.config(font=("幼圆", 12, "bold"), width=10)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def possible_verify():
|
|
|
|
|
"""验证功能"""
|
|
|
|
|
global martix, u_martix, row_entry, col_entry, big_cell_entry, cell_entry
|
|
|
|
|
global row, col
|
|
|
|
|
|
|
|
|
|
if row is not None:
|
|
|
|
|
row_nums = row_entry.get()
|
|
|
|
|
row_nums = trans_int_set(row_nums)
|
|
|
|
|
|
|
|
|
|
col_nums = col_entry.get()
|
|
|
|
|
col_nums = trans_int_set(col_nums)
|
|
|
|
|
|
|
|
|
|
big_cell_nums = big_cell_entry.get()
|
|
|
|
|
big_cell_nums = trans_int_set(big_cell_nums)
|
|
|
|
|
|
|
|
|
|
cell_nums = cell_entry.get()
|
|
|
|
|
cell_nums = trans_int_set(cell_nums)
|
|
|
|
|
|
|
|
|
|
row_entry.delete(0, tk.END)
|
|
|
|
|
if get_row_possible(u_martix, row, col) == row_nums:
|
|
|
|
|
row_entry.insert(0, "正确")
|
|
|
|
|
else:
|
|
|
|
|
row_entry.insert(0, "错误")
|
|
|
|
|
|
|
|
|
|
col_entry.delete(0, tk.END)
|
|
|
|
|
if get_col_possible(u_martix, row, col) == col_nums:
|
|
|
|
|
col_entry.insert(0, "正确")
|
|
|
|
|
else:
|
|
|
|
|
col_entry.insert(0, "错误")
|
|
|
|
|
|
|
|
|
|
big_cell_entry.delete(0, tk.END)
|
|
|
|
|
if get_big_cell_possible(u_martix, row, col) == big_cell_nums:
|
|
|
|
|
big_cell_entry.insert(0, "正确")
|
|
|
|
|
else:
|
|
|
|
|
big_cell_entry.insert(0, "错误")
|
|
|
|
|
|
|
|
|
|
cell_entry.delete(0, tk.END)
|
|
|
|
|
if GetPossible(u_martix, row, col) == cell_nums:
|
|
|
|
|
cell_entry.insert(0, "正确")
|
|
|
|
|
else:
|
|
|
|
|
cell_entry.insert(0, "错误")
|
|
|
|
|
|
|
|
|
|
print(row_nums, col_nums, big_cell_nums, cell_nums)
|
|
|
|
|
print(get_row_possible(u_martix, row, col), get_col_possible(u_martix, row, col),
|
|
|
|
|
get_big_cell_possible(u_martix, row, col), GetPossible(u_martix, row, col))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def auto_possible_verify():
|
|
|
|
|
"""验证功能"""
|
|
|
|
|
global martix, u_martix, row_entry, col_entry, big_cell_entry, cell_entry
|
|
|
|
|
global row, col
|
|
|
|
|
|
|
|
|
|
if row is not None:
|
|
|
|
|
row_entry.delete(0, tk.END)
|
|
|
|
|
row_nums = get_row_possible(u_martix, row, col)
|
|
|
|
|
row_nums = [str(i) for i in row_nums]
|
|
|
|
|
row_nums = ",".join(row_nums)
|
|
|
|
|
row_entry.insert(0, row_nums)
|
|
|
|
|
|
|
|
|
|
col_entry.delete(0, tk.END)
|
|
|
|
|
col_nums = get_col_possible(u_martix, row, col)
|
|
|
|
|
col_nums = [str(i) for i in col_nums]
|
|
|
|
|
col_nums = ",".join(col_nums)
|
|
|
|
|
col_entry.insert(0, col_nums)
|
|
|
|
|
|
|
|
|
|
big_cell_entry.delete(0, tk.END)
|
|
|
|
|
big_cell_nums = get_big_cell_possible(u_martix, row, col)
|
|
|
|
|
big_cell_nums = [str(i) for i in big_cell_nums]
|
|
|
|
|
big_cell_nums = ",".join(big_cell_nums)
|
|
|
|
|
big_cell_entry.insert(0, big_cell_nums)
|
|
|
|
|
|
|
|
|
|
cell_entry.delete(0, tk.END)
|
|
|
|
|
cell_nums = GetPossible(u_martix, row, col)
|
|
|
|
|
cell_nums = [str(i) for i in cell_nums]
|
|
|
|
|
cell_nums = ",".join(cell_nums)
|
|
|
|
|
cell_entry.insert(0, cell_nums)
|
|
|
|
|
|
|
|
|
|
print(row_nums, col_nums, big_cell_nums, cell_nums)
|
|
|
|
|
print(get_row_possible(u_martix, row, col), get_col_possible(u_martix, row, col),
|
|
|
|
|
get_big_cell_possible(u_martix, row, col), GetPossible(u_martix, row, col))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def trans_int_set(nums: str):
|
|
|
|
|
nums = re.findall(r"\d+", nums)
|
|
|
|
|
nums = "".join(nums)
|
|
|
|
|
Set = set()
|
|
|
|
|
for num in list(nums):
|
|
|
|
|
Set.add(int(num))
|
|
|
|
|
return Set
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_row_possible(martix, row, col):
|
|
|
|
|
"""当前行的可能数字"""
|
|
|
|
|
Nums = {1, 2, 3, 4, 5, 6, 7, 8, 9}
|
|
|
|
|
Set = set()
|
|
|
|
|
for i in range(9):
|
|
|
|
|
if i == row:
|
|
|
|
|
continue
|
|
|
|
|
Set.add(int(martix[i, col])) # 将所在列出现数字加入集合
|
|
|
|
|
# print(martix[i,col])
|
|
|
|
|
return Nums - Set
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_col_possible(martix, row, col):
|
|
|
|
|
"""当前列的可能数字"""
|
|
|
|
|
Nums = {1, 2, 3, 4, 5, 6, 7, 8, 9}
|
|
|
|
|
Set = set()
|
|
|
|
|
for i in range(9):
|
|
|
|
|
if i == col:
|
|
|
|
|
continue
|
|
|
|
|
Set.add(int(martix[row, i])) # 将所在列出现数字加入集合
|
|
|
|
|
# print(martix[row,i])
|
|
|
|
|
return Nums - Set
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_big_cell_possible(martix, row, col):
|
|
|
|
|
"""当前宫格可能的数字"""
|
|
|
|
|
Nums = {1, 2, 3, 4, 5, 6, 7, 8, 9}
|
|
|
|
|
Set = set()
|
|
|
|
|
m, n = row // 3, col // 3 # 计算所在九宫格的编号
|
|
|
|
|
for i in range(m * 3, m * 3 + 3):
|
|
|
|
|
for j in range(n * 3, n * 3 + 3):
|
|
|
|
|
if row == i and j == col:
|
|
|
|
|
continue
|
|
|
|
|
Set.add(int(martix[i, j])) # 将所在九宫格出现数字加入集合
|
|
|
|
|
# print(martix[i,j])
|
|
|
|
|
return Nums - Set # 返回1~9中没出现过的数字,即可选的
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def next_cell_query():
|
|
|
|
|
for row in range(9):
|
|
|
|
|
for col in range(9):
|
|
|
|
|
if martix[row, col] == 0:
|
|
|
|
|
return row, col
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def speed_set(num):
|
|
|
|
|
global wait_time
|
|
|
|
|
wait_time = num
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def launch_auto():
|
|
|
|
|
time1.restart()
|
|
|
|
|
auto_Solve(u_martix)
|
|
|
|
|
win(u_martix, time1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def auto_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 # 将可能的数组填入
|
|
|
|
|
|
|
|
|
|
draw(row, col)
|
|
|
|
|
recoder(row, col, value, u_martix)
|
|
|
|
|
show_usr_num()
|
|
|
|
|
canvas.update_idletasks()
|
|
|
|
|
time.sleep(wait_time) # 防止运算过快,减慢演算步骤
|
|
|
|
|
|
|
|
|
|
if auto_Solve(martix): # 继续深度优先遍历填入数字
|
|
|
|
|
return True # 填完最后一个数字
|
|
|
|
|
|
|
|
|
|
martix[row, col] = 0 # 如果当前状况无解则归位,然后回溯
|
|
|
|
|
recoder(row, col, value, u_martix)
|
|
|
|
|
draw(row, col)
|
|
|
|
|
show_usr_num()
|
|
|
|
|
canvas.update()
|
|
|
|
|
time.sleep(wait_time) # 防止运算过快,减慢演算步骤
|
|
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
# 当所有的数字填完,数独求解完毕
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def recoder_one(row, col, num, u_martix):
|
|
|
|
|
# 返回记录表
|
|
|
|
|
global r_step
|
|
|
|
|
step_martix = u_martix.copy()
|
|
|
|
|
r_step.append([(row, col), num, step_martix])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def recoder(row, col, num, u_martix):
|
|
|
|
|
global STEP
|
|
|
|
|
step_martix = u_martix.copy()
|
|
|
|
|
if len(STEP) > 0:
|
|
|
|
|
old_row, old_col = STEP[-1][0]
|
|
|
|
|
if old_row == row and old_col == col:
|
|
|
|
|
STEP[-1] = [(row, col), num, step_martix]
|
|
|
|
|
else:
|
|
|
|
|
STEP.append([(row, col), num, step_martix])
|
|
|
|
|
else:
|
|
|
|
|
STEP.append([(row, col), num, step_martix])
|
|
|
|
|
seq_recode()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def launch_auto_better():
|
|
|
|
|
time1.restart()
|
|
|
|
|
auto_Solve_better(u_martix)
|
|
|
|
|
win(u_martix, time1)
|
|
|
|
|
noter()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def auto_Solve_better(u_M):
|
|
|
|
|
global note_mark
|
|
|
|
|
note_mark = False # 关闭笔记
|
|
|
|
|
|
|
|
|
|
flag = 0
|
|
|
|
|
# 优化:如果某个位置只有一个可能值,则先填这个格子
|
|
|
|
|
for row in range(9):
|
|
|
|
|
for col in range(9):
|
|
|
|
|
if u_M[row, col] == 0:
|
|
|
|
|
possible = GetPossible(u_M, row, col) # 所有的可能的数字
|
|
|
|
|
if len(possible) == 1:
|
|
|
|
|
flag = 1 # 标记可以进行求解优化
|
|
|
|
|
value = possible.pop() # 只有一个可能数组,则直接将该数字填入
|
|
|
|
|
u_M[row, col] = value # 将确定的数字填入填入
|
|
|
|
|
|
|
|
|
|
draw(row, col)
|
|
|
|
|
canvas.update()
|
|
|
|
|
time.sleep(wait_time) # 防止运算过快,减慢演算步骤
|
|
|
|
|
recoder(row, col, value, u_martix)
|
|
|
|
|
show_usr_num()
|
|
|
|
|
|
|
|
|
|
time.sleep(wait_time) # 停顿一段时间,显示求解步骤
|
|
|
|
|
if auto_Solve_better(u_M): # 继续深度优先遍历填入数字
|
|
|
|
|
return True # 填完最后一个数字
|
|
|
|
|
u_M[row, col] = 0 # 如果当前填入的数字会导致后面无解则依然填入0表示空白待填
|
|
|
|
|
|
|
|
|
|
draw(row, col)
|
|
|
|
|
canvas.update()
|
|
|
|
|
time.sleep(wait_time) # 防止运算过快,减慢演算步骤
|
|
|
|
|
recoder(row, col, value, u_martix)
|
|
|
|
|
|
|
|
|
|
show_usr_num()
|
|
|
|
|
time.sleep(wait_time) # 停顿一段时间,显示求解步骤
|
|
|
|
|
if not flag: # 若没有能直接确定的格子,则按原方法进行求解
|
|
|
|
|
for row in range(9):
|
|
|
|
|
for col in range(9):
|
|
|
|
|
if u_M[row, col] == 0:
|
|
|
|
|
possible = GetPossible(u_M, row, col) # 所有的可能的数字
|
|
|
|
|
|
|
|
|
|
for value in possible:
|
|
|
|
|
u_M[row, col] = value # 将可能的数组填入
|
|
|
|
|
recoder(row, col, value, u_martix)
|
|
|
|
|
draw(row, col)
|
|
|
|
|
|
|
|
|
|
canvas.update()
|
|
|
|
|
time.sleep(wait_time) # 防止运算过快,减慢演算步骤
|
|
|
|
|
|
|
|
|
|
show_usr_num()
|
|
|
|
|
|
|
|
|
|
time.sleep(wait_time) # 停顿一段时间,显示求解步骤
|
|
|
|
|
if auto_Solve_better(u_M): # 继续深度优先遍历填入数字
|
|
|
|
|
return True # 填完最后一个数字
|
|
|
|
|
u_M[row, col] = 0 # 如果当前填入的数字会导致后面无解则依然填入0表示空白待填
|
|
|
|
|
|
|
|
|
|
draw(row, col)
|
|
|
|
|
|
|
|
|
|
canvas.update()
|
|
|
|
|
time.sleep(wait_time) # 防止运算过快,减慢演算步骤
|
|
|
|
|
recoder(row, col, value, u_martix)
|
|
|
|
|
|
|
|
|
|
show_usr_num()
|
|
|
|
|
|
|
|
|
|
time.sleep(wait_time) # 停顿一段时间,显示求解步骤
|
|
|
|
|
return False
|
|
|
|
|
return True # 当所有的数字填完,数独求解完毕
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def win(u_martix, timer: MyTimer):
|
|
|
|
|
count = 0 # 计数
|
|
|
|
|
|
|
|
|
|
for i in range(9):
|
|
|
|
|
for j in range(9):
|
|
|
|
|
if u_martix[i][j] == 0 or u_martix[i][j] == 10:
|
|
|
|
|
count += 1
|
|
|
|
|
if count == 0:
|
|
|
|
|
if Judge(u_martix):
|
|
|
|
|
for w in info.winfo_children():
|
|
|
|
|
w.destroy()
|
|
|
|
|
timer.stop()
|
|
|
|
|
win_words = tk.Label(info, text=f"游戏结束,恭喜通过", bg='white', fg='red', font=('幼圆', 16, 'bold'),
|
|
|
|
|
anchor=tk.W)
|
|
|
|
|
win_words.place(relx=0.1, rely=0.3)
|
|
|
|
|
win_time = tk.Label(info, text=f"耗时:{timer.min.get()}分{timer.sec.get()}秒", bg='white', fg='red',
|
|
|
|
|
font=('幼圆', 16, 'bold'), anchor=tk.W)
|
|
|
|
|
win_time.place(relx=0.1, rely=0.4)
|
|
|
|
|
win_step = tk.Label(info, text=f"花费步数:{len(STEP)}步", bg='white', fg='red',
|
|
|
|
|
font=('幼圆', 16, 'bold'), anchor=tk.W)
|
|
|
|
|
win_step.place(relx=0.1, rely=0.5)
|
|
|
|
|
re = tk.Button(info, text=f"重新开始", bg='white', fg='black',
|
|
|
|
|
font=('幼圆', 14, 'bold'), command=lambda: restart())
|
|
|
|
|
re.place(relx=0.1, rely=0.6, relwidth=0.5)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def load_game():
|
|
|
|
|
global martix, u_martix
|
|
|
|
|
martix = data.InitMartix(30)
|
|
|
|
|
pprint(martix)
|
|
|
|
|
restart()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def draw(row, col):
|
|
|
|
|
rect_color(row, col)
|
|
|
|
|
select_rect_color(row, col)
|
|
|
|
|
# show_usr_num()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def show_all_note():
|
|
|
|
|
canvas.delete("usr_note")
|
|
|
|
|
for i in range(9):
|
|
|
|
|
for n in range(9):
|
|
|
|
|
possible = usr_note_dict[i, n]
|
|
|
|
|
draw_mini_num(i, n, possible, "red", "usr_note")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def delete_ctrl():
|
|
|
|
|
"""擦除功能"""
|
|
|
|
|
global u_martix, usr_note_dict
|
|
|
|
|
if row != None:
|
|
|
|
|
if martix[row, col] == 0:
|
|
|
|
|
canvas.delete("usr_input")
|
|
|
|
|
u_martix[row, col] = 0
|
|
|
|
|
show_usr_num()
|
|
|
|
|
if len(usr_note_dict[row, col]) != 0:
|
|
|
|
|
usr_note_dict[row, col] = set()
|
|
|
|
|
show_all_note()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def backspace():
|
|
|
|
|
"""撤回功能"""
|
|
|
|
|
global STEP, u_martix, row, col
|
|
|
|
|
if len(STEP) > 0:
|
|
|
|
|
loca, num, step_martix = STEP.pop()
|
|
|
|
|
u_martix = step_martix
|
|
|
|
|
row, col = loca
|
|
|
|
|
seq_recode()
|
|
|
|
|
delete_ctrl()
|
|
|
|
|
draw(row, col)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def usr_input(row, col, num, color="blue"):
|
|
|
|
|
global STEP
|
|
|
|
|
if not note_mark:
|
|
|
|
|
if row != None and martix[row, col] == 0:
|
|
|
|
|
canvas.delete("usr_input")
|
|
|
|
|
canvas.delete("usr_note")
|
|
|
|
|
canvas.delete("mini_num")
|
|
|
|
|
|
|
|
|
|
step_martix = u_martix.copy()
|
|
|
|
|
|
|
|
|
|
u_martix[row, col] = num
|
|
|
|
|
usr_note_dict[row, col] = set()
|
|
|
|
|
x, y = mapping[row, col]
|
|
|
|
|
draw_one_num(x, y, num, color, "usr_input")
|
|
|
|
|
u_martix[row, col] = num
|
|
|
|
|
show_all_note()
|
|
|
|
|
show_usr_num()
|
|
|
|
|
|
|
|
|
|
if len(STEP) > 0:
|
|
|
|
|
old_row, old_col = STEP[-1][0]
|
|
|
|
|
if old_row == row and old_col == col:
|
|
|
|
|
STEP[-1] = [(row, col), num, step_martix]
|
|
|
|
|
else:
|
|
|
|
|
STEP.append([(row, col), num, step_martix])
|
|
|
|
|
else:
|
|
|
|
|
STEP.append([(row, col), num, step_martix])
|
|
|
|
|
seq_recode()
|
|
|
|
|
win(u_martix, time1)
|
|
|
|
|
else:
|
|
|
|
|
if row != None and martix[row, col] == 0:
|
|
|
|
|
u_martix[row, col] = 0
|
|
|
|
|
usr_note_dict[row, col].add(num)
|
|
|
|
|
draw_mini_num(row, col, usr_note_dict[row, col], "red", "usr_note")
|
|
|
|
|
show_usr_num()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rect_color(row, col): # 显示当前选中格之外所有颜色
|
|
|
|
|
block_color = [3, 4, 5] # 显色宫格依据
|
|
|
|
|
for key, item in rect_mapping.items():
|
|
|
|
|
if key[0] != row and key[1] != col:
|
|
|
|
|
logi_row = key[0] in block_color and key[1] in block_color # 显色逻辑
|
|
|
|
|
logi_col = key[0] in block_color or key[1] in block_color # 显色逻辑
|
|
|
|
|
if not logi_row and logi_col:
|
|
|
|
|
color = "#FAE067"
|
|
|
|
|
canvas.itemconfig(item, fill=color)
|
|
|
|
|
else:
|
|
|
|
|
color = 'white'
|
|
|
|
|
canvas.itemconfig(item, fill=color)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def select_rect_color(row, col): # 突出显示当前选中格
|
|
|
|
|
for key, item in rect_mapping.items():
|
|
|
|
|
if key[0] == row and key[1] == col:
|
|
|
|
|
canvas.itemconfig(item, fill='#DCA0DC')
|
|
|
|
|
elif key[0] == row or key[1] == col:
|
|
|
|
|
canvas.itemconfig(item, fill='#ECD0EC')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
root = tk.Tk()
|
|
|
|
|
root.title("数独") # 设置窗口标题
|
|
|
|
|
width, height = 840, 610 # 设置长宽
|
|
|
|
|
root.geometry(f'{width}x{height}') # 设置窗口大小
|
|
|
|
|
canvas = tk.Canvas(root, bg=WHITE, bd=2, width=width, height=height, background=ORANGE,
|
|
|
|
|
highlightthickness=0) # 设置画布
|
|
|
|
|
canvas.place(x=0, y=0, anchor=tk.NW) # 设置画布位置
|
|
|
|
|
|
|
|
|
|
info = draw_info(canvas)
|
|
|
|
|
time1 = MyTimer(root)
|
|
|
|
|
show_Time(info, time1)
|
|
|
|
|
|
|
|
|
|
main_menu = tk.Menu(root)
|
|
|
|
|
root.config(menu=main_menu)
|
|
|
|
|
game_menu(main_menu)
|
|
|
|
|
auto_menu(main_menu)
|
|
|
|
|
question_menu(main_menu)
|
|
|
|
|
|
|
|
|
|
rect_mapping = draw_all_rect(canvas)
|
|
|
|
|
number_button(root)
|
|
|
|
|
control_button(root, side)
|
|
|
|
|
|
|
|
|
|
basics_info()
|
|
|
|
|
canvas.bind('<Button-1>', click_event)
|
|
|
|
|
# info.bind('<Button-1>', click_event)
|
|
|
|
|
|
|
|
|
|
# time.sleep(3)
|
|
|
|
|
# label_destroy_info(info_labels, canvas)
|
|
|
|
|
|
|
|
|
|
show_fixa_num()
|
|
|
|
|
|
|
|
|
|
tk.mainloop()
|
|
|
|
|
# test2()
|