C语言实现扫雷游戏(含注释详解)

 更新时间:2021年09月10日 15:28:02   作者:3 ERROR(s)  
这篇文章主要为大家详细介绍了C语言实现扫雷游戏,含注释,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了C语言实现扫雷游戏的具体代码,供大家参考,具体内容如下

前言

一、游戏规则介绍

扫雷是一个十分经典的游戏,一张棋盘中有很多个不确定是雷还是安全区域的格子,当点击之后若没有雷则会在该区域显示周围八个格子雷的数目,若有雷则游戏结束。今天我就跟大家分享一下如何用c语言实现初阶版扫雷。

二、基本思路流程介绍

1.创建一个用户交互菜单
2.创建一个Show_Mines棋盘用来埋雷并初始化
3.创建一个Show_Table 棋盘用来和用户交互并初始化
4.玩家选择想要扫描的坐标
5.判定游戏是否结束
6.若没有踩雷则在刚扫描的区域上显示周围八个区域的地雷数目并继续游戏
7.继续扫雷
8.判定游戏是否结束

9.若全部扫描完非雷区域则游戏结束

效果展示

三、代码实现

1.用户交互菜单(Menu函数)

Menu(){
 printf("########################\n");
 printf("# 1. Play       0.Exit #\n");
 printf("########################\n");
}

2. Game函数

void Game()
{
 srand((unsigned long)time(NULL)); //生成随机数种子

 char show_board[ROW][COL];   
 char mines_board[ROW][COL];

 memset(show_board, WHAT, sizeof(show_board));//生成并且初始化用户显示棋盘
 memset(mines_board, '0', sizeof(mines_board));//生成并且初始化扫雷棋盘

 SetMines(mines_board, ROW, COL);//放雷

 int count = (ROW - 2)*(COL - 2) - NUM;    //若扫完这些次 不触雷则胜利

 while (count){
  system("cls");
  ShowBoard(show_board, ROW, COL);
  printf("请选择你要扫描的区域坐标 ");
  int x = 0;
  int y = 0;
  scanf("%d %d", &x, &y);
  if (x < 1 || x > ROW-2 || y < 1 || y > COL-2){ //非法性输入判断
   printf("输入错误!\n");
   continue;
  }
  if (show_board[x][y] != WHAT){           
   printf("此处已经被扫过了,请从新输出\n");
   continue;
  }
  if (mines_board[x][y] == '1'){
   system("cls");
   ShowBoard(mines_board, ROW, COL);
   printf("踩雷了!游戏结束!\n");
   break;
  }
  
  show_board[x][y] = CountMines(mines_board, x, y);
  count--;
 }

}

1.memset函数直接定义show_board函数并且初始化二维数组为全WHAT宏定义的*。
2.先向用户展示用户展示棋盘,用户输入一个坐标进行非法性判断。
3.把用户输入的坐标拿给放置雷的棋盘中,若该区域有雷则游戏结束,反之则继续
4.游戏胜利条件为扫描完所有非雷区域

3.放雷函数(SetMines函数)

void SetMines(char board[][COL], int row, int col){ //放雷函数
 int count = NUM;
 while (count){
  int x = rand() % (row - 2) + 1;
  int y = rand() % (col - 2) + 1;
  if (board[x][y] == '0'){
   board[x][y] = '1';
   count--;
  }
 }
}

使用随机数种子生成1到 棋盘大小长宽-2的随机数,这些随机数组成的坐标放雷,循环次数就是雷的数目。因为随机数可能生成一样的,所以要进行一次非法性判断,当棋盘这个位置没有雷的情况下才能往里面放雷。

4.扫雷展示面板(ShowBoard函数和ShowLine函数)

