【案例】用 tkinter 实现五子棋(第二版)

大家好,我是Jia ming,今天为大家带来 Python GUI 系列 —— 用 tkinter 实现五子棋

1. 前言

五子棋的棋具与围棋通用,是一种传统棋种。五子棋容易上手,老少皆宜,而且趣味横生,引人入胜:它不仅能增强思维能力,提高智力,而且富含哲理,有助于修身养性。

该软件主要分为绘制棋子模块、绘制棋盘模块和胜负判定模块三个部分。

2. 效果预览

如图所示,展示了本软件的最终效果,黑方先手,依次落子,界面下方有落子方提示,待五子连线后,会弹出游戏结束的弹窗。
在这里插入图片描述

图0 效果图

3. 重点模块介绍

3.0 数据结构

该软件紧密围绕着一个数据结构:chessBoardDict = collections.OrderedDict() #将普通字典转换为有序字典{} {(x, y):"black"},熟悉 Python 的同学都知道,这是一个有序字典,字典键为棋盘横纵坐标,值为棋子颜色(“balck”, “white”)。

Python 字典是无序的,但是可以通过 collections.OrderedDict() 方法构建有序字典,之所以需要有序,是因为该字典保存了落子双方的顺序,有序的保证是必须的。有序字典会严格保证遍历顺序和添加顺序一致。

构造方法:

>>> import collections
>>> x = collections.OrderedDict()
>>> x[1] = 'a'
>>> x[2] = 'b'
>>> x[3] = 'c'
>>> x
OrderedDict([(1, 'a'), (2, 'b'), (3, 'c')])

遍历方法:

>>> for k, v in x.items():
...     print(k, v)
...
1 a
2 b
3 c

3.1 绘制棋子模块

通过变量:

rate_piece = 0.45 # 棋子占格子大小的百分比
grid = 40 # 每个格子的大小

方便控制棋子的大小。

模块输入输出?
传入参数:canvas 画布对象需要绘制的坐标
输出:无

如何知道绘制的棋子颜色?

遍历 chessBoardDict 有序字典,该字典的最后既是前一个落子的玩家,只需要取对手玩家的颜色即可。

def drawPiece(canvas, coordinate:tuple)->None:
    """
    coordinate: (x, y)
    WB: white/black
    需要完成坐标映射
    """
    global user
    if coordinate[0] % grid >= rate_piece*grid or coordinate[1] % grid >= rate_piece*grid or coordinate[0] >= 16*grid or coordinate[1] >= 16*grid or coordinate[0] < grid or coordinate[1] < grid:
        return None
    x = coordinate[0] // grid
    y = coordinate[1] // grid
    
    if len(chessBoardDict) == 0:
        user = 'white'
        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid,  width=1, fill="black")
        print("落子: %s (%d, %d)" % ("black", x, y))
        return [(x, y), "black"]
    color = -1
    for k, v in chessBoardDict.items():
        _, color = k, v
    if color == "black":
        user = 'black'
        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid, fill="white")
        print("落子: %s (%d, %d)" % ("white", x, y))
        return [(x, y), "white"]
    else:
        user = 'white'
        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid, fill="black")
        print("落子: %s (%d, %d)" % ("black", x, y))
        return [(x, y), "black"]

该模块主要是能够按照顺序在鼠标点击位置的附近棋盘线交叉点绘制出棋子。主要需要考虑棋子的大小、颜色问题,如图1所示,展示了绘制棋子的效果。

在这里插入图片描述

图1 绘制棋子

3.2 绘制棋盘模块

该模块需要绘制绘制棋盘外框的边界线、棋盘经纬线(使用全局变量rate来控制大小)、棋盘上黑色辅助点(有rate全局变量来控制大小)。

