C语言实现扫雷小游戏实例介绍

这篇文章主要介绍“C语言实现扫雷小游戏实例介绍”,在日常操作中,相信很多人在C语言实现扫雷小游戏实例介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C语言实现扫雷小游戏实例介绍”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

壶关网站建设公司创新互联,壶关网站设计制作,有大型网站制作公司丰富经验。已为壶关近千家提供企业网站建设服务。企业网站搭建\成都外贸网站建设要多少钱,请找那个售后服务好的壶关做网站的公司定做!

游戏简介

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

实现的功能介绍

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

该程序分为三个文件:

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

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

游戏功能代码详解

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#include#include#include#include//定义打印的雷盘行、列#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语言实现扫雷小游戏实例介绍”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注创新互联网站,小编会继续努力为大家带来更多实用的文章!


当前题目:C语言实现扫雷小游戏实例介绍
浏览地址:http://pwwzsj.com/article/gdcpoo.html