C语言:扫雷游戏
- 一.游戏逻辑分析与结构框架
- 1.棋盘的创建
- 2.布置炸弹
- 3.排除炸弹
- 二.游戏实现
- 1.头文件game.h
- 2.源文件game.c
- 3.源文件test.c
在此之前我们已经对分支与循环语句、数组和函数有了一定得了解,接下来我们将写一个简单的扫雷游戏代码,在写之前得先对扫雷逻辑要有一定的了解。
游戏要求
1.电脑生成一个9x9的棋盘
2.在这9x9棋盘中随机部署10个炸弹
3.在游戏过程中如果踩到炸弹,游戏结束并且打印棋盘布局;如果没有,则统计其周围共有几个炸弹并继续游戏,直到把除10个雷之外的所有⾮雷都找出来,排雷成功,游戏结束。
扫雷游戏
一.游戏逻辑分析与结构框架
1.棋盘的创建
首先,我们得要创建一个9x9的棋盘来存放炸弹,这很简单,运用我们之前学的二维数组即可。
#defineROW9#defineCOL9但是得想想,如果我们只是创建了一个9x9的棋盘就足够了吗?在这之前就已经说明了在游戏要求3中如果没有踩到炸弹,则统计其周围共有几个炸弹,那如果非炸弹刚好布置在棋盘边沿,有三个位置已经超出了棋盘范围了,又该如何统计其周围共有几个炸弹呢?
如下图所示(其中设0为非炸弹,1为炸弹):
遇到这种情况又该如何去解决?
仔细想想,既然超出的范围我们用不上,并且也为非雷区,何不将这9x9的棋盘边沿包围住并填充上0,在创建一个11x11的棋盘,解决了因为范围超出的问题。
#defineROWSROW+2#defineCOLSCOL+2如下图所示:
创建棋盘代码参考:
voidInitBoard(charboard[ROWS][COLS],introws,intcols,charset);voidInitBoard(charboard[ROWS][COLS],introws,intcols,charset){inti=0;for(i=0;i<rows;i++){intj=0;for(j=0;j<cols;j++){board[i][j]=set;}}}InitBoard(mine,ROWS,COLS,'0');InitBoard(show,ROWS,COLS,'*');//在这里*是为了覆盖炸弹布置的位置看到这里你会觉得有些迷茫,为什么这代码分开来的,这是因为第一份代码我放在叫game.h的头文件里,主要是写游戏需要的数据类型和函数声明等 ;第二份代码放在game.c文件里,主要是写游戏中函数的实现等;第三份代码放在test.c文件里,主要是写游戏的测试逻辑
如何操作呢?如下图所示:
右击源文件,添加,新建项,然后有两个选项,一个是.c后缀的c++文件,另一个是.h后缀的头文件。
通过这些操作我们就可以得到:
在这里我们又看到除了创建棋盘之外还顺便打印了行和列,只需在代码中加上这几句就行:
voidDisplayBoard(charboard[ROWS][COLS],introw,intcol){inti=0;printf("--------扫雷游戏-------\n");for(i=0;i<=col;i++)//<<----打印列{printf("%d ",i);}printf("\n");for(i=1;i<=row;i++){printf("%d ",i);//<<----打印行intj=0;for(j=1;j<=col;j++){printf("%c ",board[i][j]);}printf("\n");}}2.布置炸弹
那接下来又应该如何布置我们的炸弹呢?想一想我们之前学过的猜数字游戏中想要得到一个随机数是如何做到的,这就不得不提rand、srand和time这三个函数了,并且炸弹布置的范围不能超过棋盘的范围,仔细缕一缕,思路不就来了吗
- 首先创建随机值:
srand((unsignedint)time(NULL));- 接着设置范围:
a+rand()%(b-a+1);//⽣成a~b的随机数但我们要的是9x9的范围,所以可以这样写:
intx=rand()%row+1;//rand() % row范围在0~row-1, +1后范围在1~rowinty=rand()%col+1;- 最后布置炸弹
设置数量count,运用while循环,将炸弹(1)随机赋值给9x9坐标任何一个,每布置完一个,count--,布置完后count==0,跳出循环
voidSetMine(charboard[ROWS][COLS],introw,intcol){intcount=EASY_COUNT;while(count){intx=rand()%row+1;//rand() % row范围在0~row-1, +1后范围在1~rowinty=rand()%col+1;if(board[x][y]=='0'){board[x][y]='1';count--;}}}在这里我们要注意的是,棋盘布局是用char类型,所有0和1要写成'0'和'1'
3.排除炸弹
既然炸弹都布置完了,那接下来的操作便是找出棋盘中所有的炸弹💣
思路是这样的,首先得输入一个有效坐标,如果该坐标是 ‘1’ ,真倒霉,被炸了游戏结束并打印炸弹布局,是否再来一局;如果该坐标是 ‘0’ ,统计该坐标周围一共有几个炸弹,继续游戏,直至找出所有炸弹,恭喜您,通关了,是否再来一局。
根据上面的思路,我们就可这样写:
voidFindMine(charmine[ROWS][COLS],charshow[ROWS][COLS],introw,intcol){intx=0;inty=0;intwin=0;while(win<row*col-EASY_COUNT){printf("请输入要排查的坐标:>");scanf("%d %d",&x,&y);if(x>=1&&x<=row&&y>=1&&y<=col){if(mine[x][y]=='1'){printf("很遗憾,你被炸死了\n");DisplayBoard(mine,ROW,COL);break;}else{intcount=GetMineCount(mine,x,y);show[x][y]=count+'0';DisplayBoard(show,ROW,COL);win++;}}else{printf("坐标错误,重新输入\n");}}if(win==row*col-EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(mine,ROW,COL);}}那如果该坐标是 ‘0’ ,又该如何统计该坐标周围一共有几个炸弹呢?
我们可以在判断该坐标不为炸弹调用函数int count = GetMineCount(mine, x, y);来计算
因为我们在此之前设置炸弹为 ‘1’,非炸弹为 ‘0’,那我们就可以将选择的坐标(x,y)的周围8个坐标值加起来即可,如下所示:
intGetMineCount(charmine[ROWS][COLS],intx,inty){return(mine[x-1][y]+mine[x-1][y-1]+mine[x][y-1]+mine[x+1][y-1]+mine[x+1][y]+mine[x+1][y+1]+mine[x][y+1]+mine[x-1][y+1]-8*'0');}二.游戏实现
声明:game.c和test.c的头文件在game.h里面,所有这两个文件顶端都要加上#include "game.h"
1.头文件game.h
#define_CRT_SECURE_NO_WARNINGS#pragmaonce#include<stdio.h>#include<stdlib.h>#include<time.h>#defineROW9#defineCOL9#defineROWSROW+2#defineCOLSCOL+2#defineEASY_COUNT10//设置炸弹数量voidInitBoard(charboard[ROWS][COLS],introws,intcols,charset);voidDisplayBoard(charboard[ROWS][COLS],introw,intcol);voidSetMine(charboard[ROWS][COLS],introw,intcol);voidFindMine(charmine[ROWS][COLS],charshow[ROWS][COLS],introw,intcol);2.源文件game.c
#include"game.h"//初始棋盘voidInitBoard(charboard[ROWS][COLS],introws,intcols,charset){inti=0;for(i=0;i<rows;i++){intj=0;for(j=0;j<cols;j++){board[i][j]=set;}}}voidDisplayBoard(charboard[ROWS][COLS],introw,intcol){inti=0;printf("--------扫雷游戏-------\n");for(i=0;i<=col;i++)//打印列{printf("%d ",i);}printf("\n");for(i=1;i<=row;i++){printf("%d ",i);//打印行intj=0;for(j=1;j<=col;j++){printf("%c ",board[i][j]);}printf("\n");}}voidSetMine(charboard[ROWS][COLS],introw,intcol){intcount=EASY_COUNT;while(count){intx=rand()%row+1;//rand() % row范围在0~row-1, +1后范围在1~rowinty=rand()%col+1;if(board[x][y]=='0'){board[x][y]='1';count--;}}}intGetMineCount(charmine[ROWS][COLS],intx,inty){return(mine[x-1][y]+mine[x-1][y-1]+mine[x][y-1]+mine[x+1][y-1]+mine[x+1][y]+mine[x+1][y+1]+mine[x][y+1]+mine[x-1][y+1]-8*'0');}voidFindMine(charmine[ROWS][COLS],charshow[ROWS][COLS],introw,intcol){intx=0;inty=0;intwin=0;while(win<row*col-EASY_COUNT){printf("请输入要排查的坐标:>");scanf("%d %d",&x,&y);if(x>=1&&x<=row&&y>=1&&y<=col){if(mine[x][y]=='1'){printf("很遗憾,你被炸死了\n");DisplayBoard(mine,ROW,COL);break;}else{intcount=GetMineCount(mine,x,y);show[x][y]=count+'0';DisplayBoard(show,ROW,COL);win++;}}else{printf("坐标错误,重新输入\n");}}if(win==row*col-EASY_COUNT){printf("恭喜你,排雷成功\n");DisplayBoard(mine,ROW,COL);}}3.源文件test.c
#include"game.h"//test.c 写游戏的测试逻辑//game.c 写游戏中函数的实现等//game.h 写游戏需要的数据类型和函数声明等voidmenu()//创建菜单{printf("********************\n");printf("***** 1.play *****\n");printf("***** 0.exit *****\n");printf("********************\n");}voidgame()//创建game{//用二维数组创建棋盘charmine[ROWS][COLS]={0};//存放好布置好的炸弹charshow[ROWS][COLS]={0};//存放排查出的炸弹的信息InitBoard(mine,ROWS,COLS,'0');InitBoard(show,ROWS,COLS,'*');//布置炸弹SetMine(mine,ROW,COL);//打印棋盘//DisplayBoard(mine, ROW, COL);//如果想看炸弹布局可将DisplayBoard前面//去掉DisplayBoard(show,ROW,COL);FindMine(mine,show,ROW,COL);}intmain(){intinput=0;srand((unsignedint)time(NULL));do{menu();//调用menu(菜单)printf("请选择:>");scanf("%d",&input);switch(input){case1:game();//调用gamebreak;case0:printf("退出游戏");break;default:printf("请重新选择!");break;}}while(input);return0;}运行结果(部分截图):
以上为简单扫雷游戏代码,想要做到真正的扫雷还需跟进一步学习,最后可以动手去试试,实践出真知!
宝剑锋从磨砺出,梅花香自苦寒来。