void ShowBoard(char board[][COL], int row, int col){//扫雷展示面板
 printf("     ");
 for (int i = 1; i <= (col - 2); i++){  //打印表头数字
  printf("%d   ", i);
 }
 printf("\n");
 ShowLine(col);//显示行线
 for (int i = 1; i <= (row - 2); i++){
  printf("%-3d|", i);
  for (int j = 1; j <= (col - 2); j++){
   printf(" %c |", board[i][j]); 
  }
  printf("\n");
  ShowLine(col);
 }
}


void ShowLine(int col){  //显示横着的虚线,作为行间隔

 for (int i = 0; i <= (col - 2); i++){
  printf("----");
 }
 printf("\n");
}

5.统计周围雷的个数(CountMines函数)

CountMines(char board[][COL], int x, int y){ //统计周围雷的个数
 return board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + \
  board[x][y + 1] + board[x + 1][y + 1] + board[x + 1][y] + \
  board[x + 1][y - 1] + board[x][y - 1] - 7 * '0';//本来减八个零,但是整形转字符加一个‘0'
}

由于数组中存放的是字符'0',周围是8个数字,所以-8*'0'才能返回雷数的int值,为了把数字也能打印出来,所以+‘0',否则打印的是数字作为的ASCLL码的值,最终的结果为-7*‘0'.

6.mine函数

int main()
{
 int quit = 0;
 int select = 0;
 while (!quit){
  Menu();
  printf("请输入 ");
  scanf("%d", &select);
  switch (select){
  case 1:
   Game();
   break;
  case 0:
   quit = 1;
   break;
  default:
   printf("输入错误,请重试!\n");
   break;
  }
 }

 printf("byebye!\n");

 system("pause");
 return 0;
}

四、总代码

#ifndef __Test_H__
#define __Test_H__

#include<stdio.h>
#include<Windows.h>
#include <stdlib.h>
#include <time.h>
#define WHAT '*'
#define NUM  20
#define COL  10
#define ROW  10
void Game();
#pragma warning(disable:4996)
#endif       //以上都是头文件

int main()
{
 int quit = 0;
 int select = 0;
 while (!quit){
  Menu();
  printf("请输入 ");
  scanf("%d", &select);
  switch (select){
  case 1:
   Game();
   break;
  case 0:
   quit = 1;
   break;
  default:
   printf("输入错误,请重试!\n");
   break;
  }
 }

 printf("byebye!\n");

 system("pause");
 return 0;
}


void Game()
{
 srand((unsigned long)time(NULL)); //生成随机数种子

 char show_board[ROW][COL];   
 char mines_board[ROW][COL];

 memset(show_board, WHAT, sizeof(show_board));
 memset(mines_board, '0', sizeof(mines_board));

 SetMines(mines_board, ROW, COL);

 int count = (ROW - 2)*(COL - 2) - NUM;    //若扫完这些次 不触雷则胜利

 while (count){
  system("cls");
  ShowBoard(show_board, ROW, COL);
  printf("请选择你要扫描的区域坐标 ");
  int x = 0;
  int y = 0;
  scanf("%d %d", &x, &y);
  if (x < 1 || x > ROW-2 || y < 1 || y > COL-2){ //非法性输入判断
   printf("输入错误!\n");
   continue;
  }
  if (show_board[x][y] != WHAT){           
   printf("此处已经被扫过了,请从新输出\n");
   continue;
  }
  if (mines_board[x][y] == '1'){
   system("cls");
   ShowBoard(mines_board, ROW, COL);
   printf("踩雷了!游戏结束!\n");
   break;
  }
  
  show_board[x][y] = CountMines(mines_board, x, y);
  count--;
 }
}


CountMines(char board[][COL], int x, int y){ //统计周围雷的个数
 return board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] + \
  board[x][y + 1] + board[x + 1][y + 1] + board[x + 1][y] + \
  board[x + 1][y - 1] + board[x][y - 1] - 7 * '0';//本来减八个零,但是整形转字符加一个‘0'
}

