来自初学者的一个简易扫雷游戏

        初学C语言一个月,与大家分享一下,我的学习成果,希望能够得到大佬的指导。

一、小游戏中运用到所学知识

1.变量的初始化,赋值,改变

2.printf和scanf的使用

3.if语句的判断,switch语句的选择

4.循环语句的使用

5.数组和函数

二、扫雷游戏实现前的想法

1.扫雷游戏的规则

游戏的目的

找出所有的雷(点开所有的非雷方块)

基本游戏规则

        在游戏棋盘上通过输入坐标的方式点开一个方格,若此方格为雷则游戏结束,若此方格不是雷则游戏继续,并显示出此方方格周围八个方格中雷的个数。

        点开所有的非雷方格后,游戏结束。  

2.扫雷游戏中棋盘的初始化,打印

        游戏的实现要有两个棋盘,一个棋盘用来呈现给玩家,另一个棋盘用来存放答案。我们使用同一个函数对这两个棋盘初始化和打印。

3.棋盘中雷区的布置

        棋盘中的雷必须是随机布置的,并且数量是一定的,我们可以先通过srand函数来生成一个种子,再通过rand函数生成两个随机数,用来表示坐标来布置雷。

4.空格的点开方式

        我们用坐标的形式来表示每一个方块的位置,玩家通过输入坐标来掀开格子,玩家输入的合法性需要进行判断,输入的坐标有问题我们需要提醒玩家重新输入。

5.点开空格后显示的数字

        若点开的方块不是雷,我们要使方块周围的雷数显示在原方块位置,我们可以通过一个函数来重复实现这一个功能。

6.游戏结束的判断

        若点开了所有的非雷空格,游戏结束,我们需要知道显示数字的函数的执行次数来判断游戏是否结束。

7.可重复实现游戏

        打印一个菜单让玩家选择游戏的进行与结束。

三、扫雷游戏的实现(附代码)

        1.游戏的菜单实现

void Menu()
{
    printf("*****************\n");
    printf("*****  MENU  ****\n");
    printf("***** 1.play ****\n");
    printf("******0.exit*****\n");
    printf("*****************\n");
}

        2.两个棋盘的创建

char board_display[ROWS][COLS] = {0};//这里的ROWS表示玩家看到棋盘的行数,COLS表示列数
char board_answer[ROWS][COLS] = {0};//这里使用一样的行数列数,方便使用一个函数处理

         3.棋盘的初始化

        我们写一个函数来实现两个棋盘的初始化,我们需要把数组,数组的行数,列数,需要初始化成的字符传给这个函数

void IntialBoard(char board[ROWS][COLS],int rows, int cols, char set)
{
    for(int i = 0; i < rows; i++)//i表示横坐标
        {
            for(int j = 0; j < cols; j++)//j表示纵坐标
            {
                board[i][j] = set;//用传来的字符赋值
            }
        }
}

        4.棋盘的打印

        我们写一个函数来实现棋盘的打印,我们需要把数组,数组的行数,列数传给这个函数。这里我们只要打印玩家需要看到的棋盘中间部分,并且为了方便玩家确定坐标,我们决定在打印的中间部分周围加上坐标,

void PrintBoard(char board[ROWS][COLS],int row ,int col)
{
    for (int i = 1; i <= col; i++)//这里的col为COL,打印第一行为横坐标
    {
        printf("%d ",i);
    }
    printf("\n");
    for(int i = 1;i <= row;i++)//这里的row为ROW
    {
        printf("%d ",i);//这里是在打印纵坐标
        int j = 0;
        for(j = 1;j <= col;j++)//这里的col为COL
        {
            printf("%c ",board[i][j]);//一个一个的打印方格
        }
        printf("\n");
    }
}

        5.雷的设置

        我们写一个函数实现雷的设置,我们需要把数组,数组的行数,列数传给这个函数。这里我们需要注意设置雷的个数一定。

void SetMine(char board[ROWS][COLS], int row, int col)
{
    int x = 0;
    int y = 0;
    int count  = EASY_COUNT;//EASY_COUNT为设置雷的数量
    while(count)//设定循环次数为雷的数量
        {
        x = rand()%row +1;//生成的0

        6.方格周围雷的数计算

        我们写一个函数来实现方格周围雷的计数,函数需要传入的参数为答案棋盘,用户输入的坐标值的x和y。

        这里我们引入一个知识,'1'-'0'得到的值是1,因为ASCII码。

int GetMineCount(char board[ROWS][COLS], int x, int y)
{
    int i = 0;
    int count = 0;//创建一个返回值
    for (i = -1; i <= 1; i++)//表示所输入坐标的周围数的行数
    {
        int j = 0;
        for (j = -1; j <= 1; j++)//表示所输入坐标的周围数的列数
        {
            count += (board[x + i][y + j] - '0');//计算返回值
        }
    }
    return count;//返回值count
}

       7.雷的查找过程以及游戏胜利的判断

        我们写一个函数来实现这个功能,需要传入的参数为两个棋盘,行数和列数。在这个函数中用户输入方块的坐标掀开方块,程序判断是否为雷,并调用GetMineCount函数的来显示周围的雷数。还要做到游戏是否胜利的判断。

void FindMine(char board_answer[ROWS][COLS], char board_display[ROWS][COLS], int row, int col)
{
    int x = 0;
    int y = 0;
    int win = 0;//设置赢的标志

    while (win < col*row - EASY_COUNT)
    {
        printf("请输入要排查的坐标:\n示例 2 4\n");
        scanf("%d %d", &x, &y);//玩家输入坐标
        if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标是否合理
        {
            if (board_answer[x][y] == '1')//输入的坐标是雷
            {
                printf("很遗憾,你踩雷了,游戏结束\n");
                PrintBoard(board_answer, ROW, COL);//打印答案
                break;
            }
            else  //不是雷
            {
                int count = GetMineCount(board_answer, x, y);
                board_display[x][y] = count + '0';//是int类型的count变为char类型再赋值
                PrintBoard(board_display, ROW, COL);//每次都打印更新后的棋盘
                win++;//标志自增
            }
        }
        else
        {
            printf("输入的坐标有误x(1~9),y(1~9),重新输入\n");
        }
    }
    
    if (win == row * col - EASY_COUNT)//判断赢得条件
    {
        printf("恭喜你,排雷成功\n");
        PrintBoard(board_answer, ROW, COL);//打印答案
    }
}

        8.头文件问题

        在上述代码中我们使用了printf()、scanf()、srand()、rand(),需要包含一些头文件,我们还定义了许多的变量,所以我们决定创建一个头文件。命名为game.h

#include
#include
#include
#ifndef game_h
#define game_h
#define ROW 9
#define COL 9

#define ROWS ROW + 2
#define COLS COL + 2
#define EASY_COUNT 10

#endif /* game_h */

void InitBoard(char board[ROWS][COLS],int rows,int cols,char set);
void PrintBoard(char board[ROWS][COLS],int row,int col);
void SetMine(char board[ROWS][COLS],int row,int col);
void FindMine(char board[ROWS][COLS], char show[ROWS][COLS], int row, int col);

        9.整合代码

        我们创建一个函数game()来整合一下代码,提高代码的可读性。

void game()
{
    char board_answer[ROWS][COLS] = {0};//存放雷的信息
    char board_display[ROWS][COLS] = {0};//存放排查出的雷的信息
    //初始化棋盘
    InitBoard(board_answer, ROWS, COLS, '0');
    InitBoard(board_display, ROWS, COLS, '*');
    //布置雷
    SetMine(board_answer, ROW, COL);
    //打印棋盘
    PrintBoard(board_display, ROW, COL);
    //排查雷
    FindMine(board_answer, board_display, ROW, COL);
}

        我们创建一个C语言文件来提高代码可读性,命名为game.c

#include "game.h"

void IntialBoard(char board[ROWS][COLS],int rows, int cols, char set)
{
    for(int i = 0; i < rows; i++)//i表示横坐标
        {
            for(int j = 0; j < cols; j++)//j表示纵坐标
            {
                board[i][j] = set;//用传来的字符赋值
            }
        }
}

void PrintBoard(char board[ROWS][COLS],int row ,int col)
{
    for (int i = 1; i <= col; i++)//这里的col为COL,打印第一行为横坐标
    {
        printf("%d ",i);
    }
    printf("\n");
    for(int i = 1;i <= row;i++)//这里的row为ROW
    {
        printf("%d ",i);//这里是在打印纵坐标
        int j = 0;
        for(j = 1;j <= col;j++)//这里的col为COL
        {
            printf("%c ",board[i][j]);//一个一个的打印方格
        }
        printf("\n");
    }
}


void SetMine(char board[ROWS][COLS], int row, int col)
{
    int x = 0;
    int y = 0;
    int count  = EASY_COUNT;//EASY_COUNT为设置雷的数量
    while(count)//设定循环次数为雷的数量
        {
        x = rand()%row +1;//生成的0= 1 && x <= row && y >= 1 && y <= col)//判断坐标是否合理
        {
            if (board_answer[x][y] == '1')//输入的坐标是雷
            {
                printf("很遗憾,你踩雷了,游戏结束\n");
                PrintBoard(board_answer, ROW, COL);//打印答案
                break;
            }
            else  //不是雷
            {
                int count = GetMineCount(board_answer, x, y);
                board_display[x][y] = count + '0';//是int类型的count变为char类型再赋值
                PrintBoard(board_display, ROW, COL);//每次都打印更新后的棋盘
                win++;//标志自增
            }
        }
        else
        {
            printf("输入的坐标有误x(1~9),y(1~9),重新输入\n");
        }
    }
    
    if (win == row * col - EASY_COUNT)//判断赢得条件
    {
        printf("恭喜你,排雷成功\n");
        PrintBoard(board_answer, ROW, COL);//打印答案
    }
}

         我们创建一个C语言文件作为main文件命名为main.c

#include "game.h"
void Menu()
{
    printf("*****************\n");
    printf("*****  MENU  ****\n");
    printf("***** 1.play ****\n");
    printf("******0.exit*****\n");
    printf("*****************\n");
}

void game()
{
    char board_answer[ROWS][COLS] = {0};//存放雷的信息
    char board_display[ROWS][COLS] = {0};//存放排查出的雷的信息
    //初始化棋盘
    InitBoard(board_answer, ROWS, COLS, '0');
    InitBoard(board_display, ROWS, COLS, '*');
    //布置雷
    SetMine(board_answer, ROW, COL);
    //打印棋盘
    PrintBoard(board_display, ROW, COL);
    //排查雷
    FindMine(board_answer, board_display, 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;
}

四、反思与总结

        以上的代码仍存在许多的问题。如无法实现游戏的重复运行,运行一次只能进行一次游戏。如排查雷的过程中,如果玩家输入多次相同的坐标会导致bug的出现。这些bug我会在不断的学习中进行更改。望大家能够不嫌弃。

你可能感兴趣的:(游戏,程序人生)