温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C语言中如何实现扫雷小游戏

发布时间:2021-05-28 12:48:17 来源:亿速云 阅读:212 作者:小新 栏目:编程语言

这篇文章给大家分享的是有关C语言中如何实现扫雷小游戏的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

游戏简介

扫雷,是一款益智类小游戏。
游戏目标是找出所有没有地雷的方格,完成游戏;要是按了有地雷的方格,游戏失败;玩家可标记雷的位置。游戏以完成时间来评高低。有不同的游戏难度可选择。

实现的功能介绍

1.计时
2.初始化雷盘
3.打印雷盘
4.随机设置雷的分布,可选择游戏难易程度
5.统计坐标位置周围的雷数
6.第一次排雷不会被炸死
7.扩展式排雷,展开周围的非雷区
8.给所选坐标位置做标记,或取消标记

该程序分为三个文件:

1.game.h :包含头文件的引用、函数的声明和宏定义
2.game.c :包含游戏各功能函数的具体实现
3.pro.c :各功能函数的调用(程序的流程)
PS:文章末尾附完整代码 及 游戏效果图

C语言中如何实现扫雷小游戏 

因为排雷时要计算每个位置周围八个位置的雷数,所以在创建数组时要多一圈,即行列都要加2。给用户显示的数组不需要加。

C语言中如何实现扫雷小游戏

游戏功能代码详解

1.计时

运用clock函数,该函数需要的头文件为 “time.h”
函数原型:clock_t clock(void);
功能:程序从启动到函数调用占用CPU的时间
这个函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick)数,在MSDN中称之为挂钟时间;若挂钟时间不可取,则返回-1。其中clock_t是用来保存时间的数据类型。

void set_time()//计时 {   printf("用时:%u 秒\n", clock() / CLOCKS_PER_SEC); }

2.初始化雷盘
这里我用到的是memset函数,需要的头文件为“memory.h”或“string.h”
函数原型:void *memset(void *s, int ch, size_t n);
功能:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。在一段内存块中填充某个给定的值。

void init_board(char board[ROWS][COLS], int row, int col, char c)//初始化雷盘 {   memset(board, c, row*col*sizeof(board[0][0])); }

3.打印雷盘
运用两个循环体实现雷盘数组的赋值、行号、列号的打印。正式游戏时可以加上system(“CLS”); 清屏语句,每次调用时都清屏一次,使游戏画面更简洁清晰。
我们把计时函数放在里面,每次打印雷盘时就可以显示所用的时间。

void disp_board(char board[ROWS][COLS], int row, int col)//打印雷盘 {   int i = 0;   int j = 0;   //system("CLS");//清屏   for (i = 0; i <= row; i++)   {     printf("%2d ", i);//打印行号   }   printf("\n");   for (i = 1; i <= row; i++)   {     printf("%2d ", i);//打印列号     for (j = 1; j <= col; j++)     {       printf("%2c ", board[i][j]);     }     printf("\n");   }   printf("\n");   set_time();//打印所用的时间 }

4.随机设置雷的分布,可选择游戏难易程度
放置雷必须是随机的,这里用到了rand函数,它和srand函数配合使用产生随机数。srand(time(NULL))放在主函数中调用一次,通过系统时间提供的种子值,使rand函数生成不同的伪随机数序列。

void set_mine(char board[ROWS][COLS], int row, int col,int count)//置雷 {   int x = 0;   int y = 0;    while (count)   {     x = rand() % row + 1;//随机位置范围1~row     y = rand() % col + 1;//随机位置范围1~col     if (board[x][y] == '0')//判断是否已有雷     {       board[x][y] = '1';//有雷的位置赋为1       count--;     }   } }

5.统计坐标位置周围的雷数 及 未扫的位置的个数
当扫到一个没有雷的位置时,会显示这个位置周围一圈八个位置的含雷的总数,所以我们要写一个“数雷”函数来数。

int count_mine(char mine[ROWS][COLS], int x, int y)//数雷 {   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';//数周围一圈八个位置的雷数 } int count_print(char print[ROWS][COLS], int row, int col)//数未扫位置 {   int count = 0;   int i = 0;   for (i = 1; i <= row; i++)   {     int j = 0;     for (j = 1; j <= col; j++)     {       if (print[i][j] == '@' ||print[i][j] == '*')       {         count++;       }     }   }   return count; }

