C语言小游戏——扫雷

相信大家都玩过windows下的扫雷游戏,对其的规则也比较了解,

这里我们就不对规则做过多赘述了。
首先菜单和主函数的编写和上一篇三子棋中的内容一致,

这里我们直接给出代码:

void menu()
{
    printf("*********  Welcom  to  Mines  *********\n");
    printf("***************************************\n");
    printf("*      1.play             0.exit      *\n");
    printf("***************************************\n");
}

int main()
{
    int choice;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
        printf("Input your choice:");
        scanf("%d", &choice);
        switch (choice)
        {
        case 1:
            game();
            break;
        case 0:
            break;
        default:
            printf(" Input error!Please try again.\n");
            break;
        }
    } while (choice);
    return 0;
}

一样,我们先定义一个game()函数,而后慢慢填充其中的内容。

和三子棋不同的是,这里需要创建两个数组,其中一个是雷区数组,另一个是需要输出在屏幕上的显示数组。

为了便于区分两个数组,雷区数组我用mines表示,显示数组我用show_area来表示。

但这一步我们先跳过,先来完成初始化数组的功能函数。

这次我选择使用memset()函数来进行初始化操作。

在init函数中,我们需要将雷区数组全部赋成“0”,“0”表示没雷。

将显示数组全部初始化为“.”,“.”表示未探索区域。

由于是扫雷程序,那么在雷区中一定要有雷才行,所以我们用上一篇提到的rand()来随机生成坐标指向雷区数组的元素,

并将其赋值为“1”,“1”表示有雷。

代码如下:

void init_mines(char mine[ROWS][COLS],char show[ROWS][COLS],int rows,int cols,int row,int col)
{
    int i, x, y;
    memset(mine, '0', rows*cols*sizeof(char));
    memset(show, '.', rows*cols*sizeof(char));
    for (i = 0; i < MINES; i++)
    {
        while (1)
        {
            x = rand() % row + 1;
            y = rand() % col + 1;
            if (mine[x][y] == '0')
            {
                mine[x][y] = '1';
                break;
            }
        }
    }
}

当用户完成每次扫雷操作后,一定要打印出当前的状况,这时就需要一个显示功能函数display()。

代码如下:
void display(char mine[ROWS][COLS],int row,int col)
{
int i, j;
for (i = 1; i <= row; i++)
{
printf("%4d", i);
}
printf("\n");
for (i = 1; i <= col; i++)
{
printf("%2d", i);
for (j = 1; j <= col; j++)
{
printf(" %c “, mine[i][j]);
}
printf(”\n");
}
}
为了用户体验,我们在打印出的雷区上方和左方加上了行数、列数,方便用户观察坐标。
这时我们就需要利用扫雷规则来编写完成checkwin()函数,以判断是否胜利。

这里我们首先判断其是不是雷,

如果不是雷,我们再编写一个checkmine()函数,用来遍历其周围雷的个数,并将个数填入显示数组中对应的元素中。

如果是雷,则返回一个值“”,“”表示被炸死。

最后判断是否胜利。

我们先定义一个count变量,用来记录未探索区域的个数,

如果未探索区域的个数和初始化时随机生成的雷的个数相等,则表示雷排完了,

返回一个值“w”,“w”表示胜利。

代码如下:

int checkwin(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col,int x,int y)
{
    int count = 0;
    if (mine[x][y] == '0')
        show[x][y] = checkmine(mine, show, x, y);
    else return '*';
    for (x = 1; x <= row; x++)
    {
        for (y = 1; y <= col; y++)
        {
            if (show[x][y] == '.')
                count++;
        }
    }
    if (count == MINES)
        return 'w';
    return 0;
}

接着我们给出上面提到的,用来遍历该坐标周围雷数的checkmine()函数。

static char checkmine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
    int m, n;
    char mine_count = '0';
    for (m = x - 1; m <= x + 1 ; m++)
    {
        for (n = y - 1; n <= y + 1; n++)
        {
            if (mine[m][n] == '1')
                mine_count++;
        }
    }
    return mine_count;
}

由于该代码只在该源文件中使用,所以我在其类型前加上了static。

这时我们就完成了扫雷各个功能函数的编写,接着根据我们平时玩游戏的思路将上述函数引入game()中即可完成简单扫雷的编写。

game()函数的代码如下:

void game()
{
    char mines[ROWS][COLS], show_area[ROWS][COLS], ret;
    int x, y;
    init_mines(mines, show_area, ROWS, COLS, ROW, COL);
    display(show_area, ROW, COL);
    while (1)
    {
        printf("Input x and y(like x y):");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
        {
            ret = checkwin(mines, show_area, ROW, COL, x, y);
            if (ret == 'w')
            {
                display(mines, ROW, COL);
                printf("Congratulations!You win!\n");
                break;
            }
            else if (ret == '*')
            {
                display(mines, ROW, COL);
                printf("You lose!Good luck next time!\n");
                break;
            }
            else
            {
                display(show_area, ROW, COL);
                printf("\n");
            }
        }
        else printf("Input error!Please try again.\n");
    }
}

和三子棋一样,我这里定义数组时也运用了宏定义。
最后放上我自己写出的代码:

代码分为三部分,

第一部分是头文件:

#ifndef __MINES_H__
#define __MINES_H__

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>

#define COLS 12
#define ROWS 12
#define COL 10
#define ROW 10
#define MINES 10

void init_mines(char mine[ROWS][COLS], char show[ROWS][COLS], int rows, int cols, int row, int col);
void display(char mine[ROWS][COLS], int row, int col);
int checkwin(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col, int x, int y);

#endif//__MINES_H__

第二部分是源文件的函数部分:

#include"mines.h"
void init_mines(char mine[ROWS][COLS],char show[ROWS][COLS],int rows,int cols,int row,int col)
{
    int i, x, y;
    memset(mine, '0', rows*cols*sizeof(char));
    memset(show, '.', rows*cols*sizeof(char));
    for (i = 0; i < MINES; i++)
    {
        while (1)
        {
            x = rand() % row + 1;
            y = rand() % col + 1;
            if (mine[x][y] == '0')
            {
                mine[x][y] = '1';
                break;
            }
        }
    }
}

void display(char mine[ROWS][COLS],int row,int col)
{
    int i, j;
    for (i = 1; i <= row; i++)
    {
        printf("%4d", i);
    }
    printf("\n");
    for (i = 1; i <= col; i++)
    {
        printf("%2d", i);
        for (j = 1; j <= col; j++)
        {
            printf(" %c  ", mine[i][j]);
        }
        printf("\n");
    }
}

static char checkmine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y)
{
    int m, n;
    char mine_count = '0';
    for (m = x - 1; m <= x + 1 ; m++)
    {
        for (n = y - 1; n <= y + 1; n++)
        {
            if (mine[m][n] == '1')
                mine_count++;
        }
    }
    return mine_count;
}