def drawBoard():
    # 界面对象的基本参数设置
    root = tk.Tk()
    root.title("五子棋")
    # root.geometry('335x265+250+250')
    # 设置界面是否可以随意拉伸
    root.resizable(False, False)

    canvas = tk.Canvas(root, bg='#F9D65B', height=grid*16, width=grid*16)
    canvas.grid(row=0, column=0)
    label = tk.Label(root, text=user, font=('Times', 16)).grid(row=1, column=0)
    # 绘制线
    canvas.create_rectangle(grid/2, grid/2, 16*grid-grid/2, 16*grid-grid/2, width=2)
    for i in range(1, 16):
        canvas.create_line(grid, i*grid, 15*grid, i*grid, fill='black')
        canvas.create_line(i*grid, grid, i*grid, 15*grid, fill='black')
    # 绘制点
    canvas.create_oval(8*grid+rate*grid, 8*grid+rate*grid, 8*grid-rate*grid, 8*grid-rate*grid, fill="black")
    canvas.create_oval(12*grid+rate*grid, 12*grid+rate*grid, 12*grid-rate*grid, 12*grid-rate*grid, fill="black")
    canvas.create_oval(4*grid+rate*grid, 4*grid+rate*grid, 4*grid-rate*grid, 4*grid-rate*grid, fill="black")
    canvas.create_oval(12*grid+rate*grid, 4*grid+rate*grid, 12*grid-rate*grid, 4*grid-rate*grid, fill="black")
    canvas.create_oval(4*grid+rate*grid, 12*grid+rate*grid, 4*grid-rate*grid, 12*grid-rate*grid, fill="black")
    # 鼠标事件
    def mouseEvent(event):
        # print(f"({event.x}, {event.y})")
        value = drawPiece(canvas, (event.x, event.y))
        tk.Label(root, text=user, font=('Times', 16)).grid(row=1,column=0)
        if value != None:
            k, v = value
            chessBoardDict[k] = v
            judge()
            # print(chessBoardDict)
            # global k
            # k += 1
    # canvas.bind("<Button-1>", lambda event:mouseEvent(event, "white" if k % 2 == 0 else "black"))
    canvas.bind("<Button-1>", lambda event:mouseEvent(event))
    
    root.mainloop()

按照五子棋盘标准尺寸,绘制15x15条线交叉的棋盘,并标识出棋盘的五个关键点位置。如图2所示,展示了棋盘的绘制效果。

在这里插入图片描述

图2 绘制棋盘

3.3. 胜负判定模块

该模块主要围绕 chessBoardDict 有序字典的遍历,每落子后便调用该模块,判断落子的八个方向是否满足五子连珠的条件。

def judge():
    global chessBoardDict
    # chessBoardDict.pop()
    for k, v in chessBoardDict.items():
        coordinate, color = k, v
    # print("color", color)
    if color == "black":
        anti_color = "white"
    else:
        anti_color = "black"
    # print("判断:", chessBoardDict)
    points = [0, 0, 0, 0, 0, 0, 0, 0]
    for k in range(5):
        if (coordinate[0], coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0], coordinate[1] - k)] == color:
            points[0] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] + k, coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1] - k)] == color:
            points[1] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] + k, coordinate[1]) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1])] == color:
            points[2] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] + k, coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1] + k)] == color:
            points[3] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0], coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0], coordinate[1] + k)] == color:
            points[4] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] - k, coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1] + k)] == color:
            points[5] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] - k, coordinate[1]) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1])] == color:
            points[6] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] - k, coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1] - k)] == color:
            points[7] += 1
        else:
            break
    if 5 in points:
        messagebox.showinfo(title="结果", message="%s 获胜!" % color)
        print(color, "win")

每当落一个子的时候,就需要判断该棋子的八个方向是否产生了连珠五子的效果,如图3所示需要判断的八个方向。如果成功连珠五子,则结束游戏。
在这里插入图片描述

图3 胜负判定的8个方向

3.4 tkinter 知识点

1. 布局

涉及两个对象:canvas 和 label。这也是我们在界面所看到的两个控件,前者为棋盘画布,我们可以在上面绘制图案,后者为棋盘下方label控件,提示每回合落子方。

使用 grid 布局方式。

canvas = tk.Canvas(root, bg='#F9D65B', height=grid*16, width=grid*16)
canvas.grid(row=0, column=0)
label = tk.Label(root, text=user, font=('Times', 16)).grid(row=1,column=0)

关于 grid 的使用方式,下面这个例子可以很好的说明:

from tkinter import *

tk=Tk()
#标签控件,显示文本和位图,展示在第一行
Label(tk,text="First").grid(row=0,sticky=E)#靠右
Label(tk,text="Second").grid(row=2,sticky=W)#第二行,靠左

#输入控件
Entry(tk).grid(row=0,column=1)
Entry(tk).grid(row=2,column=1)

#主事件循环
mainloop()

在这里插入图片描述

grid 样例

2. 鼠标事件

