任意大小迷宫自动生成+BFS寻路+生成无损迷宫bitmap(.BMP)图片

本文作者分享了自己制作的一个迷宫游戏,利用递归分割法生成迷宫,BFS算法寻找最优路径,并能生成BMP图片。程序实现了在Console中动态显示BFS路线,避免闪屏。还探讨了程序的优化问题,提供了源代码和运行指南。
摘要由CSDN通过智能技术生成

800x800迷宫自动解路径
镇楼图
在这里插入图片描述
https://pan.baidu.com/s/1ql-fy9V_vmhQp2huFWhshw
迷宫游戏百度网盘在此

迷宫游戏

本人墨尔本大学大一学生一枚,前段利用暑假在家闲来无事写了一个迷宫游戏。起初只是想锻炼巩固一下BFS,以及链表的知识点,后来逐渐给自己的程序增加了一些自己想要的功能,同时也学习到了很多东西。
主要涉及到了三个部分:
1,迷宫的生成
2,BFS寻找路线,利用队列寻路
3,BMP图片的生成
4,在Console中动态显示BFS求得的路线,运用gotoxy();而不是system(“cls”),避免闪屏。

迷宫的生成

迷宫的生成主要利用了递归分割法,先初始化空白二维矩阵,N by N grid,
递归分割法通俗的说就是在这片空白的区域中砌墙,怎么个砌法呢,就是递归的用墙"切割"这片空白的空间,直到墙和墙之间达到最小的单位宽度,在此也就是一格。
如图所示便是递归分割法:
递归分割法
在这里插入图片描述

BFS寻找路线

BFS是一种寻路的很重要的算法,在该类迷宫中BFS可以找到最优的路径。
通俗的说,BFS在我看来就像是往迷宫的起点灌水(蔓延状的遍历整个图),一旦水到了出口,立刻停止灌水,(也就是增加队列),并且开始回溯路径。
当然,水是不能回溯路径的,而存在链表(队列)中的坐标是可以回溯的。我用的方法是创建了一个结构体,包含了当前x,y坐标以及pre_x,pre_y先前坐标,起点处的先前坐标设为-1,-1,也就是在回溯过程中,一旦先前坐标为-1,停止回溯,之后便得到了完整的BFS路径。
另一个问题,
如果有同样长度的路径到达起点,我们应该选择哪一条呢?
不用担心,在添加队列之前我们就应当设定好了一个方向顺序,比如先看当前坐标的"上",之后是"下",“左”,“右”。而刚刚我已经提到过,既然有顺序可言,并且往迷宫内"灌水"的行为是一旦到达目标终点并停止,那么我们只要回溯就能得到路径,根本就无需考虑相同长度的路径,因为即使它可能存在,但是你回溯路径的选择只有一条路。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最后的一些细枝末节

程序的主体大概就是如上所说,其他一些琐碎的东西便是将数据存入txt文档并再读取,用于解路线以及画图。
画图我一开始尝试用matlab,非常方便,但是发现打包之后的matlab的exe并不能在其他电脑上通用,而且体积庞大,于是花了一点时间学习了一下BMP图片的生成,并且动手改写了一下这里的代码,归为己有。
https://blog.csdn.net/sguniver_22/article/details/80379457

先给大家看一下我最后生成的bmp图片。这是最大的一只,800x800的,如果一个有一米长 那么这个迷宫便是一平方公里那么大了。
在这里插入图片描述

还有一些小一点的,对浏览者友好。没记错的话这应该就是120x120
图片的单位都是像素。

在这里插入图片描述

如何使用程序

为了方便运行,我没有在源代码中加入过多的system(“balabala”);语句,所以写了一个批处理文件 如下 也就是运行过程。

@echo off
color FA
title = AUTO MAZE SOLVER
mode con cols=120 lines=80
::设置颜色,大小和标题
::运行maze.exe会在当前文件夹中生成一个半成品maze.txt储存了block的坐标和迷宫的信息
maze.exe
::如果源文件夹已有迷宫图片自动删除(为了之后生成新的)
del MAZE.bmp
color F9
::BFS解迷宫程序输入信息,完善maze.txt为了下一步给创建BMP使用
maze_solver.exe<maze.txt
::创建BMP文件输入信息,输出MAZE.bmp
creatBMP.exe<maze.txt
pause
::程序完整运行完毕,显示迷宫彩色BMP图片
MAZE.bmp
del maze.txt
Alvin.vbs