int checkwin(char mine[ROWS][COLS],char show[ROWS][COLS],int row,int col,int x,int y)
{
    int count = 0;
    if (mine[x][y] == '0')
        show[x][y] = checkmine(mine, show, x, y);
    else return '*';
    for (x = 1; x <= row; x++)
    {
        for (y = 1; y <= col; y++)
        {
            if (show[x][y] == '.')
                count++;
        }
    }
    if (count == MINES)
        return 'w';
    return 0;
}

这部分内容,我并没有完成关键的2点。 1、为了用户体验,在第一次用户执行扫雷操作时,不会被炸死。

2、当用户输入的坐标周围没雷时,可以实现无雷区的展开。

第三部分是源文件的游戏测试部分:

#include"mines.h"
void menu()
{
    printf("*********  Welcom  to  Mines  *********\n");
    printf("***************************************\n");
    printf("*      1.play             0.exit      *\n");
    printf("***************************************\n");
}
void game()
{
    char mines[ROWS][COLS], show_area[ROWS][COLS], ret;
    int x, y;
    init_mines(mines, show_area, ROWS, COLS, ROW, COL);
    display(mines, ROW, COL);
    display(show_area, ROW, COL);
    while (1)
    {
        printf("Input x and y(like x y):");
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= ROW && y >= 1 && y <= COL)
        {
            ret = checkwin(mines, show_area, ROW, COL, x, y);
            if (ret == 'w')
            {
                display(mines, ROW, COL);
                printf("Congratulations!You win!\n");
                break;
            }
            else if (ret == '*')
            {
                display(mines, ROW, COL);
                printf("You lose!Good luck next time!\n");
                break;
            }
            else
            {
                display(show_area, ROW, COL);
                printf("\n");
            }
        }
        else printf("Input error!Please try again.\n");
    }
}
int main()
{
    int choice;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
        printf("Input your choice:");
        scanf("%d", &choice);
        switch (choice)
        {
        case 1:
            game();
            break;
        case 0:
            break;
        default:
            printf(" Input error!Please try again.\n");
            break;
        }
    } while (choice);
    return 0;
}

希望各位能对我的代码提出意见和建议,并能指导我完成第二部分钟我未完成的两点。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值