吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5969|回复: 38
收起左侧

[C&C++ 原创] C++ 扫雷小游戏

[复制链接]
爱学习的小妖精 发表于 2020-2-19 11:51
本帖最后由 苏紫方璇 于 2020-2-19 13:54 编辑

还记得以前的扫雷游戏吗?
现在,我们就来一起回顾一下(小哥哥教我写的,感觉很不错,现在来分享给大家)
随便写写玩玩,嘻嘻嘻,大佬大大们不喜吻喷哟~~


Dev-C++写的
因为C语言中,存在文本属性,其实就是颜色属性,有背景色和前景色(就是字符的颜色)两类,每一类只提供三原色(红,绿,蓝)和加强色(灰色,可与其他颜色搭配使用,使颜色变亮)。最后还有一个反色。所以需要用三原色来搭配构造不同的颜色。

基本文本属性:
FOREGROUND_BLUE 蓝色
FOREGROUND_GREEN 绿色
FOREGROUND_RED 红色
FOREGROUND_INTENSITY 加强
BACKGROUND_BLUE 蓝色背景
BACKGROUND_GREEN 绿色背景
BACKGROUND_RED 红色背景
BACKGROUND_INTENSITY 背景色加强
COMMON_LVB_REVERSE_VIDEO 反色

不多说,下面我们直接来看看我改的源码:


大佬给的注释很多,理解起来应该不难,可以自己尝试着更改一些东西来摸索每一句的作用,Dev-C++上可以直接编译运行(我一直用的这个)

#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<time.h>
#include<conio.h>
#include<queue>
#include<ctype.h>
#define A 20        //地图的高
#define B 20        //地图的宽
#define C 30        //雷的总数
using namespace std;

//全局变量
DWORD a,b;
char map[A][B],news,spare;
int BoomTotalNum,floatx,floaty,flag[A][B],flagnum,mode,slect[A][B],game;

//定义颜色属性

const WORD FORE_BLUE   = FOREGROUND_BLUE;           //蓝色文本属性
const WORD FORE_GREEN  = FOREGROUND_GREEN;          //绿色文本属性
const WORD FORE_RED   =   FOREGROUND_RED;        //红色文本属性
const WORD FORE_WHITE  =  FORE_BLUE | FORE_RED | FORE_GREEN;        //白色文本属性
const WORD BACK_GRAY   = BACKGROUND_INTENSITY;      //灰色背景属性

//定义地图结构体 
struct node {
        int x;
        int y;
};
queue <node> dui;

//打印位置
void position(int x,int y) {
        COORD pos={x,y};
        HANDLE Out=GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleCursorPosition(Out,pos);
}

//隐藏光标 
void Hide() {
        HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);  
        CONSOLE_CURSOR_INFO CursorInfo;  
        GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息  
        CursorInfo.bVisible = false; //隐藏控制台光标  
        SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态   
}

//初始化
void Beginning() {
        while(!dui.empty()) {
                dui.pop();
        }
        game=1;
        //BoomTotalNum=C;
        floatx=A/2;
        floaty=B/2;
        flagnum=0;
        BoomTotalNum=C;
        mode=0;
        HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);    //获得标准输出设备句柄  
    CONSOLE_SCREEN_BUFFER_INFO csbi;                        //定义窗口缓冲区信息结构体  
    GetConsoleScreenBufferInfo(handle_out, &csbi);          //获得窗口缓冲区信息
    int x,y;
        srand((unsigned)time(0));
        for(int i=0;i<A;i++) for(int j=0;j<B;j++) {
                map[i][j]=' ';
                flag[i][j]=0;
                slect[i][j]=0;
        }
        while(BoomTotalNum) {
                x=rand()%A;
                y=rand()%B;
                if(map[x][y]==' ') {
                        map[x][y]='@';
                        BoomTotalNum--;
                }
        }  
        SetConsoleTextAttribute(handle_out, BACK_GRAY);
        for(int i=0;i<A;i++) {
                for(int j=0;j<B;j++) printf("█");
                printf("\n");
        }
        position(floaty*2,floatx);
        SetConsoleTextAttribute(handle_out, FORE_RED);  
        printf("开");        //光标位置
        position(44,9);
        printf("扫雷模式");
        position(44,5);
        printf("剩余雷数:%d ",C-flagnum);
        SetConsoleTextAttribute(handle_out, BACK_GRAY); 
        position(5,22);
        printf("按“空格”切换标记模式");
        position(5,23);
        printf("按“Enter”确认");
        position(5,24);
        printf("按“方向键”选择方块"); 

}