如下样例,我们便可以绑定一个鼠标单击左键事件,传入 event 参数,每点一次鼠标,就会打印鼠标的坐标值,我们可以通过这个方法来调用胜负判断模块。

	# 鼠标事件
    def mouseEvent(event):
        print(f"({event.x}, {event.y})")
    canvas.bind("<Button-1>", lambda event:mouseEvent(event))

其它鼠标事件:

'''
鼠标点击事件
<Button-1>  鼠标左键
<Button-2>   鼠标中间键(滚轮)
<Button-3>  鼠标右键
<Double-Button-1>   双击鼠标左键
<Double-Button-3>   双击鼠标右键
<Triple-Button-1>   三击鼠标左键
<Triple-Button-3>   三击鼠标右键
'''

3. canvas 画布操作

关于canva画布的操作,我们这里用到了线、矩形、圆形。下面提供了几个学习样例以供参考。

import tkinter as tk
 
root = tk.Tk()
 
w = tk.Canvas(root, width =200, height = 100)
w.pack()
 
#画一条黄色的横线
w.create_line(0, 50, 200, 50, fill = "yellow")
#画一条红色的竖线(虚线)
w.create_line(100, 0, 100, 100, fill = "red", dash = (4, 4))
#中间画一个蓝色的矩形
w.create_rectangle(50, 25, 150, 75, fill = "blue")
 
root.mainloop()

在这里插入图片描述

线条以及矩形样例
import tkinter as tk
 
root = tk.Tk()
 
w = tk.Canvas(root, width =200, height = 100)
w.pack()
 
w.create_rectangle(40, 20, 160, 80, dash = (4, 4))
w.create_oval(40, 20, 160, 80, fill = "pink")
 
w.create_text(100, 50, text = "Python")
 
root.mainloop()

在这里插入图片描述

圆形样例

4. 开发运行环境

4.1 开发环境

本软件的开发环境如下:

PyCharm 2020.2 (Community Edition)
Build #PC-202.6397.98, built on July 28, 2020
Runtime version: 11.0.7+10-b944.20 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Windows 10 10.0
GC: ParNew, ConcurrentMarkSweep
Memory: 1902M
Cores: 12

4.2 软件所涉及到的开源库

import tkinter as tk
from tkinter import messagebox
import collections
表1 软件所涉及到的开源库
开源库说明
tkinterPython3提供的界面设计库
collectionsPython内建的一个集合模块,提供了许多有用的集合类

5. 使用说明

本软件操作简单,界面简洁。
运行程序,用户便能看到如图4所示的界面。
在这里插入图片描述

图4 初始界面

下方“black”显示了当前落子的颜色,开局黑方先手。鼠标点击落子即可,落子效果如图5所示。
在这里插入图片描述

图5 黑方先手

然后是白方落子,如图6所示。
在这里插入图片描述

图6 白方落子

如图7所示,黑方获胜,会弹出提示框。

在这里插入图片描述

图7 黑方获胜

源码

# 五子棋
# @author: jiaming
import tkinter as tk
from tkinter import messagebox
import collections

rate = 0.1 # 黑点占格子大小的百分比
rate_piece = 0.45 # 棋子占格子大小的百分比
grid = 40 # 每个格子的大小
color = (249, 214, 91) # 棋盘颜色
user = 'black'
# k = 0
chessBoardDict = collections.OrderedDict()  #将普通字典转换为有序字典{} {(x, y):"black"}

def judge():
    global chessBoardDict
    # chessBoardDict.pop()
    for k, v in chessBoardDict.items():
        coordinate, color = k, v
    # print("color", color)
    if color == "black":
        anti_color = "white"
    else:
        anti_color = "black"
    # print("判断:", chessBoardDict)
    points = [0, 0, 0, 0, 0, 0, 0, 0]
    for k in range(5):
        if (coordinate[0], coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0], coordinate[1] - k)] == color:
            points[0] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] + k, coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1] - k)] == color:
            points[1] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] + k, coordinate[1]) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1])] == color:
            points[2] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] + k, coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] + k, coordinate[1] + k)] == color:
            points[3] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0], coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0], coordinate[1] + k)] == color:
            points[4] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] - k, coordinate[1] + k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1] + k)] == color:
            points[5] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] - k, coordinate[1]) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1])] == color:
            points[6] += 1
        else:
            break
    for k in range(5):
        if (coordinate[0] - k, coordinate[1] - k) in chessBoardDict.keys() and chessBoardDict[(coordinate[0] - k, coordinate[1] - k)] == color:
            points[7] += 1
        else:
            break
    if 5 in points:
        messagebox.showinfo(title="结果", message="%s 获胜!" % color)
        print(color, "win")

