热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C语言实现扫雷小游戏(扩展版)

这篇文章主要为大家详细介绍了C语言实现扩展版的扫雷小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

实现的拓展功能如下:

1.设置游戏难度等级
2.保证玩家在第一把踩雷后不被炸死
3.若排雷的地方无雷,自动扩展到有雷的周围,并给出雷数
4.标记(相当于扫雷游戏中的插旗子)
5.取消标记

分析:

1.用二维字符数组mine[ROWS][COLS]来存储雷,现在我们用字符1来表示有雷,字符0表示无雷。用二维字符数组show[ROWS][COLS]将所有的元素初始化为*,并打印作为展现给玩家的。同时用show数组来表示对应的mine数组中周围雷即字符0的个数。
对于边缘的格子无法计算雷的个数,因此需再增加2行2列,防止数组越界。
2.游戏难度等级的设置即就是雷的个数和棋盘大小不同,即就是Putmine中传的COUNT(雷数)不同,棋盘大小不同也就是在初始化、埋雷、扫雷、打印棋盘等函数中传的行、列数不同,由于是控制台程序,没有将一般模式和困难模式的棋盘打印的过大(因为会丑,也容易眼花),正常情况下扫雷的中级模式是40个雷,16*16格,高级模式是99个雷,16*30格.
3.为了保证玩家体验,保证玩家在第一把踩雷后不被炸死,此时只需要判断玩家第一次排查的坐标是否等于雷的坐标,如果是,将雷悄悄移走(重新生成随机数)
4.若排雷的地方无雷,自动扩展到有雷的周围,并给出雷数,此时需要用到递归,直至递归到周围有雷停止,并计算雷数,显示在棋盘上。
5.标记与取消标记这个是很容易实现的,将标记位置改为P(也可以为其他),取消标记改回*即可。

实现效果:

详细代码如下:

test.c

/*
date:2018/12/27
author:Better Me1
program:Mine Clearance
compiler:Visual Studio 2013
拓展功能:
1.设置游戏难度等级
2.保证玩家在第一把踩雷后不被炸死
3.若排雷的地方无雷,自动扩展到有雷的周围,并给出雷数
4.标记(相当于扫雷游戏中的插旗子)
5.取消标记
*/
 
/*测试部分*/
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
#include 
#include 
 
void menu(){
    printf("************  扫雷小游戏  ************\n");
    printf("******  1.进入游戏  2.退出游戏  ******\n");
    printf("**************************************\n");
}
void menu2(){
    printf("********  请选择要挑战的模式  ********\n");
    printf("********  1.简单模式(10个雷)********\n");
    printf("********  2.一般模式(15个雷)********\n");
    printf("********  3.困难模式(20个雷)********\n");
}
void game(int COUNT ){
    if (COUNT == 10){
        char mine[ROWS][COLS] = { 0 };
        char show[ROWS][COLS] = { 0 };//显示雷,给玩家看
        InitBoard(mine, ROWS, COLS, '0');
        InitBoard(show, ROWS, COLS, '*');//初始化棋盘
        Putmine(mine, ROW-6, COL-6, COUNT);//埋雷
        //DisplayBoard(mine, ROW - 6, COL - 6);
        DisplayBoard(show, ROW-6, COL-6);//打印棋盘
        Findmine(mine, show, ROW-6, COL-6, COUNT);//扫雷
    }
    else if (COUNT == 15){
        char mine[ROWS][COLS] = { 0 };
        char show[ROWS][COLS] = { 0 };//显示雷,给玩家看
        InitBoard(mine, ROWS, COLS, '0');
        InitBoard(show, ROWS, COLS, '*');//初始化棋盘
        Putmine(mine, ROW - 2, COL - 2, COUNT);//埋雷
        //DisplayBoard(mine, ROW - 2, COL - 2);
        DisplayBoard(show, ROW - 2, COL - 2);//打印棋盘
        Findmine(mine, show, ROW - 2, COL - 2, COUNT);//扫雷
    }
    else{
        char mine[ROWS][COLS] = { 0 };
        char show[ROWS][COLS] = { 0 };//显示雷,给玩家看
        InitBoard(mine, ROWS, COLS, '0');
        InitBoard(show, ROWS, COLS, '*');//初始化棋盘
        Putmine(mine, ROW, COL, COUNT);//埋雷
        //DisplayBoard(mine, ROW, COL);
        DisplayBoard(show, ROW, COL);//打印棋盘
        Findmine(mine, show, ROW , COL, COUNT);//扫雷
    }
}
void test(){
    srand((unsigned int)time(0));//随机种子
    int input = 0;
    int input2 = 0;
    int COUNT = 0;
    do{
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        system("cls");
        switch (input){
        case 1:
            while (1){
                menu2();
                printf("请选择:>");
                scanf("%d", &input2);
                switch (input2){
                case 1:
                    COUNT = EASY_COUNT;
                    break;
                case 2:
                    COUNT = USUAL_COUNT;
                    break;
                case 3:
                    COUNT = HARD_COUNT;
                    break;
                default:
                    printf("输入有误,请重新选择!\n");
                    break;
                }
                if (input2 >= 1 && input2 <= 3){
                    break;
                }
            }
            system("cls");
            game(COUNT);
            break;
        case 2:
            printf("退出游戏!\n");
            break;
        default:
            printf("输入有误,请重新选择!\n");
            break;
        }
    } while ((input - 2));
}
void main(){
    test();
    system("pause");
}