在源代码BMP文件夹和MAZE文件夹中的批处理文件则是方便我修改代码时候编译用的,如果各位看客用的也是gcc编译那也可以使用。

链接

链接: https://www.youtube.com/watch?v=KiCBXu4P-2Y&t=878s
油管上BFS的视频

I TURN COFFEE INTO CODE!

下面附上源代码。
第一次写博客希望大家多多支持,代码繁琐之处欢迎大家在评论中指出! 抱拳感谢!
btw:程序的时间复杂度BIG-OH在迷宫尺寸大于四百之后不是很理想,三百尺寸是十秒左右,二百两三秒,一百以内毫秒。上面最大的800X800的图跑了十几分钟,希望大家能指出可以优化的地方!!!
哦对了,程序运行方法还没告诉你们呢,先输入尺寸,然后输入1是不改变默认终点,也就是左上到右下,如果输入0的话那就可以改变终点位置,再输入想要的终点,如 19,5 如果坐标invalid程序会自动提示重新输入。
大家可以讲console字体调到8号或者更小,因为程序设定如果迷宫大小大于130则不显示,所以如果字体过大,屏幕会乱的一塌糊涂,但是最后生成的图片是没问题的。
最后动态显示路线则是使用gotoxy函数实现。
/************************************************************************************/
生成BMP

//bmp.h


#ifndef _BMP_H
#define _BMP_H

//bmp 图片数据获取
//filePath : 路径
//picMaxSize : 返回图片数据字节数, 不接收置NULL
//width : 返回图片宽(像素), 不接收置NULL
//height : 返回图片高(像素), 不接收置NULL
//per : 返回图片每像素的字节数, 不接收置NULL
//返回 : 图片数据指针, 已分配内存, 用完记得释放
unsigned char *bmp_get(char *filePath, int *picMaxSize, int *width, int *height, int *per);

//生成 bmp 图片
//filePath : 路径
//data : 原始数据
//width : 宽(像素)
//height : 高(像素)
//per : 每像素字节数
//返回 : 成功创建的 .bmp 文件大小, 小于0则失败
int bmp_create(char *filePath, unsigned char *data, int width, int height, int per);

#endif