def drawPiece(canvas, coordinate:tuple)->None:
    """
    coordinate: (x, y)
    WB: white/black
    需要完成坐标映射
    """
    global user
    if coordinate[0] % grid >= rate_piece*grid or coordinate[1] % grid >= rate_piece*grid or coordinate[0] >= 16*grid or coordinate[1] >= 16*grid or coordinate[0] < grid or coordinate[1] < grid:
        return None
    x = coordinate[0] // grid
    y = coordinate[1] // grid
    
    if len(chessBoardDict) == 0:
        user = 'white'
        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid,  width=1, fill="black")
        print("落子: %s (%d, %d)" % ("black", x, y))
        return [(x, y), "black"]
    color = -1
    for k, v in chessBoardDict.items():
        _, color = k, v
    if color == "black":
        user = 'black'
        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid, fill="white")
        print("落子: %s (%d, %d)" % ("white", x, y))
        return [(x, y), "white"]
    else:
        user = 'white'
        canvas.create_oval(x*grid+rate_piece*grid, y*grid+rate_piece*grid, x*grid-rate_piece*grid, y*grid-rate_piece*grid, fill="black")
        print("落子: %s (%d, %d)" % ("black", x, y))
        return [(x, y), "black"]

def drawBoard():
    # 界面对象的基本参数设置
    root = tk.Tk()
    root.title("五子棋")
    # root.geometry('335x265+250+250')
    # 设置界面是否可以随意拉伸
    root.resizable(False, False)

    canvas = tk.Canvas(root, bg='#F9D65B', height=grid*16, width=grid*16)
    canvas.grid(row=0, column=0)
    label = tk.Label(root, text=user, font=('Times', 16)).grid(row=1, column=0)
    # 绘制线
    canvas.create_rectangle(grid/2, grid/2, 16*grid-grid/2, 16*grid-grid/2, width=2)
    for i in range(1, 16):
        canvas.create_line(grid, i*grid, 15*grid, i*grid, fill='black')
        canvas.create_line(i*grid, grid, i*grid, 15*grid, fill='black')
    # 绘制点
    canvas.create_oval(8*grid+rate*grid, 8*grid+rate*grid, 8*grid-rate*grid, 8*grid-rate*grid, fill="black")
    canvas.create_oval(12*grid+rate*grid, 12*grid+rate*grid, 12*grid-rate*grid, 12*grid-rate*grid, fill="black")
    canvas.create_oval(4*grid+rate*grid, 4*grid+rate*grid, 4*grid-rate*grid, 4*grid-rate*grid, fill="black")
    canvas.create_oval(12*grid+rate*grid, 4*grid+rate*grid, 12*grid-rate*grid, 4*grid-rate*grid, fill="black")
    canvas.create_oval(4*grid+rate*grid, 12*grid+rate*grid, 4*grid-rate*grid, 12*grid-rate*grid, fill="black")
    # 鼠标事件
    def mouseEvent(event):
        # print(f"({event.x}, {event.y})")
        value = drawPiece(canvas, (event.x, event.y))
        tk.Label(root, text=user, font=('Times', 16)).grid(row=1,column=0)
        if value != None:
            k, v = value
            chessBoardDict[k] = v
            judge()
            # print(chessBoardDict)
            # global k
            # k += 1
    # canvas.bind("<Button-1>", lambda event:mouseEvent(event, "white" if k % 2 == 0 else "black"))
    canvas.bind("<Button-1>", lambda event:mouseEvent(event))
    
    root.mainloop()

if __name__ == "__main__":
    drawBoard()