6.第一次排雷不会被炸死
为了增加游戏的可玩性,加入“第一次排雷不被炸死”这个函数。当第一次排就遇到雷时,我们把雷偷偷挪走,随机放在一个原本无雷的位置。

void safe_mine(char mine[ROWS][COLS],char print[ROWS][COLS],int x,int y,int row,int col)//第一次排雷不炸死 {   char ch = 0;   int ret = 1;   int number = 0;   if (mine[x][y] == '1')//第一次踩到雷后补救   {     mine[x][y] = '0';     char ch = count_mine(mine, x, y);     print[x][y] = ch + '0';//数字对应的ASCII值和数字字符对应的ASCII值相差48,即'0'的ASCII值     extend_board(mine, print, x, y);     while (ret)//在其余有空的地方设置一个雷     {       int x = rand() % row + 1;//产生1到row的随机数,在数组下标为1到10的范围内布雷       int y = rand() % col + 1;//产生1到col的随机数,在数组下标为1到10的范围内布雷       if (mine[x][y] == '0')//找不是雷的地方布雷       {         mine[x][y] = '1';         disp_board(print, row, col);         //disp_board(mine, row, col);         ret--;         break;       }     }   } }

7.扩展式排雷,展开周围的非雷区
当游戏中排到一个周围一圈都无雷的位置时,运用递归,实现扩展展开周围的一片无雷区。

void extend_board(char mine[ROWS][COLS], char print[ROWS][COLS], int x, int y)//运用递归扩展周围 {      int n = 0;   n = count_mine(mine, x, y);    if (n == 0)//当该位置周围雷数为0时扩展   {     print[x][y] = ' ';//扩展的位置变为“空格”打印出来     if (mine[x - 1][y] == '0' && print[x - 1][y] == '@')     {       extend_board(mine, print, x - 1, y);//递归     }     if (mine[x + 1][y] == '0' && print[x + 1][y] == '@')     {       extend_board(mine, print, x + 1, y);     }     if (mine[x][y + 1] == '0' && print[x][y + 1] == '@')     {       extend_board(mine, print, x, y + 1);     }     if (mine[x - 1][y + 1] == '0' && print[x - 1][y + 1] == '@')     {       extend_board(mine, print, x - 1, y + 1);     }     if (mine[x + 1][y + 1] == '0' && print[x + 1][y + 1] == '@')     {       extend_board(mine, print, x + 1, y + 1);     }     if (mine[x][y - 1] == '0' && print[x][y - 1] == '@')     {       extend_board(mine, print, x, y - 1);     }     if (mine[x + 1][y - 1] == '0' && print[x + 1][y -1] == '@')     {       extend_board(mine, print, x + 1, y - 1);     }     if (mine[x - 1][y - 1] == '0' && print[x - 1][y - 1] == '@')     {       extend_board(mine, print, x - 1, y - 1);     }   }   else       print[x][y] = n + '0';  }  int find_mine(char mine[ROWS][COLS], char print[ROWS][COLS], int row, int col,int count)//排雷 {   int x = 0;   int y = 0;   int number = 0;   int ret = 0;   while (1)   {     printf("输入坐标扫雷\n");     scanf("%d%d", &x, &y);//玩家输入扫雷的坐标位置     if ((x >= 1 && x <= row) && (y >= 1 && y <= col))//判断输入坐标是否有误,输入错误重新输入     {       if (mine[x][y] == '0')//没踩到雷       {         number++;//记录扫雷的次数         char ch = count_mine(mine, x, y);//数雷数         print[x][y] = ch + '0';//数字对应的ASCII值和数字字符对应的ASCII值相差48,即'0'的ASCII值         extend_board(mine, print, x, y);         disp_board(mine, row, col);         disp_board(print, row, col);         if (count_print(print, row, col) == count)//剩余未扫位置=雷数 时胜利         {           return 0;         }         to_sign(print);//判断是否标记         disp_board(print, row, col);       }       else if (mine[x][y] == '1')//踩到雷       {         if (ret == 0 && number == 0)         {           ret++;           safe_mine(mine,print,x,y,row,col);         }         else           return 1;       }     }     else     {       printf("输入错误!请重新输入\n");     }   } }

8.给所选坐标位置做标记,或取消标记
扫雷游戏还有一个功能:可以给你认为是雷的位置标记,或者取消标记。
我通过三个函数来实现,一个判断用户是否需要标记;一个实现标记功能,将@标记成* ;一个实现取消标记功能,将* 改回@。

