C++扫雷程序

程序非常复杂,转载供大神评论

#include <time.h>
#include <stdlib.h>
#include "codingtang.h"

#define TITLE "Mine Cweeper"   //定义游戏名称
#define QUAD 32                //一张图片的长宽像素
#define QORG 64                
#define XSIZE 20               // x尺寸  20张图片
#define YSIZE 20               // y尺寸  
#define WIDTH XSIZE*QUAD       // 屏幕 宽
#define HEIGHT YSIZE*QUAD      // 屏幕 高
#define CELLS_NUM XSIZE*YSIZE  // 扫雷块的最大数量 20*20 
#define BOMB_MAX CELLS_NUM/10  // 炸弹的最大数量,为总块数的十分之一  400/10
#define BOMB 9                 // 炸弹编号为9
#define WALL 10                // 未点击图片编号为10
#define MARK 11                // 旗子标记编号为11


typedef struct{
    int img;
    bool bomb;
    int adj;
    bool check;
} Cell;
//定义扫雷块结构体,每扫雷块有:
//  img(照片编号)  bomb(是否是炸弹)  adj(九宫格内有几个炸弹)  check(是否点击)
 
Window window;
// 创建窗口

void setupGame(const char *text, Cell cells[], int x, int y);  //初始化游戏
int coin(int min, int max);    // 随机数
void render(const char *text, int offset, int x, int y); //渲染单个
void renderAll(const char *text, Cell cells[]);   // 渲染全部内容
int checkCell(Cell cells[],int x, int y);  //点击
bool click(Cell cells[], int x, int y );  //是否点击
bool mark(Cell *cell, int *marked, int *disc);  //是否标记
void addAdj(Cell cells[], int x, int y);   // 检测周围炸弹数量
void setBombs(Cell cells[],int bombs,int x, int y);  //设置炸弹数量

void setupGame(const char *text, Cell cells[], int x, int y) {
    
    window.clear();  //清空窗口

    for(int i = 0; i < XSIZE; i++) {   //遍历整个屏幕  20*20
        for(int j = 0; j < YSIZE; j++) {
            cells[i+j*XSIZE].img = WALL;  //默认为未点击状态
            cells[i+j*XSIZE].bomb = false;//默认非炸弹
            cells[i+j*XSIZE].adj = 0; //默认周围无炸弹
            cells[i+j*XSIZE].check = false; //默认为未点击
            render(text,WALL,i,j);  //这个图片渲染为10:未点击状态
        }
    }

    setBombs(cells,BOMB_MAX,x,y);  //设置炸弹

    window.present();  //显示在窗口上面
}

int coin(int min, int max) {
    int offset = rand() % (max-min);
    return min+offset;
} //随机值在 min~max中间

void render(const char *text, int offset, int x, int y) { //渲染函数
    SDL_Rect srcR;  //原图的尺寸
    SDL_Rect destR; //目标的区域

    srcR.x = offset*QORG;  //原图中第offset的区域
    srcR.y = 0;
    srcR.w = QORG;  //原图尺寸
    srcR.h = QORG;  //原图尺寸

    destR.x = x*QUAD;  //目标图的区域选取
    destR.y = y*QUAD;  //目标图的区域选取
    destR.w = QUAD;  //目标图尺寸
    destR.h = QUAD;  //目标图尺寸

    window.drawImageExt(text, srcR, destR);   //绘制这个图片
}

void renderAll(const char *text, Cell cells[]) { //渲染全部函数
    window.clear();  //清屏

    for(int i = 0; i < XSIZE; i++) { //遍历整个屏幕  20*20
        for(int j = 0; j < YSIZE; j++) {
            render(text, cells[i+XSIZE*j].img,i,j);  //将每张图片渲染出对应的位置
        }
    }
    window.present();  //在窗口上面显示出来
}

bool mark(Cell *cell, int *marked, int *disc) {  //标记切换
    switch(cell->img) {  // 判断这个扫雷块的图片
        case MARK: {  //如果是标记的就取消标记
            cell->img = WALL;
            *marked -= 1;  //标记为0 :取消标记
            break;
        }
        case WALL: { //如果是未标记 就切换为标记
            if(*marked >= BOMB_MAX) break;  //标记数量超过炸弹数,无法继续标记
            cell->img = MARK;  //否则就设置为标记
            *marked+=1;    //标记为1 : 状态:标记
            if(cell->bomb) {  //如果这个是炸弹:标记正确
                *disc+=1;   //标记正确的数量加1
            }
            return true;  //标记成功
            break;
        }
    }
    return false;  //否则标记失败
}

int checkCell(Cell cells[], int x, int y) {  //点击扫雷块
    int result = 0;  
    Cell *cell = &cells[x+y*XSIZE];  //选取对应的扫雷块
    if(cell->check) return 0;  //如果点击过,就结束
    cell->img = cell->adj;  // 设置图片为周围炸弹数量
    cell->check = true;  //设置为点击
    result++; 
    if(cell->adj == 0) {  //如果周围没有炸弹,就查找九宫格之内的其他方块
        int downX = x-1;
        int upX = x+1;
        int downY = y-1;
        int upY = y+1;
        for(int i=downX;i<=upX;i++) {
            for(int j=downY;j<=upY;j++) {
                if( (i>=0) && (j>=0) && (i<XSIZE) && (j<YSIZE) ) {
                    result+=checkCell(cells,i,j);
                }
            }
        }
    }
    return result; //返回最后的结果:点击数量
}


bool click(Cell cells[], int x, int y) {  //能否点击
    Cell *cell = &cells[x+y*XSIZE];  //选取对应的扫雷块
    if(cell->bomb) {  //如果是炸弹
        cell->img = BOMB;  //图片设置为炸弹
        cell->check=true;  //点击
        return false;   //不能点击
    }
    return true; //可以点击
}