'''
鼠标点击事件
<Button-1>  鼠标左键
<Button-2>   鼠标中间键(滚轮)
<Button-3>  鼠标右键
<Double-Button-1>   双击鼠标左键
<Double-Button-3>   双击鼠标右键
<Triple-Button-1>   三击鼠标左键
<Triple-Button-3>   三击鼠标右键
'''

  • 9
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
tkinter 实现五子棋UI界面 import tkinter as tk from tkinter import messagebox from chessboard import ChessBoard ChessBoard = ChessBoard() class GUI(object): def __init__(self): self.counter = 0 self.winner = 0 self.is_start = False self.is_surrender = False self.window = tk.Tk() # 窗口对象(首字母大写) self.window.title('Gobang') self.window.geometry('800x540') self.window.resizable(width = False, height = False) # 画布对象 棋盘 self.canvas = tk.Canvas(self.window, height = 540, width = 540) self.chessboard = tk.PhotoImage(file = 'Gobang_chessboard/chessboard.gif') self.blackpoint = tk.PhotoImage(file = 'Gobang_chessboard/blackpoint.gif') self.whitepoint = tk.PhotoImage(file = 'Gobang_chessboard/whitepoint.gif') self.canvas.create_image(0, 0, anchor = 'nw', image = self.chessboard) self.canvas.bind("", self.get_point) self.start_point = 10 # 起始点位置 self.step = 35 # 每个格子的跨度 self.canvas.place(x = 0, y = 0) # 标签对象 self.l_info = tk.Label(self.window, text = 'Not started', font=('Arial', 12), width = 25, height = 2) self.l_info.place(x = 545, y = 0) # 文本框对象 self.t = tk.Text(self.window, height = 15) self.t.place(x = 540, y = 40) # 按钮对象 self.f_header = tk.Frame(self.window, highlightthickness=0) self.b_start = tk.Button(self.f_header, text = 'start', command = self.start) self.b_restart = tk.Button(self.f_header, text = 'restart', command = self.restart) self.b_regret = tk.Button(self.f_header, text = 'regret', command = self.regret) self.b_surrender = tk.Button(self.f_header, text = 'surrender', command = self.surrender) self.f_header.place(x = 545, y = 250) self.b_start.pack(side='left', padx=10) self.b_restart.pack(side = 'left') self.b_surrender.pack(side = 'right') self.b_regret.pac
可以使用tkinter库来实现五子棋游戏。首先,你需要创建一个游戏界面窗口,并在窗口中添加一个棋盘。然后,你可以通过点击棋盘上的位置来落子。接下来,你需要编写一些逻辑来判断游戏的胜负以及防止无效的落子。最后,你可以在游戏结束时显示胜利者或者平局的信息。 以下是一个简单的示例代码,可以帮助你开始实现五子棋游戏: ```python import tkinter as tk class Gobang: def __init__(self, width=15, height=15): self.width = width self.height = height self.board = [[0] * height for _ in range(width)] self.player = 1 self.game_over = False self.window = tk.Tk() self.window.title("五子棋") self.canvas = tk.Canvas(self.window, width=width*30, height=height*30, bg="white") self.canvas.pack() self.canvas.bind("<Button-1>", self.on_click) self.draw_board() def draw_board(self): for i in range(self.width): self.canvas.create_line(i*30, 0, i*30, self.height*30) for i in range(self.height): self.canvas.create_line(0, i*30, self.width*30, i*30) def draw_piece(self, x, y): if self.board[x][y] != 0: return color = "black" if self.player == 1 else "white" self.canvas.create_oval(x*30-15, y*30-15, x*30+15, y*30+15, fill=color) self.board[x][y] = self.player if self.check_win(x, y): self.game_over = True winner = "黑棋" if self.player == 1 else "白棋" self.canvas.create_text(self.width*15, self.height*15, text="{}胜利!".format(winner)) if not self.game_over: self.player = 2 if self.player == 1 else 1 def check_win(self, x, y): directions = [(1, 0), (0, 1), (1, 1), (1, -1)] for dx, dy in directions: count = 1 for i in range(1, 5): new_x, new_y = x + i*dx, y + i*dy if 0 <= new_x < self.width and 0 <= new_y < self.height and self.board[new_x][new_y] == self.player: count += 1 else: break for i in range(1, 5): new_x, new_y = x - i*dx, y - i*dy if 0 <= new_x < self.width and 0 <= new_y < self.height and self.board[new_x][new_y] == self.player: count += 1 else: break if count >= 5: return True return False def on_click(self, event): if self.game_over: return x = event.x // 30 y = event.y // 30 self.draw_piece(x, y) def start(self): self.window.mainloop() game = Gobang() game.start() ``` 你可以运行上述代码来尝试玩五子棋游戏。在游戏窗口中,你可以点击棋盘上的位置来落子,黑棋先手。当有一方连成五子时,游戏结束并显示胜利者。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jia ming

谢谢投食哦~

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

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

打赏作者

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

抵扣说明:

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

余额充值