【C语言】实现简单扫雷

简介: 布置雷-10个扫雷输入坐标是雷 --就炸死,游戏结束不是雷 --告诉你这个坐标周围8个坐标上总共有几个雷。 直到把所有非雷的位置全部找出来,游戏结束,扫雷成功。

76b6371d9fbfb461e903dbd14acd625f_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_12,color_FFFFFF,t_70,g_se,x_16.png

扫雷简单版介绍:

布置雷-10个

扫雷

输入坐标

是雷 --就炸死,游戏结束

不是雷 --告诉你这个坐标周围8个坐标上总共有几个雷。  

直到把所有非雷的位置全部找出来,游戏结束,扫雷成功。


布局分析:

     首先要我们要有一个9*9的棋盘,然后把雷的位置存储进去


     但是这些的雷的存储需要存储空间,如何才能存储雷的信息呢?


数组 创建一个二维数组来存储这些雷的信息


    接下来就是雷的布置了,如果用字符‘0’表示为非雷,用字符‘1’表示为雷。


    当我们扫雷的时候,挑选了一个坐标不是雷,同时周围有两个雷,这个坐标就会显示‘2’。


    问题来了,当我们扫到一个坐标周围有一个雷的时候就先显示‘1’,这与布置雷时显示‘1’的含义冲突。


    为了避免这种冲突,我们创建两个二维数组,分别为mine[9][9]和show[9][9]。


    mine数组:存储布置好雷的信息,非雷为字符‘0’,雷为字符‘1’ (挖坑,注:后面会把坑填上)


    show数组:存储排查出雷达信息,未排查的用‘*’显示,排查出的则显示周围雷的个数

e1417f4b8f1d367ce2488cf78e6d0269_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png


   接下来又出现一个新问题,当我们在排查的时候,如果这个坐标不是雷那么就会访问周围八个坐标的雷数。


   如果这个排查雷的坐标在边缘如下图(9,8)那么在访问过程中就会越界,而如果我们每一次排查边缘位置时就要判断周围八个坐标的合法性就会显的太过麻烦,所以最后的解决方案是把mine数组提升到11*11(注:上下各加一行,左右各加一列)

07350ace849372f591ce628652006467_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png

     为了让show数组对应mine数组,所以show数组也要提升到11*11


代码实现:      

       本次分为三个部分game.h h和 test.c 和 game.c


       test.c 主要实现扫雷主体,game.c主要实现扫雷中函数实现,game.h主要实现个函数声明


game.h代码实现:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9  //行数
#define COL 9  //列数
#define ROWS ROW+2  
#define COLS COL+2
#define EASY_COUNT 10  //简单版  布置10个雷
//初始化
void init_board(char arr[ROWS][COLS], int rows, int cols, char set);
//打印
void show_board(char arr[ROWS][COLS], int row, int col);
//布置雷
void set_mine(char mine[ROWS][COLS],int row,int col);
//排查雷
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//获取雷的数量
int get_mine_count(char mine[ROWS][COLS], int x, int y);

test.c代码实现:

main函数实现:

首先要实现一个菜单界面,比如选择1:开始玩游戏、选择0:退出


创建一个input变量(目的:为了接收玩家输入信息),用do while语句循环,接着添加menu函数scanf函数接受input的值,switch语句进行选择。


               srand((unsigned int)time(NULL))是为了实现随机数,会在game.c模块里面提及

int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do {
  menu();
  printf("请输入:>");
  scanf("%d", &input);
  switch (input)
  {
  case 1:
    game();
    break;
  case 0:
    printf("退出\n");
    break;
  default:
    printf("输入错误,重新输入\n");
    break;
  }
  } while (input);
  return 0;
}

menu函数实现(菜单):

void menu()
{
  printf("**************************\n");
  printf("********  1.paly  ********\n");
  printf("********  0.exit  ********\n");
}

game函数实现:

首先创建mine和show数组

用init_board函数进行初始化

用set_mine函数布置雷

用show_board函数打印棋盘

用find_mine函数排查雷

       这些函数会在game.c里面实现