void to_sign(char board[ROWS][COLS])//判断是否标记 {   int chose_b = 0;   int x = 0;   int y = 0;   printf("是否需要标记/取消标记:>\n(1.标记 ;2.取消标记 ;3.跳过该步骤) :>");   scanf("%d", &chose_b);   do{     switch (chose_b)     {     case 1:     {          printf("请输入需要标记的位置坐标:>\n");          scanf("%d%d", &x, &y);          sign(board, x, y);          break;     }     case 2:     {          printf("请输入取消标记的位置坐标:>\n");          scanf("%d%d", &x, &y);          unsign(board, x, y);          break;     }     case 3:     {          printf("跳过此步骤。\n");          chose_b = 0;          break;     }     default:     {     printf("输入错误!\n");          chose_b = 0;          break;     }     }     chose_b = 0;   } while (chose_b); } void sign(char board[ROWS][COLS], int x, int y)//用‘*'标记雷 {   if (board[x][y] == '@')   {     board[x][y] = '*';   } } void unsign(char board[ROWS][COLS], int x, int y)//取消标记 {   if (board[x][y] == '*')   {     board[x][y] = '@';   } }

附:完整代码

game.h

#ifndef  _GAME_H_ #define  _GAME_H_ //用到的头文件 #include<stdio.h> #include<stdlib.h> #include<time.h> #include<string.h> #include<windows.h> //定义打印的雷盘行、列 #define _ROW 9 #define _COL 9 #define ROW 16 #define COL 16 //定义数组的行、列 #define _ROWS _ROW+2 #define _COLS _COL+2 #define ROWS ROW+2 #define COLS COL+2 //定义难、易程度雷数 #define EASY_COUNT 10 #define HARD_COUNT 40 //定义游戏中的函数 void init_board(char board[ROWS][COLS],int row, int col, char c);//初始化 void disp_board(char board[ROWS][COLS],int row,int col);//打印 void set_mine(char board[ROWS][COLS], int row, int col,int count);//置雷 void safe_mine(char mine[ROWS][COLS], char print[ROWS][COLS], int x, int y, int row, int col);//第一次排雷不炸死 int find_mine(char mine[ROWS][COLS], char print[ROWS][COLS], int row, int col,int count);//排雷 int count_mine(char mine[ROWS][COLS], int x, int y);//数雷 void extend_board(char mine[ROWS][COLS], char print[ROWS][COLS], int x, int y);//扩展 void to_sign(char board[ROWS][COLS]);//判断是否标记 void sign(char board[ROWS][COLS], int x, int y);//标记 void unsign(char board[ROWS][COLS], int x, int y);//取消标记 int count_print(char print[ROWS][COLS], int row, int col);//数未扫位置 #endif//_GAME_H_

game.c

