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

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("<Button-3>", lambda evt: clickRight(evt, txt))
    btn.bind("<Button-1>", 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()

其中,clickRight为鼠标右键点击的响应函数;clickLeft为鼠标左键点击的响应函数,右键点击会对方格进行标记,左键点击后,如果是雷那么将爆炸。

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

在这里插入图片描述

生成雷区

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

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

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("<Button-3>", lambda evt: clickRight(evt, txt))
    btn.bind("<Button-1>", 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()

效果为

在这里插入图片描述
这个扫雷还有一些不足之处,最显而易见的就是旗帜和雷的颜色,这一点其实很好办,只要改下前景就行。另外一点就是,并没有提供一个按钮用于改变雷区和难度,对于这点,最简单的方法既是来一个参数对话框,这个内容接下来就讲。

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微小冷

请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值