void game()
{
  //扫雷实现
  //mine数组是用来存放布置好雷的信息
  char mine[ROWS][COLS] = { 0 };//'0'
  //show数组是用来存放排查出的雷的信息的
  char show[ROWS][COLS] = { 0 };//'*'
  //初始化棋盘
  init_board(mine, ROWS, COLS,'0'); //mine[11][11]数组全部初始化为字符‘0’
  init_board(show, ROWS, COLS,'*'); //show[11][11]数组全部初始化为字符‘1’
  //布置雷
  set_mine(mine, ROW,COL);
   //打印棋盘
  show_board(show, ROW, COL);
  //排查雷
  find_mine(mine, show, ROW, COL);
}

game.c代码实现(主要功能):

       init_board函数实现:

主要功能:初始化棋盘

传参:{ arr[11][11],行,列,初始化内容}

返回值: 无

void init_board(char arr[ROWS][COLS], int rows, int cols,char set)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < rows; i++)
  {
  for (j = 0; j < cols; j++)
  {
    arr[i][j] = set;
  }
  }
}

show_board函数实现:

主要功能:打印棋盘


传参:{ arr[11][11] ,行,列,初始化内容}


(这里面传入的是ROW和COL,因为玩游戏时只用显示中间9*9的空间就行了)


返回值: 无


在打印棋盘的过程中,加入行和列数方便玩家出入坐标,效果如下


ac2a7309d38fb6405fed05e2d18ea2d6_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_16,color_FFFFFF,t_70,g_se,x_16.png

void show_board(char arr[ROWS][COLS], int row, int col)
{
  int i = 0;
  int j = 0;
  printf("---------扫雷---------\n");
  for (i = 0; i <= col; i++)
  {
  printf("%d ", i);
  }
  printf("\n");
  for (i = 1; i <= row; i++)
  {
  printf("%d ", i);
  for (j = 1; j <= col; j++)
  {
    printf("%c ", arr[i][j]);
  }
  printf("\n");
  }
  printf("---------扫雷---------\n");
}

 set_mine 函数实现:

               功能:布置雷


               传参:{mine[11][11],行(9),列(9)}


               首先声明一个变量count,并赋值为EASY_COUNT。


               声明x、y表示坐标


               接下来布置雷的坐标用rand库函数来实现


rand() % row + 1 表示生成的坐标在1~9 之间


               同时还要判断随机产生的坐标是不是已经布置好雷,用if语句


rand()生成随机数的函数


               然后要布置EASY_COUNT个雷,每次布置一个雷,EASY_COUNT就减去一个,所以用while循环来表示这种效果。


void set_mine(char mine[ROWS][COLS], int row, int col)
{
  int count = EASY_COUNT; // EASY_COUNT = 9 在game.h中声明
  int x = 0;
  int y = 0;
  while (count)
  {
  x = rand() % row + 1;
  y = rand() % col + 1;
  if (mine[x][y] == '0')
  {
    mine[x][y] = '1';//布置雷
    count--; 
  }
  }
}

get_mine_count函数实现:

               功能:获取雷达数量


               传参:{mine[11][11],行(坐标),列(坐标)}


               返回值: n(雷的个数)


               首先声明一个整数n 记录雷的个数。


               下面用for循环遍历九个坐标。


               不知 大家有没有了解过下面两个式子


‘0’ - ‘0’ = 0


‘1’ - ‘0’ = 1


(‘0’的ASCII 码的值为 48,‘1’的ASCII 码的值为 49)

2f172e0a229723602e270dc92a7c1900_watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aiB5aiB5rKB5rKB,size_20,color_FFFFFF,t_70,g_se,x_16.png



                所以,只需要需要把九个坐标相加并减去九个‘0’,也就得到雷的个数。


               而如果要用‘*’或者‘#’表示雷或非雷,就不能用这种情况,会变得麻烦。


               这也是为啥在mine数组里面都是用字符‘0’表示非雷,用字符‘1’表示雷(填坑)

int get_mine_count(char mine[ROWS][COLS],int x,int y)
{
  int n = 0;
  for (int i = -1; i <= 1; i++)
  {
  for (int j = -1; j <= 1; j++)
  {
    n += mine[x + i][y + j] - '0';
  }
  }
  return n;
}