void addAdj(Cell cells[], int x, int y) { //查找周围有几个炸弹
    int downX = x-1;  
    if(downX<0) downX = 0;
    int downY = y-1;
    if(downY<0) downY = 0;
    int upX = x+1;
    if(upX >= XSIZE) upX = XSIZE-1;
    int upY = y+1;
    if(upY >= YSIZE) upY = YSIZE-1;
    //选取九宫格,排除边缘情况
    for(int i=downX; i<=upX; i++) {
        for(int j=downY; j<=upY; j++) {
            cells[i+j*XSIZE].adj++;  //添加炸弹数量
        }
    }
}
//如果这个是炸弹,那么这个炸弹的九宫格其他块的炸弹数量都应该加1

void setBombs(Cell cells[], int bombs,int x, int y) {  //设置炸弹
    for(int i=0; i < bombs; i++) {  //循环随机设置炸弹
        int x0 = coin(0,XSIZE);
        int y0 = coin(0,YSIZE);
        if(cells[x0+y0*XSIZE].bomb) { //如果本身就是炸弹,会重新选择一个地方
            i--;
        } 
        else {
            if(x != x0 || y != y0) {
                cells[x0+y0*XSIZE].bomb = true;  //设置为炸弹
                addAdj(cells,x0,y0);  //添加炸弹周围其他块的adj
            }
        }
    }
}

int main(int argc, char** argv)
{
    srand(time(NULL));  //随机数

    window = createWindow(WIDTH, HEIGHT);  //创建窗口

    Cell cells[CELLS_NUM];  //定义扫雷块数组
    string sprites = "bomb.png";  //设置精灵图

    setupGame(sprites.c_str(),cells,0,0);  //初始化游戏

    SDL_Event event;  //定义事件
    Event ev;  //定义ev事件
    bool running = true;  //游戏正在运行

    bool lost = false;  //游戏没有结束

    int undisc = CELLS_NUM;  //全部都是未知的  开始未点击
    int marked = 0;  //标记的数量
    int disc = 0;  //已知数量 (已经点击数量)

    bool init = false;  //  初始化

    while(running) {  //游戏运行中
        if (waitEventTimeout(&ev, 250)){  //键盘事件监听
            switch(ev.type) {  //判断事件是什么类型
                case CDT_QUIT:  //退出事件
                    running = false;  //游戏结束
                    break;
                case CDT_KEY_DOWN:{  //按键按下事件
                    int keyCode = ev.keyCode;  //定义一个按键
                    switch (keyCode){  //判断是什么按键按下
                        case CDT_KEY_ESCAPE: {  //escape键  退出
                            running = false;  //结束游戏
                            break;
                        }
                        case CDT_KEY_n: {  //n键  重新开始游戏
                            setupGame(sprites.c_str(),cells,0,0);
                            undisc = CELLS_NUM;
                        }
                    }
                }

                case CDT_MOUSEBUTTONDOWN: {  //鼠标按下事件
                    MouseButtonEvent button = ev.button;  //定义一个鼠标按钮
                    int x = button.x/QUAD;  //根据点击的坐标求得点击的区域
                    int y = button.y/QUAD;
                    if(!init) {  //如果未初始化
                        setupGame(sprites.c_str(),cells,x,y);  //初始化一下
                        undisc = CELLS_NUM;
                        marked = 0;
                        disc = 0;
                        init = true;
                    }
                    if(button.button == CDT_BUTTON_LEFT){  //如果是鼠标左键点击
                        lost = !click(cells,x,y);  // 如果不能点击,就代表结束
                        if(lost) { //如果游戏结束
                            print("%s\n", "Game Over!");  //输出游戏结束
                            for(int i=0;i<XSIZE;i++) {
                                for(int j=0;j<YSIZE;j++) {
                                    Cell *cell = &cells[i+j*XSIZE]; //选取对应的扫雷块
                                    if(cell->bomb) {  //如果是炸弹
                                        cell->img = BOMB;  //设置图片为炸弹
                                    }
                                }
                            }
                            renderAll(sprites.c_str(),cells);  //渲染全部
                            SDL_Delay(4000);  //延时 4000毫秒
                            setupGame(sprites.c_str(),cells,0,0); //重置
                            undisc = CELLS_NUM;
                            marked = 0;
                            disc = 0;
                            init = false;
                        } 
                        else {
                            undisc -= checkCell(cells,x,y);  //点击之后的数量
                            if(undisc == BOMB_MAX) {  //如果未点击的数量等于炸弹数
                                print("%s\n", "You won!"); //胜利
                                renderAll(sprites.c_str(),cells); //渲染全部
                                SDL_Delay(2000); //延迟2000毫秒
                                setupGame(sprites.c_str(),cells,0,0); //重置游戏
                                undisc = CELLS_NUM;
                                marked = 0;
                                disc = 0;
                                init = false;
                            }
                        }
                    } 
                    else if(button.button == CDT_BUTTON_RIGHT) { //如果是鼠标右键点击
                        if(mark(&cells[x+y*XSIZE], &marked, &disc)) { //标记函数

                            if(disc == BOMB_MAX) { //如果标记数量等于炸弹数。获胜
                                print("%s\n", "You won!");
                                renderAll(sprites.c_str(),cells);  //重置
                                SDL_Delay(2000);
                                setupGame(sprites.c_str(),cells,0,0);
                                undisc = CELLS_NUM;
                                marked = 0;
                                disc = 0;
                                init = false;
                            }
                        }
                    }
                    renderAll(sprites.c_str(),cells); //点击操作完成后,渲染全部
                }
            }
        }
    }

    window.quit();  //退出窗口

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值