void ShowBoard(char board[][COL], int row, int col){//扫雷展示面板
 printf("     ");
 for (int i = 1; i <= (col - 2); i++){
  printf("%d   ", i);
 }
 printf("\n");
 ShowLine(col);//显示行线
 for (int i = 1; i <= (row - 2); i++){
  printf("%-3d|", i);
  for (int j = 1; j <= (col - 2); j++){
   printf(" %c |", board[i][j]); 
  }
  printf("\n");
  ShowLine(col);
 }
}

oid SetMines(char board[][COL], int row, int col){ //放雷函数
 int count = NUM;
 while (count){
  int x = rand() % (row - 2) + 1;
  int y = rand() % (col - 2) + 1;
  if (board[x][y] == '0'){
   board[x][y] = '1';
   count--;
  }
 }
}
void ShowLine(int col){

 for (int i = 0; i <= (col - 2); i++){
  printf("----");
 }
 printf("\n");
}

Menu(){   //用户交互函数
 printf("########################\n");
 printf("# 1. Play       0.Exit #\n");
 printf("########################\n");
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • C++实现LeetCode(73.矩阵赋零)

    C++实现LeetCode(73.矩阵赋零)

    这篇文章主要介绍了C++实现LeetCode(73.矩阵赋零),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C/C++实现对STORM运行信息查看及控制的方法

    C/C++实现对STORM运行信息查看及控制的方法

    这篇文章主要介绍了C/C++实现对STORM运行信息查看及控制的方法,需要的朋友可以参考下
    2014-07-07
  • C++针对bmp格式解析实例

    C++针对bmp格式解析实例

    这篇文章主要介绍了C++针对bmp格式解析实例,设计CWnd框架的使用及位图的操作,需要的朋友可以参考下
    2014-10-10
  • 一篇文章带你了解论C语言中算法的重要性

    一篇文章带你了解论C语言中算法的重要性

    最近一直在学数据结构与算法,深深的感受到我们学习语言,永远都只是一项工具,方法才是其中最重要的部分。这篇文章我将会通过几个例子来说明算法,也就是写程序的思路在程序中的重要意义
    2021-08-08
  • C++泛型模板约束深入讲解

    C++泛型模板约束深入讲解

    C/C++ 作为 C# 语言的前置版本,ECMA工业化编程语言,自然是存在 “泛型模板约束” 的功能的,只是本文不以 C/C++ 20 新语法搞出来的 “requires” 关键字来实现,它很难用
    2022-09-09
  • C++基于Boost.Asio实现端口映射器的过程详解

    C++基于Boost.Asio实现端口映射器的过程详解

    Boost.Asio 是一个功能强大的 C++ 库,用于异步编程和网络编程,它提供了跨平台的异步 I/O 操作,在这篇文章中,我们将深入分析一个使用 Boost.Asio 实现的简单端口映射服务器,文中有详细的代码讲解,需要的朋友可以参考下
    2023-11-11
  • 讲解C++编程中Address-of运算符&的作用及用法

    讲解C++编程中Address-of运算符&的作用及用法

    这篇文章主要介绍了C++编程中Address-of运算符&的作用及用法,是C++入门学习中的基础知识,需要的朋友可以参考下
    2016-01-01
  • C++实现简单的图书管理系统

    C++实现简单的图书管理系统

    本文给大家分享的是使用C++实现简单的图书管理系统的代码,本系统采用了面向对象的程序设计方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2015-08-08
  • Visual Studio Code上添加小程序自动补全插件的操作方法

    Visual Studio Code上添加小程序自动补全插件的操作方法

    这篇文章主要介绍了Visual Studio Code上添加小程序自动补全插件的操作方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • 浅析C++中的函数重载

    浅析C++中的函数重载

    这篇文章主要介绍了浅析C++中的函数重载,在C++中,可以为两个或两个以上的函数提供相同的函数名称,只要参数类型不同,或者参数类型相同而参数个数不同,又或者参数类型参数个数相同,参数次序不同,称为函数重载,需要的朋友可以参考下
    2023-08-08

最新评论