#define _CRT_SECURE_NO_WARNINGS #include "game.h" void set_time()//计时 {   printf("用时:%u 秒\n", clock() / CLOCKS_PER_SEC); } void init_board(char board[ROWS][COLS], int row, int col, char c)//初始化雷盘 {   memset(board, c, row*col*sizeof(board[0][0])); } void disp_board(char board[ROWS][COLS], int row, int col)//打印雷盘 {   int i = 0;   int j = 0;   system("CLS");//清屏   for (i = 0; i <= row; i++)//加行号   {     printf("%2d ", i);   }   printf("\n");   for (i = 1; i <= row; i++)//加列号   {     printf("%2d ", i);     for (j = 1; j <= col; j++)     {       printf("%2c ", board[i][j]);     }     printf("\n");   }   printf("\n");   set_time();//打印所用的时间 } void set_mine(char board[ROWS][COLS], int row, int col,int count)//置雷 {   int x = 0;   int y = 0;    while (count)   {     x = rand() % row + 1;//随机位置范围1~row     y = rand() % col + 1;//随机位置范围1~col     if (board[x][y] == '0')//判断是否已有雷     {       board[x][y] = '1';       count--;     }   } } void safe_mine(char mine[ROWS][COLS],char print[ROWS][COLS],int x,int y,int row,int col)//第一次排雷不炸死 {   char ch = 0;   int ret = 1;   int number = 0;   if (mine[x][y] == '1')//第一次踩到雷后补救   {     mine[x][y] = '0';     char ch = count_mine(mine, x, y);     print[x][y] = ch + '0';//数字对应的ASCII值和数字字符对应的ASCII值相差48,即'0'的ASCII值     extend_board(mine, print, x, y);     while (ret)//在其余有空的地方设置一个雷     {       int x = rand() % row + 1;//产生1到row的随机数,在数组下标为1到10的范围内布雷       int y = rand() % col + 1;//产生1到col的随机数,在数组下标为1到10的范围内布雷       if (mine[x][y] == '0')//找不是雷的地方布雷       {         mine[x][y] = '1';         disp_board(print, row, col);         //disp_board(mine, row, col);         ret--;         break;       }     }   } } int count_mine(char mine[ROWS][COLS], int x, int y)//数雷 {   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';//数周围一圈八个位置的雷数 } int count_print(char print[ROWS][COLS], int row, int col)//数未扫位置 {   int count = 0;   int i = 0;   for (i = 1; i <= row; i++)   {     int j = 0;     for (j = 1; j <= col; j++)     {       if (print[i][j] == '@' ||print[i][j] == '*')       {         count++;       }     }   }   return count; } void extend_board(char mine[ROWS][COLS], char print[ROWS][COLS], int x, int y)//运用递归扩展周围 {      int n = 0;   n = count_mine(mine, x, y);    if (n == 0)//当该位置周围雷数为0时扩展   {     print[x][y] = ' ';//扩展的位置变为“空格”打印出来     if (mine[x - 1][y] == '0' && print[x - 1][y] == '@')     {       extend_board(mine, print, x - 1, y);//递归     }     if (mine[x + 1][y] == '0' && print[x + 1][y] == '@')     {       extend_board(mine, print, x + 1, y);     }     if (mine[x][y + 1] == '0' && print[x][y + 1] == '@')     {       extend_board(mine, print, x, y + 1);     }     if (mine[x - 1][y + 1] == '0' && print[x - 1][y + 1] == '@')     {       extend_board(mine, print, x - 1, y + 1);     }     if (mine[x + 1][y + 1] == '0' && print[x + 1][y + 1] == '@')     {       extend_board(mine, print, x + 1, y + 1);     }     if (mine[x][y - 1] == '0' && print[x][y - 1] == '@')     {       extend_board(mine, print, x, y - 1);     }     if (mine[x + 1][y - 1] == '0' && print[x + 1][y -1] == '@')     {       extend_board(mine, print, x + 1, y - 1);     }     if (mine[x - 1][y - 1] == '0' && print[x - 1][y - 1] == '@')     {       extend_board(mine, print, x - 1, y - 1);     }   }   else       print[x][y] = n + '0';  }  int find_mine(char mine[ROWS][COLS], char print[ROWS][COLS], int row, int col,int count)//排雷 {   int x = 0;   int y = 0;   int number = 0;   int ret = 0;   while (1)   {     printf("输入坐标扫雷\n");     scanf("%d%d", &x, &y);//玩家输入扫雷的坐标位置     if ((x >= 1 && x <= row) && (y >= 1 && y <= col))//判断输入坐标是否有误,输入错误重新输入     {       if (mine[x][y] == '0')//没踩到雷       {         number++;//记录扫雷的次数         char ch = count_mine(mine, x, y);//数雷数         print[x][y] = ch + '0';//数字对应的ASCII值和数字字符对应的ASCII值相差48,即'0'的ASCII值         extend_board(mine, print, x, y);     //   disp_board(mine, row, col);         disp_board(print, row, col);         if (count_print(print, row, col) == count)//剩余未扫位置=雷数 时胜利         {           return 0;         }         to_sign(print);//判断是否标记         disp_board(print, row, col);       }       else if (mine[x][y] == '1')//踩到雷       {         if (ret == 0 && number == 0)         {           ret++;           safe_mine(mine,print,x,y,row,col);         }         else           return 1;       }     }     else     {       printf("输入错误!请重新输入\n");     }   } } void sign(char board[ROWS][COLS], int x, int y)//用‘*'标记雷 {   if (board[x][y] == '@')   {     board[x][y] = '*';   } } void unsign(char board[ROWS][COLS], int x, int y)//取消标记 {   if (board[x][y] == '*')   {     board[x][y] = '@';   } } void to_sign(char board[ROWS][COLS])//判断是否标记 {   int chose_b = 0;   int x = 0;   int y = 0;   printf("是否需要标记/取消标记:>\n(1.标记 ;2.取消标记 ;3.跳过该步骤) :>");   scanf("%d", &chose_b);   do{     switch (chose_b)     {     case 1:     {          printf("请输入需要标记的位置坐标:>\n");          scanf("%d%d", &x, &y);          sign(board, x, y);          break;     }     case 2:     {          printf("请输入取消标记的位置坐标:>\n");          scanf("%d%d", &x, &y);          unsign(board, x, y);          break;     }     case 3:     {          printf("跳过此步骤。\n");          chose_b = 0;          break;     }     default:     {     printf("输入错误!\n");          chose_b = 0;          break;     }     }     chose_b = 0;   } while (chose_b); }