//打印地图的一块儿 
void Lump(int xx,int yy) {
        switch(map[xx][yy]) {
                case '1' : printf("①");break;        //周围雷的数量(下同) 
                case '2' : printf("②");break;
                case '3' : printf("③");break;
                case '4' : printf("④");break;
                case '5' : printf("⑤");break;
                case '6' : printf("⑥");break;
                case '7' : printf("⑦");break;
                case '8' : printf("⑧");break;
                case ' ' :
                        if(xx==floatx&&yy==floaty) {
                                if(flag[xx][yy]==0) {
                                        if(mode%2==0) printf("开");
                                        else printf("标");
                                }
                                else printf("?");
                        }
                        else {
                                if(flag[xx][yy]==0) printf("█");
                                else printf("?");
                        }
                        break;
                case '@' :
                        if(xx==floatx&&yy==floaty) {
                                if(flag[xx][yy]==0) {
                                        if(mode%2==0) printf("开");
                                        else printf("标");
                                }
                                else printf("?");
                        }
                        else {
                                if(flag[xx][yy]==0) printf("█");
                                else printf("?");
                        }
                        break;
                case 'x' : if(floatx==xx&&floaty==yy) printf(""); else printf("  ");break;        //已经挖开的空白
        }
}

//移动光标
void Move() {
        HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);    //获得标准输出设备句柄  
    CONSOLE_SCREEN_BUFFER_INFO csbi;                        //定义窗口缓冲区信息结构体  
    GetConsoleScreenBufferInfo(handle_out, &csbi);          //获得窗口缓冲区信息
    int xxx,yyy;
    xxx=floatx;
    yyy=floaty;
        switch(news) {
                case 72 : floatx--;break;        //上 
                case 80 : floatx++;break;        //下 
                case 75 : floaty--;break;        //左 
                case 77 : floaty++;break;        //右 
        }
        if(floatx==-1) floatx=A-1; floatx%=A;        //两端穿模处理 
        if(floaty==-1) floaty=B-1; floaty%=B;

        position(yyy*2,xxx);
        SetConsoleTextAttribute(handle_out, BACK_GRAY);
        Lump(xxx,yyy);        //删除原位置

        if(map[floatx][floaty]=='x') {
                position(floaty*2,floatx);
                printf("  ");
        }

        position(floaty*2,floatx);
        SetConsoleTextAttribute(handle_out, FORE_WHITE);  
        Lump(floatx,floaty);        //更新新位置 
} 

//插旗和排雷模式切换 
void Mode() {
        HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);    //获得标准输出设备句柄  
    CONSOLE_SCREEN_BUFFER_INFO csbi;                        //定义窗口缓冲区信息结构体  
    GetConsoleScreenBufferInfo(handle_out, &csbi);          //获得窗口缓冲区信息
        mode++;
        SetConsoleTextAttribute(handle_out, FORE_WHITE);
        position(floaty*2,floatx);
        if(mode%2==0) printf("开");
        else printf("标");

        position(44,9);
        if(mode%2==0) {
                SetConsoleTextAttribute(handle_out, FORE_WHITE);  
                printf("扫雷模式");
        }
        else {
                SetConsoleTextAttribute(handle_out, FORE_RED);  
                printf("插旗模式");
        }
}

//该点周围地雷数 
int Boomnum(int xx,int yy) {
        int num=0;
        if((xx-1>=0)&&(yy-1>=0)&&(map[xx-1][yy-1]=='@')) num++;
        if((xx-1>=0)&&(yy+0>=0)&&(map[xx-1][yy]=='@')) num++;
        if((xx-1>=0)&&(yy+1<B) &&(map[xx-1][yy+1]=='@')) num++;
        if((xx+0>=0)&&(yy-1>=0)&&(map[xx][yy-1]=='@')) num++;
        if((xx+0>=0)&&(yy+1<B) &&(map[xx][yy+1]=='@')) num++;
        if((xx+1<A)&&(yy-1>=0) &&(map[xx+1][yy-1]=='@')) num++;
        if((xx+1<A)&&(yy+0>=0) &&(map[xx+1][yy]=='@')) num++;
        if((xx+1<A)&&(yy+1<B)  &&(map[xx+1][yy+1]=='@')) num++;
        return num;
}

//更新地图 
void Open() {
        node c;
        node d;
        while(!dui.empty()) {
                dui.pop();
        }
        c.x=floatx;
        c.y=floaty;
        dui.push(c);
        slect[c.x][c.y]=1;
        while(!dui.empty()) {
                c=dui.front();
                dui.pop();
                if(Boomnum(c.x,c.y)!=0) {
                        map[c.x][c.y]=(Boomnum(c.x,c.y)+48);
                        continue;
                }
                else {
                        map[c.x][c.y]='x';                                                                                                                                                                                                                                                                                                                                                                                                                                     
                        if((c.x-1>=0)&&(c.y-1>=0)&&(map[c.x-1][c.y-1]==' ')&&(slect[c.x-1][c.y-1]==0)) {
                                d.x=c.x-1;
                                d.y=c.y-1;
                                dui.push(d);
                                slect[d.x][d.y]=1;
                        }
                        if((c.x-1>=0)&&(c.y-0>=0)&&(map[c.x-1][c.y]==' ')&&(slect[c.x-1][c.y]==0)) {
                                d.x=c.x-1;
                                d.y=c.y-0;
                                dui.push(d);
                                slect[d.x][d.y]=1;
                        }
                        if((c.x-1>=0)&&(c.y+1<B)&&(map[c.x-1][c.y+1]==' ')&&(slect[c.x-1][c.y+1]==0)) {
                                d.x=c.x-1;
                                d.y=c.y+1;
                                dui.push(d);
                                slect[d.x][d.y]=1;
                        }
                        if((c.x-0>=0)&&(c.y-1>=0)&&(map[c.x][c.y-1]==' ')&&(slect[c.x][c.y-1]==0)) {
                                d.x=c.x-0;
                                d.y=c.y-1;
                                dui.push(d);
                                slect[d.x][d.y]=1;
                        }
                        if((c.x-0>=0)&&(c.y+1<B)&&(map[c.x][c.y+1]==' ')&&(slect[c.x][c.y+1]==0)) {
                                d.x=c.x-0;
                                d.y=c.y+1;
                                dui.push(d);
                                slect[d.x][d.y]=1;
                        }
                        if((c.x+1<A)&&(c.y-1>=0)&&(map[c.x+1][c.y-1]==' ')&&(slect[c.x+1][c.y-1]==0)) {
                                d.x=c.x+1;
                                d.y=c.y-1;
                                dui.push(d);
                                slect[d.x][d.y]=1;
                        }
                        if((c.x+1<A)&&(c.y-0>=0)&&(map[c.x+1][c.y]==' ')&&(slect[c.x+1][c.y]==0)) {
                                d.x=c.x+1;
                                d.y=c.y-0;
                                dui.push(d);
                                slect[d.x][d.y]=1;
                        }
                        if((c.x+1<A)&&(c.y+1<B)&&(map[c.x+1][c.y+1]==' ')&&(slect[c.x+1][c.y+1]==0)) {
                                d.x=c.x+1;
                                d.y=c.y+1;
                                dui.push(d);
                                slect[d.x][d.y]=1;
                        }
                }
        }
}