game.h

#ifndef _GAME_H_
#define _GAME_H
 
#define EASY_COUNT 10 //简单级,10个雷
#define USUAL_COUNT 15 //普通级,15个雷
#define HARD_COUNT 20 //单级,20个雷
 
 
#define ROW 15//行
#define COL 15 //列
 
#define ROWS ROW+2
#define COLS COL+2
 
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set);//初始化棋盘
void DisplayBoard(char board[ROWS][COLS], int row, int col);//打印棋盘
void Putmine(char board[ROWS][COLS], int row, int col, int count);//埋雷
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,int count);//扫雷
 
#endif

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
#include 
#include 
#include 
#include 
 
void InitBoard(char board[ROWS][COLS], int rows, int cols, char set){
    memset(board, set, rows*cols*sizeof(board[0][0]));
}
void DisplayBoard(char board[ROWS][COLS], int row, int col){
    int i, j = 0;
    if (row == ROW - 6){
        printf("------------------------------\n");
    }
    if (row == ROW - 2){
        printf("-----------------------------------------\n");
    }
    if (row == ROW){
        printf("----------------------------------------------\n");
    }
    for (i = 0; i <= row; i++){
        for (j = 0; j <= col; j++){
            if (i == 0 || j == 0){
                if (j == 0){
                    if (i <10){
                        printf("%d  ", i);
                    }
                    else{
                        printf("%d ", i);
                    }
                }
                else{
                    if (j <10){
                        printf("%d  ", j);
                    }
                    else{
                        printf("%d ", j);
                    }
                }
            }
            else{
                printf("%c  ", board[i][j]);
            }
        }
        printf("\n");
    }
    if (row == ROW - 6){
        printf("------------------------------\n");
    }
    if (row == ROW - 2){
        printf("-----------------------------------------\n");
    }
    if (row == ROW){
        printf("----------------------------------------------\n");
    }
}
void Putmine(char board[ROWS][COLS], int row, int col, int count){
    int c = 0;//埋好的雷的个数
    int i = 0;
    int j = 0;
    do{
        i = rand() % row + 1;
        j = rand() % col + 1;
        if (board[i][j] =='0'){//保证雷的个数为 count个
            board[i][j] = '1';
            c++;
        }    
    } while (count-c);
}
/*统计雷的个数*/
int MineCount(char mine[ROWS][COLS], int i, int j){
    return (mine[i - 1][j] +
        mine[i - 1][j + 1] +
        mine[i][j + 1] +
        mine[i + 1][j + 1] +
        mine[i + 1][j] +
        mine[i + 1][j - 1] +
        mine[i][j - 1] +
        mine[i - 1][j - 1]) - 8 * '0';
}
void ExpansionMine(char mine[ROWS][COLS], char show[ROWS][COLS], int i, int j, int row, int col){
    if (MineCount(mine, i, j) == 0){
        show[i][j] = ' ';
        //再次遍历周围的雷
        if (i - 1 > 0 && show[i - 1][j] == '*'){
        //    printf("1\n");
            ExpansionMine(mine, show, i - 1, j, row, col);//递归
        }
        if (i - 1 > 0 && j + 1 <= col && show[i - 1][j + 1] == '*'){
            ExpansionMine(mine, show, i - 1, j + 1, row, col);
        }
        if (j + 1 <= col && show[i][j + 1] == '*'){
            ExpansionMine(mine, show, i, j + 1, row, col);
        }
        if (i + 1 <= row && j + 1 <= col && show[i + 1][j + 1] == '*'){
            ExpansionMine(mine, show, i + 1, j + 1, row, col);
        }
        if (i + 1 <= row && show[i + 1][j] == '*'){
            ExpansionMine(mine, show, i + 1, j, row, col);
        }
        if (i + 1 <= row && j - 1 >0 && show[i + 1][j - 1] == '*'){
            ExpansionMine(mine, show, i + 1, j - 1, row, col);
        }
        if (j - 1 > 0 && show[i][j - 1] == '*'){
            ExpansionMine(mine, show, i, j - 1, row, col);
        }
        if (i - 1 > 0 && j - 1 > 0 && show[i - 1][j + 1] == '*'){
            ExpansionMine(mine, show, i - 1, j + 1, row, col);
        }
    }
    else{//周边有雷
        show[i][j] = MineCount(mine, i, j) + '0';
    }
}
void menu3(){
    printf("********   1.标记    2.排查   ********\n");
    printf("请选择:>");
}
void Findmine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int count){
    int i, j;//行列坐标
    int playcount = 0;//玩家排雷的次数
    int remine = 0;//已标记的或没有排查的坐标;
    while (remine!=count){
        //printf("%d", remine);
        int input = 0;
        printf("***** 1.标记  2.取消标记  3.排查 *****\n");
        printf("请选择:>");
        scanf("%d", &input);
        if (input == 1){
            printf("请输入要标记的坐标(如:a b):>");
            scanf("%d %d", &i, &j);
            if (i >= 1 && i <= row && j >= 1 && j <= col){
                if (show[i][j] == '*'){
                    show[i][j] = 'P';
                    system("cls");
                    DisplayBoard(show, row, col);
                }
                else if (show[i][j] == 'P'){
                    printf("此坐标已被标记过,请重新输入!\n");
                }
                else{
                    printf("此坐标已被排查过,请重新输入!\n");
                }
            }
 
            else{
                printf("坐标输入有误,请重新输入!\n");
            }
        }
        else if (input == 2){
            printf("请输入要取消标记的坐标(如:a b):>");
            scanf("%d %d", &i, &j);
            if (i >= 1 && i <= row && j >= 1 && j <= col){
                if (show[i][j] == 'P'){
                    show[i][j] = '*';
                    system("cls");
                    DisplayBoard(show, row, col);
                }
                else if (show[i][j] == '*'){
                    printf("此坐标还没有被标记过,请重新输入!\n");
                }
                else{
                    printf("此坐标已被排查过,请重新输入!\n");
                }
            }
 
            else{
                printf("坐标输入有误,请重新输入!\n");
            }
        }
        else if (input == 3){
            //printf("%d", remine);
            printf("请输入要排查的坐标(如:a b):>");
            scanf("%d%d", &i, &j);
            if (i >= 1 && i <= row && j >= 1 && j <= col){
                if (show[i][j] == '*'){
                    if (mine[i][j] == '1'){
                        if (playcount == 0){//此时说明玩家首次排雷且踩到雷了
                            mine[i][j] = '0';
                            Putmine(mine, row, col, 1);//重新放雷,保证玩家在第一把不踩雷
                            playcount = 1;
                            ExpansionMine(mine, show, i, j, row, col);//扩展周边的雷
                            DisplayBoard(show, row, col);
                        }
                        else{
                            printf("很遗憾,你被炸死了!\n");
                            printf("雷阵布局如下:\n");
                            DisplayBoard(mine, row, col);
                            break;
                        }
                    }
                    else{
                        ExpansionMine(mine, show, i, j, row, col);//扩展周边的雷
                        system("cls");
                        //DisplayBoard(mine, row, col);
                        DisplayBoard(show, row, col);
                        playcount = 1;
                    }
                }
                else if (show[i][j] == 'P'){
                    printf("此坐标已被标记过,请重新输入!\n");
                }
                else{
                    printf("此坐标已被排查过,请重新输入!\n");
                }
            }
            else{
                printf("坐标输入有误,请重新输入!\n");
            }
        }
        else{
            printf("输入有误,请重新输入!\n");
        }
        remine = 0;//重新统计;
        for (int m = 1; m <= row; m++){
            for (int n = 1; n <= col; n++){
                if ((show[m][n] == '*' )||( show[m][n] == 'P')){
                    remine++;
                }
            }
        }
    }
    //printf("%d", remine);
    if (remine == count){
        printf("恭喜您,排雷成功!\n");
        printf("雷阵布局如下:\n");
        DisplayBoard(mine, row, col);
    }
 
}

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


推荐阅读
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了关系型数据库和NoSQL数据库的概念和特点,列举了主流的关系型数据库和NoSQL数据库,同时描述了它们在新闻、电商抢购信息和微博热点信息等场景中的应用。此外,还提供了MySQL配置文件的相关内容。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • MySQL多表数据库操作方法及子查询详解
    本文详细介绍了MySQL数据库的多表操作方法,包括增删改和单表查询,同时还解释了子查询的概念和用法。文章通过示例和步骤说明了如何进行数据的插入、删除和更新操作,以及如何执行单表查询和使用聚合函数进行统计。对于需要对MySQL数据库进行操作的读者来说,本文是一个非常实用的参考资料。 ... [详细]
  • 本文介绍了Foundation框架中一些常用的结构体和类,包括表示范围作用的NSRange结构体的创建方式,处理几何图形的数据类型NSPoint和NSSize,以及由点和大小复合而成的矩形数据类型NSRect。同时还介绍了创建这些数据类型的方法,以及字符串类NSString的使用方法。 ... [详细]
author-avatar
硕之缘2010
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有