pro.c

#define _CRT_SECURE_NO_WARNINGS #include "game.h" void menu() {   printf("+---------------------------------+\n");   printf("+   Welcome to 扫雷世界 !   +\n");   printf("+     ο(=>ω<=)ρ⌒☆    +\n");   printf("+      1、play        +\n");   printf("+      0、exit        +\n");   printf("+---------------------------------+\n"); } void game() {   char mine[ROWS][COLS] = { 0 };   char print[ROWS][COLS] = { 0 };   int chose_m = 0;   int ret = 0;   printf("请选择模式(1、简单 2、困难):>");//选择游戏难易程度,产生不同大小的棋盘和雷数   scanf("%d", &chose_m);   switch (chose_m)   {   case 1:   {             init_board(mine, ROWS, COLS, '0');//初始化雷盘          init_board(print, ROWS, COLS, '@');          set_mine(mine, _ROW, _COL, EASY_COUNT);//布雷   //      disp_board(mine, _ROW, _COL);//打印雷盘          disp_board(print, _ROW, _COL);          int ret = find_mine(mine, print, _ROW, _COL, EASY_COUNT);//扫雷,踩到雷返回1,没有踩到雷返回0          while (1)//循环扫雷          {            if (ret == 0)//若返回0则胜利            {              disp_board(print, _ROW, _COL);              printf("WOW~ YOU WIN!\n\n");              break;            }           if (ret)//若返回1则失败            {              disp_board(mine, _ROW, _COL);//打印雷盘              printf("GAME OVER!\n");              break;            }             disp_board(print, _ROW, _COL);//打印玩家棋盘          }          break;     }     case 2:     {          init_board(mine, ROWS, COLS, '0');//初始化雷盘          init_board(print, ROWS, COLS, '@');          set_mine(mine, ROW, COL, HARD_COUNT);//布雷     //    disp_board(mine, ROW, COL);//打印雷盘          disp_board(print, ROW, COL);          while (1)//循环扫雷          {            int ret = find_mine(mine, print, ROW, COL, HARD_COUNT);//扫雷,踩到雷返回1,没有踩到雷返回0            if (ret == 0)//若返回0胜利            {              disp_board(print, ROW, COL);              printf("WOW~ YOU WIN!\n\n");              break;            }            if (ret)//若返回1失败            {              disp_board(mine, ROW, COL);//打印雷盘              printf("GAME OVER!\n");              break;            }            disp_board(print, ROW, COL);//打印玩家棋盘          }          break;     }     default:     {           printf("输入错误!\n");           break;     }   } } void text() {   srand((unsigned int)time(NULL));//产生随机值发生器   int chose = 0;//选择是否开始游戏   do   {     menu();//菜单     printf("请选择:>");     scanf("%d", &chose);     switch (chose)     {     case 1:       game();//开始游戏       break;     case 0:       printf("退出游戏\n");       break;     default:       printf("输入错误,没有该选项\n");       break;     }   } while (chose); } int main() {   text();   system("pause");   return 0; }

游戏效果图 

①开始选择菜单、难易模式选择
C语言中如何实现扫雷小游戏
②两种难度扫雷
↓9×9雷盘 10颗雷
C语言中如何实现扫雷小游戏
↓16×16雷盘 40颗雷
C语言中如何实现扫雷小游戏
③演示标记
C语言中如何实现扫雷小游戏
C语言中如何实现扫雷小游戏
④GAME OVER 玩家失败演示
C语言中如何实现扫雷小游戏
⑤WIN 玩家成功演示
C语言中如何实现扫雷小游戏

感谢各位的阅读!关于“C语言中如何实现扫雷小游戏”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI