|
|
|
|
"""
|
|
|
|
|
@Author: packy945
|
|
|
|
|
@FileName: UI.py
|
|
|
|
|
@DateTime: 2023/4/27 17:42
|
|
|
|
|
@SoftWare: PyCharm
|
|
|
|
|
"""
|
|
|
|
|
# -*- encoding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
import tkinter as tk
|
|
|
|
|
from pprint import pprint
|
|
|
|
|
from tkinter import *
|
|
|
|
|
from data import *
|
|
|
|
|
import time
|
|
|
|
|
import numpy as np
|
|
|
|
|
from tkinter import scrolledtext
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BLACK = "#000000"
|
|
|
|
|
HINT = '#6D2DFA'
|
|
|
|
|
SILVER = '#FFFFFF'
|
|
|
|
|
u_NUMBER = '#6D2DFA'
|
|
|
|
|
WHITE = "#FFFFFF"
|
|
|
|
|
ORANGE = '#FF8C00'
|
|
|
|
|
RED = "#C80000"
|
|
|
|
|
YELLOW = "#FAE067"
|
|
|
|
|
GREY = '#808080'
|
|
|
|
|
GREYLESS = '#CCCCCC'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
side = 40
|
|
|
|
|
|
|
|
|
|
# 构建主窗口
|
|
|
|
|
width, height = 840, 610#设置长宽
|
|
|
|
|
root = tk.Tk()#设置主窗口
|
|
|
|
|
root.title("数独")#设置窗口标题
|
|
|
|
|
root.config(bg=BLACK)#设置背景
|
|
|
|
|
root.geometry(f'{width}x{height}')#设置窗口大小
|
|
|
|
|
root.resizable(0, 0) # 防止用户调整尺寸
|
|
|
|
|
canvas = tk.Canvas(root, bg=WHITE, bd=2, width=width, height=height, background=ORANGE,
|
|
|
|
|
highlightthickness=0)#设置画布
|
|
|
|
|
|
|
|
|
|
canvas.place(x=0, y=0, anchor=NW)#设置画布位置
|
|
|
|
|
|
|
|
|
|
side = 40
|
|
|
|
|
"""文字框"""
|
|
|
|
|
top_x = (side + 3) * 11 # 文本框顶点x
|
|
|
|
|
top_y = 50 # 文本框顶点y
|
|
|
|
|
bc_x = (side + 3) * 7 + 20 # 文本框宽度
|
|
|
|
|
bc_y = (side + 3) * 12 # 文本框高度
|
|
|
|
|
|
|
|
|
|
right = tk.Frame(root, bg=WHITE, relief="sunken", width=bc_x, height=bc_y)
|
|
|
|
|
right.place(x=top_x, y=top_y, anchor=NW) # 右边栏
|
|
|
|
|
|
|
|
|
|
class MyTimer:
|
|
|
|
|
# 计时器
|
|
|
|
|
def __init__(self):
|
|
|
|
|
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 = 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
|
|
|
|
|
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 rect_draw(side, row, col):
|
|
|
|
|
'''
|
|
|
|
|
绘制一个方格
|
|
|
|
|
:param side: 方格边长
|
|
|
|
|
:param row: 行
|
|
|
|
|
:param col: 列
|
|
|
|
|
:return:
|
|
|
|
|
'''
|
|
|
|
|
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:
|
|
|
|
|
color = "#FAE067"
|
|
|
|
|
else:
|
|
|
|
|
color = 'white'
|
|
|
|
|
canvas.create_rectangle(row * (side + 3) + 50, col * (side + 3) + 50, row * (side + 3) + 50 + side, col * (side + 3) + 50 + side,
|
|
|
|
|
fill=color, width=0) # 绘制一个方格
|
|
|
|
|
|
|
|
|
|
def draw_all_rect():
|
|
|
|
|
"""
|
|
|
|
|
左上角开始
|
|
|
|
|
:param left_x:
|
|
|
|
|
:param top_y:
|
|
|
|
|
:return:
|
|
|
|
|
"""
|
|
|
|
|
for i in range(9):
|
|
|
|
|
for n in range(9):
|
|
|
|
|
rect_draw(side, i, n)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
martix_position_mapping = 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
|
|
|
|
|
|
|
|
|
|
def show_Time(timer: MyTimer):
|
|
|
|
|
'''
|
|
|
|
|
显示计时器
|
|
|
|
|
:param timer:计时器示例
|
|
|
|
|
:return:
|
|
|
|
|
'''
|
|
|
|
|
Time = tk.Label(right, text="运行时间: 分 秒", bg=WHITE, fg=BLACK, font=('幼圆', 16, 'bold'), anchor=W)
|
|
|
|
|
Time.place(x=30, y=30, width=300, 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)
|
|
|
|
|
|
|
|
|
|
def num_draw(side, row, col, martix, u_martix):
|
|
|
|
|
'''
|
|
|
|
|
绘制方格中的数字
|
|
|
|
|
:param side: 方格大小
|
|
|
|
|
:param row: 行
|
|
|
|
|
:param col: 列
|
|
|
|
|
:param martix: 原矩阵
|
|
|
|
|
:param u_martix: 用户矩阵
|
|
|
|
|
:return:
|
|
|
|
|
'''
|
|
|
|
|
if u_martix[row, col] == 10:# 如果该方格为提示信息,则不显示大数字
|
|
|
|
|
return
|
|
|
|
|
if not martix[row, col] == 0: # 如果该方格为题目所给数字(不可更改),则显示为黑色
|
|
|
|
|
color = 'black' # 将颜色设置为黑色
|
|
|
|
|
else:
|
|
|
|
|
if u_martix[row, col] not in GetPossible(u_martix, row, col): # 判断这一格的数字是否符合数独要求
|
|
|
|
|
color = 'red' # 不符合要求显示红色
|
|
|
|
|
else:
|
|
|
|
|
color = 'purple' # 用户填的数字的颜色
|
|
|
|
|
if martix[row, col] != 0 or u_martix[row, col] != 0: #如果该格子有数据要显示
|
|
|
|
|
canvas.create_text(col * (side + 3) + 50 + side / 2, row * (side + 3) + 50 + side / 2,
|
|
|
|
|
text=f"{u_martix[row, col]}", font=('幼圆', 18, 'bold'), fill=color, tags="num")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def Difficulty(empty):
|
|
|
|
|
"""
|
|
|
|
|
难度显示:
|
|
|
|
|
:param empty: 原始空格数目
|
|
|
|
|
:return:
|
|
|
|
|
"""
|
|
|
|
|
Level = tk.Label(right, text="难度:{:.2f}".format(empty / 81), bg=WHITE, fg=BLACK, font=('幼圆', 16, 'bold'), anchor=W)
|
|
|
|
|
Level.place(x=30, y=60, width=300, height=30)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def noter(tag):
|
|
|
|
|
'''
|
|
|
|
|
显示笔记提示
|
|
|
|
|
:param tag: 笔记模式是否开启
|
|
|
|
|
:return:
|
|
|
|
|
'''
|
|
|
|
|
note_help1 = tk.Label(right, text=f"False 时保存笔记,当前笔记:{tag}", bg=WHITE, fg=RED, font=('幼圆', 12, 'bold'), anchor=W)
|
|
|
|
|
note_help1.place(x=30, y=90, width=300, height=30)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def seq_recode(right, STEP):
|
|
|
|
|
'''
|
|
|
|
|
显示步骤
|
|
|
|
|
:param STEP: 步骤
|
|
|
|
|
:return:
|
|
|
|
|
'''
|
|
|
|
|
note_help1 = tk.Label(right, text=f"步骤记录:", bg=WHITE, fg=RED, font=('幼圆', 12, 'bold'), anchor=W)
|
|
|
|
|
note_help1.place(x=30, y=120, width=300, height=30)
|
|
|
|
|
scr = scrolledtext.ScrolledText(right, fg='red', font=('幼圆', 16, 'bold'))#设置一个可滚动文本框
|
|
|
|
|
scr.place(x=30, y=150, width=280, height=300)#
|
|
|
|
|
for i in range(len(STEP)):
|
|
|
|
|
if i != 0:#将步骤显示到文本框中
|
|
|
|
|
scr.insert('end', f"{STEP[i][:3]}\n") # 末尾插入
|
|
|
|
|
scr.config(state=DISABLED) # 设置文本框为 “不能编辑”
|
|
|
|
|
scr.see(END)#将视图移到末尾
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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] == 10:
|
|
|
|
|
count += 1
|
|
|
|
|
return count
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
martix = M = np.array([[1, 3, 4, 0, 0, 6, 0, 0, 7],
|
|
|
|
|
[0, 9, 2, 0, 0, 7, 0, 5, 6],
|
|
|
|
|
[0, 6, 7, 8, 9, 4, 0, 2, 3],
|
|
|
|
|
[0, 8, 1, 2, 4, 9, 6, 0, 0],
|
|
|
|
|
[9, 4, 5, 6, 0, 8, 2, 3, 0],
|
|
|
|
|
[2, 7, 6, 0, 1, 5, 9, 0, 4],
|
|
|
|
|
[0, 2, 8, 0, 5, 1, 0, 0, 9],
|
|
|
|
|
[0, 1, 3, 0, 6, 0, 0, 4, 8],
|
|
|
|
|
[0, 5, 0, 4, 0, 0, 0, 1, 2]])
|
|
|
|
|
|
|
|
|
|
u_M = np.array([[1, 3, 4, 0, 0, 6, 0, 0, 7],
|
|
|
|
|
[0, 9, 2, 0, 0, 7, 0, 5, 6],
|
|
|
|
|
[0, 6, 7, 8, 9, 4, 0, 2, 3],
|
|
|
|
|
[0, 8, 1, 2, 4, 9, 6, 0, 0],
|
|
|
|
|
[9, 4, 5, 6, 0, 8, 2, 3, 0],
|
|
|
|
|
[2, 7, 6, 1, 1, 5, 9, 0, 4],
|
|
|
|
|
[0, 2, 8, 0, 5, 1, 0, 6, 9],
|
|
|
|
|
[0, 1, 3, 0, 6, 0, 7, 4, 8],
|
|
|
|
|
[0, 5, 0, 4, 0, 0, 0, 1, 2]])
|
|
|
|
|
# text_enter(side)
|
|
|
|
|
|
|
|
|
|
# time1.start() # 计时开始
|
|
|
|
|
# draw((5, 5),M,u_martix)
|
|
|
|
|
|
|
|
|
|
side = 40
|
|
|
|
|
def left1(event):
|
|
|
|
|
print(event.x, event.y)
|
|
|
|
|
x = event.x
|
|
|
|
|
y = event.y
|
|
|
|
|
for key, posit_lt in martix_position_mapping.items():
|
|
|
|
|
if posit_lt[0] < x < posit_lt[0]+side and posit_lt[1] < y < posit_lt[1]+side:
|
|
|
|
|
print(key)
|
|
|
|
|
canvas.bind('<Button-1>', left1)
|
|
|
|
|
draw_all_rect()
|
|
|
|
|
martix_position_mapping = creat_martix_mapping(side)
|
|
|
|
|
seq_recode(right,[])
|
|
|
|
|
|
|
|
|
|
time1 = MyTimer() # 实例计时器
|
|
|
|
|
show_Time(time1)
|
|
|
|
|
|
|
|
|
|
emp = empty(u_M)
|
|
|
|
|
Difficulty(emp)
|
|
|
|
|
noter(True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mainloop()
|