【tkinter】用不到50行Python代码,写一个扫雷小游戏

文章目录

    • 定制按钮
    • 生成雷区
    • 主流程

基础知识:

  • StringVar
  • tkinter布局

定制按钮

学会了布局和绑定事件,就可以开发一些简单的应用,比如扫雷小游戏。从外观来看,扫雷就是一个按钮矩阵,左键点击按钮,如果按钮里埋了雷,那么就游戏结束,否则继续游戏。

所以第一步,是对按钮进行定制

import tkinter as tk
from itertools import product

def clickRight(evt, txt):
    if txt.get() == "":
        txt.set("")
    else:
        txt.set("")

def clickLeft(evt, txt, isMine):
    if isMine:
        txt.set("")
    else:
        txt.set(" ")

def setMine(root, i, j, isMine=False):
    txt = tk.StringVar()
    btn = tk.Button(root, width=5, height=2,
        textvariable=txt)
    btn.grid(row=i,column=j)
    btn.bind("", lambda evt: clickRight(evt, txt))
    btn.bind("", lambda evt: clickLeft(evt, txt, isMine))

root = tk.Tk()
root.title("扫雷")
for i,j in product(range(5), range(8)):
    setMine(root, i, j, True)

root.mainloop()

效果如下,总共设置了40个按钮,每个按钮都是雷。

【tkinter】用不到50行Python代码,写一个扫雷小游戏_第1张图片

生成雷区

接下来要做的有两件事,一是随机生成一片雷区,二是引发雷的连锁反应,当点击一个按钮,如果这个按钮不是雷,那么会显示这个按钮周围的雷的个数。

随机雷区可以通过矩阵实现

import numpy as np
def setMineMat(M, N, r):
    mat = np.random.rand(M, N)
    return mat > r

其中mat是一个范围在0到1之间均匀分布的矩阵,其返回值是一个布尔型矩阵,True为雷,False为非雷,所以r越大,则True值越少,雷也就越少,也就越简单。

然后实现第二个需求,当左键点击按钮后,按钮显示的值,

def mineNumber(mat, i, j):
    if mat[i,j] == True:
        return ""
    M, N = mat.shape
    i0, i1 = max(0, i-1), min(M, i+2)
    j0, j1 = max(0, j-1), min(N, j+2)
    num = np.sum(mat[i0:i1, j0:j1])
    return str(num)

在这个基础上,更改左键单击的逻辑,除了点击之后显示的内容发生变化之外,若该点为雷,则弹出失败框;若该点为0,则将该点周围所有点全部翻面。

from tkinter.messagebox import showerror

def clickRight(evt, txt):
    if txt.get() == "": txt.set("")
    else: txt.set("")

def clickLeft(i, j):
    if txtLst[i][j].get() != "":
        return
    flag = mineNumber(mat, i, j)
    txtLst[i][j].set(flag)
    if flag == "":
        showerror("", "你输了!")
    if flag != "0":
        return
    i0, i1 = max(0, i-1), min(M, i+2)
    j0, j1 = max(0, j-1), min(N, j+2)
    for i,j in product(range(i0,i1), range(j0, j1)):
        clickLeft(i, j)

重新写一下生成雷区的逻辑,按钮绑定了两个事件,分别在左键点击和右键点击时触发。

def setMine(root, i, j):
    txt = tk.StringVar()
    btn = tk.Button(root, width=5, height=2,
        textvariable=txt)
    btn.grid(row=i,column=j)
    btn.bind("", lambda evt: clickRight(evt, txt))
    btn.bind("", lambda evt: clickLeft(i, j))
    return txt

主流程

最后,写一下主流程

root = tk.Tk()
root.title("扫雷")

M, N, r  = 6, 10, 0.8
mat = setMineMat(M, N, r)
txtLst = [[] for _ in range(M)]
for i,j in product(range(M), range(N)):
    txt = setMine(root, i, j)
    txtLst[i].append(txt)

root.mainloop()

效果为

【tkinter】用不到50行Python代码,写一个扫雷小游戏_第2张图片
这个扫雷还有一些不足之处,最显而易见的就是旗帜和雷的颜色,这一点其实很好办,只要改下前景就行。另外一点就是,并没有提供一个按钮用于改变雷区和难度,对于这点,最简单的方法既是来一个参数对话框,这个内容接下来就讲。

你可能感兴趣的:(#,Python标准库,python,tkinter,扫雷,GUI,绑定)