search_mine函数实现:

               功能:对坐标为非雷且周围没有雷的位置,进行连展


               传参:{ mine[11][11] , show[11][11] , x(横坐标) , y(纵坐标)}


               返回值:无


               实现思路:先证明有个整数count记录该坐标周围雷的个数,接下来进行判断,如果该位置周围没有雷,则把该坐标在show中的内容改为‘空格’,反之则改为count + '0' 并返回结束该函数。


               如果为‘空格’,这下一步进行for循环遍历周围八个坐标,声明连个整数a和b,分别记录 (x+i)的值和(y+j)的值。


               接下来判断mine[a][b]中存储的是否为‘0’(非雷),如果是则进行递归调用 search_mine函数。


void search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
  if (show[x][y] != '*' )
  {
  return ;
  }
  int count = get_mine_count(mine, x, y);
  if (count == 0)
  {
  show[x][y] = ' ';
  }
  else {
  show[x][y] = count + '0';
  return;
  }
  for (int i = -1; i <= 1; i++)
  {
  for (int j = -1; j <= 1; j++)
  {
    int a = x + i;
    int b = y + j;
    if (mine[a][b] != '1')
    {
    search_mine(mine, show, a, b);
    }
  }
  }
}

find_mine函数实现:

功能:扫雷游戏的主框架,对输入的坐标进行判断,同时判断输赢(排查雷)


传参:{ mine[11][11] , show[11][11] , 行,列 }


返回值:无


实现思路:


先声明三个整数 x, y , win。x和y用来记录玩家输入的坐标,win用来记录非雷的个数


玩家需要一直输入坐标直到扫到雷或者把非雷的位置找完,所用要用while循环来实现这一功能,循环的条件为(row*col- EASY_COUNT),循环内用if语句进行判断。


循环结束判断玩家是否满足赢的条件(行*列 - 雷的个数)= win。


void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int win = 0;
  //9*9-10
  while (win<row*col- EASY_COUNT)
  {
  printf("请输入排查雷的坐标:>");
  scanf("%d%d", &x, &y);
  if (x >= 1 && x <= row && y >= 1 && y <= col)
  {
    //坐标合法
    //1.踩雷
    if (mine[x][y] == '1')
    {
    printf("很遗憾,你被炸死了\n");
    Displayboard(mine, row, col);
    break;
    }
    else  //不是雷
    {
    //计算x,y坐标周围有几个雷
    int count = get_mine_count(mine, x, y);
    show[x][y] = count + '0';
    Displayboard(show, row, col);
    win++;
    }
  }
  else
  {
    printf("输入坐标非法,请重新输入!\n");
  }
  }
  if (win == row * col - EASY_COUNT)
  {
  printf("恭喜你!排雷成功");
  Displayboard(mine, row, col);
  }
}

代码整体呈现(可以跳过以上内容,直接复制代码测试):