```c
//bmp.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

//
#define  Bmp_FileHeader_Size    14  // sizeof(Bmp_FileHeader)的值不一定准确
typedef struct{
    uint8_t bfType[2];    //文件类型: "BM"/bmp, "BA"/.. , ...
    uint32_t bfSize;      //整个文件的大小
    uint16_t bfReserved1; //保留: 0
    uint16_t bfReserved2; //保留: 0
    uint32_t bfOffbits;   //文件数据从第几个字节开始
}Bmp_FileHeader;
//
#define  Bmp_Info_Size    40
typedef struct{
    uint32_t biSize;    //该段占用字节数
    uint32_t biWidth;   //图像宽度, 单位像素
    int32_t biHeight;   //图像高度, 单位像素(数据为正时为倒向)
    uint16_t biPlanes;  //平面数, 总是为1
    uint16_t biBitCount;    //单位像素占用比特数: 1, 4, 8, 16, 24, 42
    uint32_t biCompression; //图像压缩方式: 0/BI_BGB 不压缩, 
                            //  1/BI_RLE8 8比特游程压缩, 只用于8位位图
                            //  2/BI_RLE4 4比特游程压缩, 只用于4位位图
                            //  3/BI_BITFIELDS 比特域, 用于16/32位位图
                            //  4/BI_JPEG 位图含有jpeg图像, 用于打印机
                            //  5/BI_PWG 位图含有pwg图像, 用于打印机
    uint32_t biSizeImage;   //说明图像大小, 为BI_BGB时可能为0
    int32_t biXPelsPerMeter;//水平分辨率, 像素/米, 有符号整数
    int32_t biYPelsPerMeter;//垂直分辨率, 像素/米, 有符号整数
    uint32_t biClrUsed;     //位图实际使用彩色表中的颜色索引数(为0表示使用所有)
    uint32_t biClrImportant;//图像显示有重要影响的颜色索引数
}Bmp_Info;

//功能: 读取bmp格式图片
//参数: filePath: 传入, 文件地址
//     picMaxSize: 传出, 用以返回读取到的图片矩阵的总字节数
//      width: 传出, 用以返回图片横向的像素个数
//     height: 传出, 用以返回图片纵向的像素个数
//       per: 传出, 用以返回图片每像素占用字节数
//返回: 图片矩阵数据的指针(注意指针是函数内分配的内存, 用完需释放)
unsigned char *bmp_get(char *filePath, int *picMaxSize, int *width, int *height, int *per)
{
    FILE *fp;
    Bmp_FileHeader bf;
    Bmp_Info bi;
    int perW, perWCount;
    int ret;
    int i, j, picCount, totalSize;
    int overLineBytesNum;
    unsigned int overLineBytesSum;    // overLineBytesNum : 行结尾补0字节数  //每行字节数规定为4的倍数, 不足将补0, 所以读行的时候注意跳过
    unsigned char buffHeader[512], *data, *pic;
    //
    if(filePath == NULL)
        return NULL;
    //
    if((fp = fopen(filePath, "rb")) < 0)
    {   
        printf("bmp_get : open file %s failed\r\n", filePath);
        return NULL;
    }
    //Bmp_FileHeader
    if(fread(buffHeader, 1, Bmp_FileHeader_Size, fp) <= 0)
    {
        printf("bmp_get : read Bmp_FileHeader failed\r\n");
        fclose(fp);
        return NULL;
    }
    bf.bfType[0] = buffHeader[0]; bf.bfType[1] = buffHeader[1];
    bf.bfSize = buffHeader[2] + ((buffHeader[3]&0xFF)<<8) + ((buffHeader[4]&0xFF)<<16) + ((buffHeader[5]&0xFF)<<24);
    bf.bfOffbits = buffHeader[10] + ((buffHeader[11]&0xFF)<<8) + ((buffHeader[12]&0xFF)<<16) + ((buffHeader[13]&0xFF)<<24);
    //printf("bmp_get : bfType/%s, bfSize/%d, bfOffbits/%d\r\n", bf.bfType, bf.bfSize, bf.bfOffbits);
    if(bf.bfType[0] != 'B' || bf.bfType[1] != 'M')
    {
        printf("bmp_get : bmp type err, bfType must be \"BM\"\r\n");
        fclose(fp);
        return NULL;
    }
    //Bmp_Info
    if(bf.bfOffbits - Bmp_FileHeader_Size < Bmp_Info_Size || fread(buffHeader, 1, Bmp_Info_Size, fp) <= 0)
    {
        printf("bmp_get : read Bmp_Info failed\r\n");
        fclose(fp);
        return NULL;
    }
    bi.biSize = buffHeader[0] + ((buffHeader[1]&0xFF)<<8) + ((buffHeader[2]&0xFF)<<16) + ((buffHeader[3]&0xFF)<<24);
    bi.biWidth = buffHeader[4] + ((buffHeader[5]&0xFF)<<8) + ((buffHeader[6]&0xFF)<<16) + ((buffHeader[7]&0xFF)<<24);
    bi.biHeight = buffHeader[8] | ((buffHeader[9]&0xFF)<<8) | ((buffHeader[10]&0xFF)<<16) | ((buffHeader[11]&0xFF)<<24);
    bi.biPlanes = buffHeader[12] + ((buffHeader[13]&0xFF)<<8);
    bi.biBitCount = buffHeader[14] + ((buffHeader[15]&0xFF)<<8);
    bi.biCompression = buffHeader[16] + ((buffHeader[17]&0xFF)<<8) + ((buffHeader[18]&0xFF)<<16) + ((buffHeader[19]&0xFF)<<24);
    bi.biSizeImage = buffHeader[20] + ((buffHeader[21]&0xFF)<<8) + ((buffHeader[22]&0xFF)<<16) + ((buffHeader[23]&0xFF)<<24);
    bi.biXPelsPerMeter = buffHeader[24] | ((buffHeader[25]&0xFF)<<8) | ((buffHeader[26]&0xFF)<<16) | ((buffHeader[27]&0xFF)<<24);
    bi.biYPelsPerMeter = buffHeader[28] | ((buffHeader[29]&0xFF)<<8) | ((buffHeader[30]&0xFF)<<16) | ((buffHeader[31]&0xFF)<<24);
    bi.biClrUsed = buffHeader[32] + ((buffHeader[33]&0xFF)<<8) + ((buffHeader[34]&0xFF)<<16) + ((buffHeader[35]&0xFF)<<24);
    bi.biClrImportant = buffHeader[36] + ((buffHeader[37]&0xFF)<<8) + ((buffHeader[38]&0xFF)<<16) + ((buffHeader[39]&0xFF)<<24);
    //perW 每像素字节数
    if(bi.biBitCount >= 8)
        perW = bi.biBitCount/8;
    else
        perW = 1;
    //计算总字节数
    //totalSize = bf.bfSize - bf.bfOffbits;
    //计算总字节数
    overLineBytesNum = 4- bi.biWidth*(bi.biBitCount/8)%4;
    if(overLineBytesNum == 4)
        overLineBytesNum = 0;
    if(bi.biHeight < 0)
    {
        totalSize = bi.biWidth*(-bi.biHeight)*(bi.biBitCount/8);
        overLineBytesSum = overLineBytesNum*(-bi.biHeight);
    }else
    {
        totalSize = bi.biWidth*bi.biHeight*(bi.biBitCount/8);
        overLineBytesSum = overLineBytesNum*bi.biHeight;
    }
    //printf("bmp_get : biSize/%d, biWidth/%d, biHeight/%d, biPlanes/%d, biBitCount/%d, biCompression/%d, biSizeImage/%d, biXPelsPerMeter/%d, biYPelsPerMeter/%d, biClrUsed/%d, biClrImportant/%d, overLineBytesNum/%d, overLineBytesSum/%d, totalSize/%d\r\n", bi.biSize, bi.biWidth, bi.biHeight, bi.biPlanes, bi.biBitCount, bi.biCompression, bi.biSizeImage, bi.biXPelsPerMeter, bi.biYPelsPerMeter, bi.biClrUsed, bi.biClrImportant, overLineBytesNum, overLineBytesSum, totalSize);
    //指针移动到数据起始
    if(fseek(fp, bf.bfOffbits, 0) < 0)
    {
        printf("bmp_get : lseek failed\r\n");
        fclose(fp);
        return NULL;
    }
    //分配内存一次读入整张图片
    data = (unsigned char *)calloc(1, totalSize + overLineBytesSum + perW);    //多1像素的字节, 防止操作不当溢出
    if((ret = fread(data, 1, totalSize + overLineBytesSum, fp)) != (totalSize + overLineBytesSum))
    {
        if(ret <= 0)
        {
            printf("bmp_get : read data failed\r\n");
            free(data);
            fclose(fp);
            return NULL;
        }
    }
    //close
    fclose(fp);
    //
    pic = (unsigned char *)calloc(1, totalSize);
    memset(pic, 0, totalSize);
    //根据图片方向拷贝数据
    if(bi.biHeight > 0)     //倒向        //上下翻转 + 左右翻转 + 像素字节顺序调整
    {
        for(i = 0, picCount = totalSize; i < totalSize + overLineBytesSum && picCount >= 0; )
        {
            picCount -= bi.biWidth*perW;
            for(j = 0, perWCount = perW - 1; j < bi.biWidth*perW && i < totalSize + overLineBytesSum && picCount >= 0; j++)
            {
                pic[picCount + perWCount] = data[i++];
                if(--perWCount < 0)
                    perWCount = perW - 1;
                if(perWCount == perW - 1)
                    picCount += perW;
            }
            picCount -= bi.biWidth*perW;
            i += overLineBytesNum;
        }
    }
    else    // 正向        //像素字节顺序调整
    {
        for(i = 0, j = 0, picCount = 0, perWCount = perW - 1; i < totalSize + overLineBytesSum && picCount < totalSize; )
        {   
            pic[picCount + perWCount] = data[i++];
            if(--perWCount < 0)
                perWCount = perW - 1;
            if(perWCount == perW - 1)
                picCount += perW;
            if(++j == bi.biWidth*perW)
            {
                j = 0;
                i += overLineBytesNum;
            }
        }
    }
    //free
    free(data);
    //返回 宽, 高, 像素字节
    if(picMaxSize)
        *picMaxSize = totalSize;
    if(width)
        *width = bi.biWidth;
    if(height)
    {
        if(bi.biHeight > 0)
            *height = bi.biHeight;
        else
            *height = -bi.biHeight;
    }
    if(per)
        *per = perW;
    return pic;
}

//功能: 创建bmp格式图片
//参数: filePath: 传入, 文件地址
//      data: 传入, 图片矩阵数据的指针
//     width: 传入, 图片横向的像素个数
//     height: 传入, 图片纵向的像素个数
//       per: 传入, 图片每像素占用字节数
//返回: 创建的bmp图片文件的大小, -1表示创建失败
int bmp_create(char *filePath, unsigned char *data, int width, int height, int per)
{
    FILE *fp;
    int fileSize, fileSize2, count, headSize;
    unsigned char *bmpData, *p;
    int perWCount;
    int i, j, picCount;
    int overLineBytesNum;
    unsigned int overLineBytesSum = 0;// overLineBytesNum : 行结尾补0字节数  //每行字节数规定为4的倍数, 不足将补0, 所以读行的时候注意跳过
    //
    if(width < 0)
    {
        printf("bmp_create : width < 0 , err !!\r\n");
        return -1;
    }
    //
    if((fp = fopen(filePath, "wb+")) < 0)
    {
        printf("bmp_create : create %s err\r\n", filePath);
        return -1;
    }
    //
    overLineBytesNum = width*per%4;
    if(overLineBytesNum == 4)
        overLineBytesNum = 0;
    headSize = Bmp_FileHeader_Size + Bmp_Info_Size;
    if(height < 0)
    {
        overLineBytesNum = overLineBytesNum*(-height);
        fileSize2 =  width*(-height)*per;
    }
    else
    {
        overLineBytesNum = overLineBytesNum*height;
        fileSize2 =  width*height*per;
    }
    fileSize = headSize + fileSize2;
    bmpData = (unsigned char *)calloc(1, fileSize + overLineBytesNum);
    //
    count = 0;
    //
    bmpData[count++] = 'B';      //bfType
    bmpData[count++] = 'M';
    bmpData[count++] = (unsigned char)((fileSize>>0)&0xFF);    //bfSize     低位在前
    bmpData[count++] = (unsigned char)((fileSize>>8)&0xFF);
    bmpData[count++] = (unsigned char)((fileSize>>16)&0xFF);
    bmpData[count++] = (unsigned char)((fileSize>>24)&0xFF);
    count++;    //保留
    count++;
    count++;
    count++;
    bmpData[count++] = (unsigned char)((headSize>>0)&0xFF);    //bfOffbits     低位在前
    bmpData[count++] = (unsigned char)((headSize>>8)&0xFF);
    bmpData[count++] = (unsigned char)((headSize>>16)&0xFF);
    bmpData[count++] = (unsigned char)((headSize>>24)&0xFF);

    bmpData[count++] = (unsigned char)((Bmp_Info_Size>>0)&0xFF);    //biSize
    bmpData[count++] = (unsigned char)((Bmp_Info_Size>>8)&0xFF);
    bmpData[count++] = (unsigned char)((Bmp_Info_Size>>16)&0xFF);
    bmpData[count++] = (unsigned char)((Bmp_Info_Size>>24)&0xFF);
    bmpData[count++] = (unsigned char)((width>>0)&0xFF);    //biWidth
    bmpData[count++] = (unsigned char)((width>>8)&0xFF);
    bmpData[count++] = (unsigned char)((width>>16)&0xFF);
    bmpData[count++] = (unsigned char)((width>>24)&0xFF);
    bmpData[count++] = (unsigned char)((height>>0)&0xFF);    //biHeight
    bmpData[count++] = (unsigned char)((height>>8)&0xFF);
    bmpData[count++] = (unsigned char)((height>>16)&0xFF);
    bmpData[count++] = (unsigned char)((height>>24)&0xFF);
    bmpData[count++] = 0x01;    //biPlanes
    bmpData[count++] = 0x00;
    bmpData[count++] = 24;    //biBitCount
    bmpData[count++] = 0;
    bmpData[count++] = 0;    //biCompression
    bmpData[count++] = 0;
    bmpData[count++] = 0;
    bmpData[count++] = 0;
    bmpData[count++] = (unsigned char)((fileSize2>>0)&0xFF);    //biSizeImage
    bmpData[count++] = (unsigned char)((fileSize2>>8)&0xFF);
    bmpData[count++] = (unsigned char)((fileSize2>>16)&0xFF);
    bmpData[count++] = (unsigned char)((fileSize2>>24)&0xFF);
    bmpData[count++] = 0;    //biXPelsPerMeter
    bmpData[count++] = 0;
    bmpData[count++] = 0;
    bmpData[count++] = 0;
    bmpData[count++] = 0;    //biYPelsPerMeter
    bmpData[count++] = 0;
    bmpData[count++] = 0;
    bmpData[count++] = 0;
    bmpData[count++] = 0;    //biClrUsed
    bmpData[count++] = 0;
    bmpData[count++] = 0;
    bmpData[count++] = 0;
    bmpData[count++] = 0;    //biClrImportant
    bmpData[count++] = 0;
    bmpData[count++] = 0;
    bmpData[count++] = 0;
    //
    p = &bmpData[count];
    if(height >= 0)     //倒向        //上下翻转 + 左右翻转 + 像素字节顺序调整
    {
        for(i = 0, picCount = fileSize2; i < fileSize2 + overLineBytesSum && picCount >= 0; )
        {
            picCount -= width*per;
            for(j = 0, perWCount = per - 1; j < width*per && i < fileSize2 + overLineBytesSum && picCount >= 0; j++)
            {
                p[i++] = data[picCount + perWCount];
                if(--perWCount < 0)
                    perWCount = per - 1;
                if(perWCount == per - 1)
                    picCount += per;
            }
            picCount -= width*per;
            i += overLineBytesNum;
        }
    }
    else    // 正向        //像素字节顺序调整
    {
        for(i = 0, j = 0, picCount = 0, perWCount = per - 1; i < fileSize2 + overLineBytesSum && picCount < fileSize2; )
        {   
            p[i++] = data[picCount + perWCount];
            if(--perWCount < 0)
                perWCount = per - 1;
            if(perWCount == per - 1)
                picCount += per;
            if(++j == width*per)
            {
                j = 0;
                i += overLineBytesNum;
            }
        }
    }
    //
    fileSize = fwrite(bmpData, 1, fileSize, fp);
    free(bmpData);
    fclose(fp);
    //sync();
    return fileSize;
}



//main.c

#include <stdio.h>
#include <stdlib.h> //malloc free

#include "bmp.h"

//一张 宽100*高50*像素3字节 的RGB图片
int BMP_WIDTH = 0;
int BMP_HEIGHT = 0;
#define BMP_PERW 3
//读取图片用
int width, height, perW, picSize;

int main(int argc, char *argv[])
{
   
    int x,y,ch=0;
    scanf("%d\n[%*d,%*d]\n[%*d,%*d]\n",&BMP_WIDTH);//去头
    BMP_HEIGHT = BMP_WIDTH;
    unsigned char buff[BMP_HEIGHT][BMP_WIDTH][BMP_PERW];
    //---------- 创建一张图片 ----------
    ch=getchar();
    while(ch!='$'){
   
        scanf("%d,%d]\n",&y,&x);
        //block
        buff[y][x][0] = 0xb0;
        buff[y][x][1] = 0xb0;
        buff[y][x][2] = 0xf0;
        
        ch=getchar();
    }
    getchar();
    //path
    ch=getchar();
    while(ch!='$'){
   
        scanf("%d,%d]\n",&y,&x);
        buff[y][x][0] = 0;
        buff[y][x][1] = 0;
        buff[y][x][2] = 0;
        ch=getchar();
    }
    getchar();
    
    ch=getchar();
    //space
    while(ch!=EOF){
   
        scanf("%d,%d]\n",&y,&x);
        buff[y][x][0] = 0xff;
        buff[y][x][1] = 0xff;
        buff[y][x][2
  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值