从零开始用 C 语言写扫雷
2026/9/12 21:24:34 网站建设 项目流程

目录:

  1. 项目结构:文件划分
  2. 菜单和棋盘初始化:为什么用 11×11 存 9×9
  3. 打印棋盘:雷区与显示区
  4. 随机埋雷:生成
  5. 玩家操作:输入、判断、输赢
  6. 游戏主循环:菜单与流程控制
  7. 踩坑记录
  8. 完整代码
  9. 总结

1.项目结构

本项目采用多文件编程,将声明、实现和入口分离,让每个文件职责清晰,方便后续维护和调试。

文件职责
game.h定义棋盘大小等宏,声明所有函数
game.c实现初始化、埋雷、打印、玩家操作等逻辑
test.c编写main()函数,调用菜单和游戏流程

2.菜单和棋盘初始化

打印菜单的代码如下:
test.c

voidmenu(){printf("- - - - - - - - - - - -\n");printf("- - - - 1.play - - - -\n");printf("- - - - 0.exit - - - -\n");printf("- - - - - - - - - - - -\n");}intmain(){intn=0;do{menu();printf("the number is: ");scanf("%d",&n);switch(n){case1://game();break;case0:printf("exit");break;default:printf("error");break;}}while(n);return0;}

在这里我把玩游戏的区域设为 9×9 ,但对于整个棋盘需设置为 11×11 , 因为在后续计算每个格子周围 8 个方向的雷数时,边缘格子会访问到 [-1] 或 [9] 这样的越界下标。多出一圈"围墙"后,所有合法格子的周围 8 个方向都在数组范围内,不需要额外写边界判断。
game.h

#defineROWS11#defineCOLS11#defineROW9#defineCOL9voidInitboard(charboard[ROWS][COLS],intr,intc,charset);

test.c

voidgame(){charmine[ROWS][COLS]={0};charshow[ROWS][COLS]={0};Initboard(show,ROWS,COLS,'?');Initboard(mine,ROWS,COLS,'0');}

game.c

voidInitBoard(charboard[ROWS][COLS],intr,intc,charset){for(inti=0;i<r;i++){for(intj=0;j<c;j++){board[i][j]=set;}}}

3. 打印棋盘:雷区与显示区

game.h

voidDislayBoard(charboard[ROWS][COLS],intr,intc);

game.c

voidDisplayBoard(charboard[ROWS][COLS],intr,intc){inti=0;intj=0;for(j;j<=r;j++){printf("%d ",j);}printf("\n");for(i=1;i<=r;i++){printf("%d ",i);for(j=1;j<=c;j++){printf("%c ",board[i][j]);}printf("\n");}printf("\n");}

test.c

voidgame(){DisplayBoard(show,ROW,COL);DisplayBoard(mine,ROW,COL);}

4. 随机埋雷:生成

game.h

#include<stdlib.h>#include<time.h>#defineSET10voidSetmine(charboard[ROWS][COLS],intr,intc);

game.c

voidSetmine(charboard[ROWS][COLS],intr,intc){intcount=SET;while(count){intx=rand()%r+1;inty=rand()%c+1;if(board[x][y]=='0'){board[x][y]='1';count--;}}}

test.c

voidgame(){Setmine(mine,ROW,COL);}intmain(){srand((unsignedint)time(NULL));}

5. 玩家操作:输入、判断、输赢

这个模块是玩游戏的重要部分,下面我讲拆成一下六个部分来讲解:

  • 输入坐标
    通过输入行号和列号来选择要翻开的格子,比如输入 2 3 表示翻开第 2 行第 3 列。

  • 合法性判断
    输入的坐标不能越界并且不能是已经翻过的格子,这里需要判断合不合法,不合法时提示重新输入,合法才继续。

  • 踩雷判断
    翻开格子后,需根据mine棋盘,看是 ‘1’ 还是 ‘0’ , 是 ‘1’ 结束游戏; 是 ‘0’ 继续游戏。

  • 计算周围的雷数
    如果没踩雷,统计该格子周围 8 个方向有多少个 ‘1’,把结果写入 show 棋盘对应位置。

关于计算雷数的方法有多种,这里我介绍两个:
方法1:

returnboard[x+1][y]+board[x+1][y-1]+board[x+1][y+1]+board[x][y+1]+board[x][y-1]+board[x-1][y]+board[x-1][y+1]+board[x-1][y-1]-8*'0';

思路:把 8 个方向的字符全部加起来,最后统一减去 8 * ‘0’,把 8 个字符都转成数字。

方法2:

for(i=-1;i<=1;i++){for(j=-1;j<=1;j++){count+=(mine[x+i][y+j]-'0');}}returncount;

思路:用 i 和 j 从 -1 到 1 遍历,刚好覆盖周围 8 个方向加上自身。每个格子单独减 ‘0’ 转成数字后累加。

  • 胜利判断
    每次成功翻开一个格子后,检查是否所有非雷格子都已被翻开。如果是,则玩家获胜。

  • 循环控制
    把以上步骤放在一个循环里,玩家每回合操作一次,直到踩雷(失败)或全部翻开(胜利)才退出循环。

结合以上思路,得到以下代码:

game.h

voidSearchmine(charshow[ROWS][COLS],charmine[ROWS][COLS],intr,intc);

game.c

inttne_number_of_mine(charboard[ROWS][COLS],intx,inty){returnboard[x+1][y]+board[x+1][y-1]+board[x+1][y+1]+board[x][y+1]+board[x][y-1]+board[x-1][y]+board[x-1][y+1]+board[x-1][y-1]-8*'0';}voidSearchmine(charshow[ROWS][COLS],charmine[ROWS][COLS],intr,intc){intx,y;intamount=0;printf("site : ");scanf("%d %d",&x,&y);while(amount<r*c-SET){if(x>0&&x<=r&&y>0&&y<=c){if(show[x][y]=='?'){intcount=tne_number_of_mine(mine,x,y);show[x][y]='0'+count;DisplayBoard(show,ROW,COL);amount++;}else{printf("bomb! you dead\n");DisplayBoard(mine,ROW,COL);break;}}else{printf("the address is illegal\n");break;}}if(amount==r*c-SET){printf("congratulation! you make it\n");DisplayBoard(mine,ROW,COL);}}

test.c

voidgame(){Searchmine(show,mine,ROW,COL);}

6. 踩坑记录

再写代码时需注意这两个函数的顺序,SetMine(mine, ROW, COL); 在前,
DisplayBoard(mine, ROW, COL);在后。

SetMine(mine,ROW,COL);DisplayBoard(mine,ROW,COL);

7. 完整代码

game.h

#include<stdio.h>#include<stdlib.h>#include<time.h>#defineROWS11#defineCOLS11#defineROW9#defineCOL9#defineSET10voidInitboard(charboard[ROWS][COLS],intr,intc,charset);voidDislayBoard(charboard[ROWS][COLS],intr,intc);voidSetmine(charboard[ROWS][COLS],intr,intc);voidSearchmine(charshow[ROWS][COLS],charmine[ROWS][COLS],intr,intc);

game.c

#define_CRT_SECURE_NO_WARNINGS#include"game.h"voidInitboard(charboard[ROWS][COLS],intr,intc,charset){inti=0;intj=0;for(i=1;i<r;i++){for(j=1;j<c;j++){board[i][j]=set;}}}voidDisplayBoard(charboard[ROWS][COLS],intr,intc){inti=0;intj=0;for(j;j<=r;j++){printf("%d ",j);}printf("\n");for(i=1;i<=r;i++){printf("%d ",i);for(j=1;j<=c;j++){printf("%c ",board[i][j]);}printf("\n");}printf("\n");}voidSetmine(charboard[ROWS][COLS],intr,intc){intcount=SET;while(count){intx=rand()%r+1;inty=rand()%c+1;if(board[x][y]=='0'){board[x][y]='1';count--;}}}inttne_number_of_mine(charboard[ROWS][COLS],intx,inty){returnboard[x+1][y]+board[x+1][y-1]+board[x+1][y+1]+board[x][y+1]+board[x][y-1]+board[x-1][y]+board[x-1][y+1]+board[x-1][y-1]-8*'0';}voidSearchmine(charshow[ROWS][COLS],charmine[ROWS][COLS],intr,intc){intx,y;intamount=0;printf("site : ");scanf("%d %d",&x,&y);while(amount<r*c-SET){if(x>0&&x<=r&&y>0&&y<=c){if(show[x][y]=='?'){intcount=tne_number_of_mine(mine,x,y);show[x][y]='0'+count;DisplayBoard(show,ROW,COL);amount++;}else{printf("bomb! you dead\n");DisplayBoard(mine,ROW,COL);break;}}else{printf("the address is illegal\n");break;}}if(amount==r*c-SET){printf("congratulaton! you make it\n");DisplayBoard(mine,ROW,COL);}}

test.c

#define_CRT_SECURE_NO_WARNINGS#include"game.h"voidmenu(){printf("- - - - - - - - - - - -\n");printf("- - - - 1.play - - - -\n");printf("- - - - 0.exit - - - -\n");printf("- - - - - - - - - - - -\n");}voidgame(){charmine[ROWS][COLS]={0};charshow[ROWS][COLS]={0};Initboard(show,ROWS,COLS,'?');Initboard(mine,ROWS,COLS,'0');DisplayBoard(show,ROW,COL);Setmine(mine,ROW,COL);DisplayBoard(mine,ROW,COL);Searchmine(show,mine,ROW,COL);}intmain(){intn=0;srand((unsignedint)time(NULL));do{menu();printf("the number is: ");scanf("%d",&n);switch(n){case1:game();break;case0:printf("exit");break;default:printf("error");break;}}while(n);return0;}

8. 总结

本文用 C 语言实现了一个 9×9 的扫雷小游戏,核心要点如下:

  • 多文件结构game.h声明、game.c实现、test.c入口,职责清晰。
  • 11×11 存 9×9:多出一圈"围墙",避免统计周围雷数时数组越界。
  • 随机埋雷:用rand()在非雷位置生成 10 颗雷。
  • 玩家操作:输入坐标 → 合法性判断 → 踩雷判断 → 统计周围雷数 → 胜利判断,循环直到输赢。
  • 踩坑提醒:先SetMine埋雷,再DisplayBoard打印,顺序不能反。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询