game.h(头文件)
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define EASY_COUNT 10
//初始化
void init_board(char arr[ROWS][COLS], int rows, int cols, char set);
//打印
void show_board(char arr[ROWS][COLS], int row, int col);
//布置雷
void set_mine(char mine[ROWS][COLS],int row,int col);
//连展
void search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y);
//排查雷
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
//获取周围雷的个数
int get_mine_count(char mine[ROWS][COLS], int x, int y);
test.c
#include"game.h"
void menu()
{
  printf("**************************\n");
  printf("********  1.paly  ********\n");
  printf("********  0.exit  ********\n");
}
void game()
{
  //扫雷实现
  //mine数组是用来存放布置好雷的信息
  char mine[ROWS][COLS] = { 0 };//'0'
  //show数组是用来存放排查出的雷的信息的
  char show[ROWS][COLS] = { 0 };//'*'
  //初始化棋盘
  init_board(mine, ROWS, COLS,'0');
  init_board(show, ROWS, COLS,'*');
  //打印棋盘
  //show_board(mine,ROW,COL);
  //布置雷
  set_mine(mine, ROW,COL);
  show_board(show, ROW, COL);
  //排查雷
  find_mine(mine, show, ROW, COL);
}
int main()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do {
  menu();
  printf("请输入:>");
  scanf("%d", &input);
  switch (input)
  {
  case 1:
    game();
    break;
  case 0:
    printf("退出\n");
    break;
  default:
    printf("输入错误,重新输入\n");
    break;
  }
  } while (input);
  return 0;
}
game.c
#include"game.h"
void init_board(char arr[ROWS][COLS], int rows, int cols,char set)
{
  int i = 0;
  int j = 0;
  for (i = 0; i < rows; i++)
  {
  for (j = 0; j < cols; j++)
  {
    arr[i][j] = set;
  }
  }
}
void show_board(char arr[ROWS][COLS], int row, int col)
{
  int i = 0;
  int j = 0;
  printf("---------扫雷---------\n");
  for (i = 0; i <= col; i++)
  {
  printf("%d ", i);
  }
  printf("\n");
  for (i = 1; i <= row; i++)
  {
  printf("%d ", i);
  for (j = 1; j <= col; j++)
  {
    printf("%c ", arr[i][j]);
  }
  printf("\n");
  }
  printf("---------扫雷---------\n");
}
//布置雷
void set_mine(char mine[ROWS][COLS], int row, int col)
{
  int count = EASY_COUNT;
  int x = 0;
  int y = 0;
  while (count)
  {
  x = rand() % row + 1;
  y = rand() % col + 1;
  if (mine[x][y] == '0')
  {
    mine[x][y] = '1';//布置雷
    count--; 
  }
  }
}
//
int get_mine_count(char mine[ROWS][COLS],int x,int y)
{
  int n = 0;
  for (int i = -1; i <= 1; i++)
  {
  for (int j = -1; j <= 1; j++)
  {
    n += mine[x + i][y + j] - '0';
  }
  }
  return n;
}
void search_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
  if (show[x][y] != '*' )
  {
  return ;
  }
  int count = get_mine_count(mine, x, y);
  if (count == 0)
  {
  show[x][y] = ' ';
  }
  else {
  show[x][y] = count + '0';
  return;
  }
  for (int i = -1; i <= 1; i++)
  {
  for (int j = -1; j <= 1; j++)
  {
    int a = x + i;
    int b = y + j;
    if (mine[a][b] != '1')
    {
    search_mine(mine, show, a, b);
    }
  }
  }
}
//排查雷
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
  int x = 0;
  int y = 0;
  int win = 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");
    show_board(mine, ROW, COL);
    break;
    }
    else {
    search_mine(mine, show, x, y);
    show_board(show, ROW, COL);
    win++;
    }
  }
  else {
    printf("坐标非法,重新输入\n");
    break;
  }
  }
  if (win == row * col - EASY_COUNT)
  {
  printf("恭喜你排雷成功\n");
  show_board(mine, ROW, COL); 
  }
}
相关文章
|
1月前
|
C语言
扫雷游戏(用C语言实现)
扫雷游戏(用C语言实现)
76 0
|
3月前
|
机器学习/深度学习 C语言
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
【8月更文挑战第5天】本篇文章用C语言采用多文件编写实现了一个基础的扫雷游戏(附源码),并讲解了关于函数递归的基础概念及其相对应的习题练习(附源码)
40 1
九/十:《初学C语言》— 扫雷游戏实现和函数递归基础
|
2月前
|
存储 安全 算法
C 语言——实现扫雷小游戏
本文介绍了使用二维数组创建棋盘并实现扫雷游戏的方法。首先,通过初始化数组创建一个9x9的棋盘,并添加行列标识以便操作。接着,利用随机数在棋盘上布置雷。最后,通过判断玩家输入的坐标来实现扫雷功能,包括显示雷的数量和处理游戏胜利或失败的情况。文中提供了完整的代码实现。
43 1
C 语言——实现扫雷小游戏
|
1月前
|
存储 算法 安全
C语言实现扫雷游戏
C语言实现扫雷游戏
|
1月前
|
C语言
初学者指南:使用C语言实现简易版扫雷游戏
初学者指南:使用C语言实现简易版扫雷游戏
33 0
|
1月前
|
C语言
C语言扫雷游戏(详解)
C语言扫雷游戏(详解)
36 0
|
1月前
|
存储 编译器 C语言
【C语言篇】数组和函数的实践:扫雷游戏(附源码)
【C语言篇】数组和函数的实践:扫雷游戏(附源码)
35 0
|
3月前
|
C语言
扫雷(C语言)
扫雷(C语言)
43 4
|
4月前
|
存储 编译器 C语言
|
5月前
|
C语言
【海贼王编程冒险 - C语言海上篇】怎样用C语言实现简单的扫雷游戏?
【海贼王编程冒险 - C语言海上篇】怎样用C语言实现简单的扫雷游戏?
31 1