用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"); } }

和三子棋一样,我这里定义数组时也运用了宏定义。

下面展示除胜利外的几种情况:

1、在(1,2)周围有1个雷。

2、被炸死。

最后放上我自己写出的代码:

代码分为三部分,

第一部分是头文件:

#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; }

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

转载于:https://www.cnblogs.com/xiefei777/p/7711510.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值