int main() {
        freopen("排名.txt","r",stdin);
        Relife:        //重玩处
        HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);    //获得标准输出设备句柄  
    CONSOLE_SCREEN_BUFFER_INFO csbi;                        //定义窗口缓冲区信息结构体  
    GetConsoleScreenBufferInfo(handle_out, &csbi);          //获得窗口缓冲区信息

        Hide();                //隐藏光标
        Beginning();//初始化地图
        a=GetTickCount();
        while(1) {
                if(kbhit()!=0) {
                        spare=getch();

                        //按其他
                        if((spare!=(-32))&&(spare!=13)&&(spare!=' ')) continue;//跳过 

                        //按Enter
                        if(spare==13) {        //确认 
                                //排雷
                                if(mode%2==0) {
                                        if(map[floatx][floaty]=='@'&&flag[floatx][floaty]==0) {
                                                break;        //触雷
                                                game=0;
                                        }

                                        if(flag[floatx][floaty]==1) continue;        //有旗跳过
                                        Open();
                                        position(0,0);
                                        SetConsoleTextAttribute(handle_out, BACK_GRAY);
                                        for(int i=0;i<A;i++) {
                                                for(int j=0;j<B;j++) Lump(i,j);
                                                printf("\n");
                                        }
                                        position(floaty*2,floatx);
                                        SetConsoleTextAttribute(handle_out, FORE_WHITE);
                                        Lump(floatx,floaty);
                                }

                                //插拔旗
                                else {

                                        //不能插旗的地方
                                        if(map[floatx][floaty]=='x'||(map[floatx][floaty]>'0'&&map[floatx][floaty]<'9'))
                                                continue;        //跳过

                                        //插旗
                                        if(flag[floatx][floaty]==0) {
                                                flagnum++;
                                                flag[floatx][floaty]=1;
                                                position(floaty*2,floatx);
                                                SetConsoleTextAttribute(handle_out, FORE_WHITE);
                                                Lump(floatx,floaty);
                                        }

                                        //拔旗 
                                        else {
                                                flagnum--;
                                                flag[floatx][floaty]=0;
                                                position(floaty*2,floatx);
                                                SetConsoleTextAttribute(handle_out, FORE_WHITE);
                                                Lump(floatx,floaty);
                                        }
                                }
                        }

                        //按空格
                        if(spare==' ') Mode();        //切换模式 

                        //按方向键 
                        if(spare==-32) {
                                news=getch();
                                Move();        //移动光标
                        }
                        for(int i=0;i<A;i++) for(int j=0;j<B;j++) if(map[i][j]=='x'||(map[i][j]>'0'&&map[i][j]<'9')) game++;
                        if(game==A*B-C+1) break;
                        else game=1;
                        SetConsoleTextAttribute(handle_out, FORE_RED);
                        position(44,5);
                        printf("剩余雷数:%d ",C-flagnum);
                }
                else Sleep(10);
                b=GetTickCount();
                SetConsoleTextAttribute(handle_out, FORE_RED);
                position(44,7);
                printf("用时:");        //用时 
                if((b-a)/60000<10) printf("0");
                printf("%d:",(b-a)/60000);
                if(((b-a)/1000)%60<10) printf("0");
                printf("%d:",((b-a)/1000)%60);
                if(((b-a)/10)%100<10) printf("0");
                printf("%d",((b-a)/10)%100);
        }
        SetConsoleTextAttribute(handle_out, FORE_RED);
        position(5,5);
        if(game==1) printf("游戏结束!");
        else printf("恭喜通关!");
        position(5,8);
        printf("任意键重玩");
        scanf("%c%c",&spare,&spare);
        system("cls");
        position(0,0);
        goto Relife;
}

运行程序效果:

运行程序效果:

免费评分

参与人数 14吾爱币 +17 热心值 +13 收起 理由
豆包豆奶 + 1 + 1 谢谢@Thanks!
北辰无殇 + 1 + 1 我很赞同!
lonelydrunk + 1 谢谢@Thanks!
ftzhouyubo + 1 + 1 热心回复!
洪冼象 + 1 我很赞同!
cheng32375 + 1 + 1 谢谢@Thanks!
hcj222 + 1 挺强的
秋风抚过 + 1 + 1 用心讨论,共获提升!
rhel7 + 1 + 1 用心讨论,共获提升!
苏紫方璇 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
haungyexingdong + 1 + 1 热心回复!
wwhtm + 1 + 1 用心讨论,共获提升!
CLX + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
heyechuanmei + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 爱学习的小妖精 发表于 2020-2-21 15:40
CLX 发表于 2020-2-19 12:21
我是初学者,之前尝试做过,但...一言难尽呀,敢问大佬有源码么?

哈哈哈,没事没事,慢慢来,可以的,上面那些就是源码可以成功运行
 楼主| 爱学习的小妖精 发表于 2020-3-14 14:33
铁狼 发表于 2020-2-19 12:24
太多了吧,不过可以观摩一下,毕竟我也学C++

加油!C很重要哒!好好学相信你可以的
15157519997 发表于 2020-2-19 12:10
jefel 发表于 2020-2-19 12:15
不错,可以观察。
無--- 发表于 2020-2-19 12:15
相信自己,永不放弃
yhzh 发表于 2020-2-19 12:16
能不能附件发源码
loner888 发表于 2020-2-19 12:18
表示看不懂~~
CLX 发表于 2020-2-19 12:21
我是初学者,之前尝试做过,但...一言难尽呀,敢问大佬有源码么?
wwhtm 发表于 2020-2-19 12:23
我就是写不出来,只能举手
铁狼 发表于 2020-2-19 12:24
太多了吧,不过可以观摩一下,毕竟我也学C++
散场的拥抱 发表于 2020-2-19 12:37
牛逼,厉害
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 18:21

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表