C语言实现扫雷

C语言实现扫雷

目录结构和上一个五子棋一样一样的,参考五子棋程序

代码流程

  1. 用户输入,选择游戏难度,此处使用了枚举常量PLAY1和PLAY2与SWitch语句进行搭配使用,可以让代码清晰明了。
  2. 进入游戏的流程是根据用户输入的难度选择,创建不同大小的数组空间(棋盘),这里本应该用malloc动态申请内存来做,但是偷懒,我用符号常量定义了一个大空间ROW行和COL列,在选择处做一个判断,分别传入不同的row和col。并且定义了EASY_COUNT 和MIDDLE_COUNT两个不同难度的雷数。
  3. 完成随机布雷,展示棋盘,玩家排雷,以及最重要的棋盘展开函数。

重点难点注意点

  1. 怎么判断是胜利,还是爆炸?

    如果玩家输入的坐标是雷,那么就原地爆炸,如果玩家把所有尚未点开的块都点开了并且没有遇到雷,那么则是胜利,if(show[i][j]=='*' && board[i][j]=='0') 这句话意思是如果还有尚未点开的地图并且这里没有雷,那么就还不算胜利,这个在FindMine函数里。

  2. 棋盘展开函数

    其实就是一个深度优先遍历搜索,从当前坐标开始不断的向周围四个方向进行探索,如果碰到show矩阵有数字的地方就停止展开(或者碰到边界),把走过的show矩阵全部置为空格,这样就达到了爆炸的效果。需要注意的是,深搜需要一个used数组,和棋盘一样大小,记录已经走过的格子,不然走过一边又走一遍会无限死循环的。

  3. 代码重用性

    我们用一个show数组表示显示的棋盘,一个board数组表示雷的分布,初始化函数多传入一个 set 参数,能避免多写一遍代码。而且两个数组都是char型,很方便的在 ‘*’ ‘数字’ ‘空格’,之间转化,记得算雷数时减去周围的8个’0’ 的ascii码值就可以了。

运行结果

p1GsAJ.md.png

p1Gg91.md.png

game.h

#ifndef __GAME_H__
#define __GAME_H__

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


enum OPTION
{
    EXIT,
    PLAY,
    PLAY2,

};

#define EASY_COUNT 5      //7x7
#define MIDDLE_COUNT 90      //10x10


#define ROW 30
#define COL 30

void InitBoard(char board[ROW][COL], int row, int col, char set);
void Display(char board[ROW][COL], int row, int col);
void SetMine(char board[ROW][COL], int row, int col, int mine);
void SpreadMine(char board[ROW][COL],char show[ROW][COL],int used[ROW][COL], int row, int col, int x, int y);
int FindMine(char board[ROW][COL],char show[ROW][COL], int row, int col);
int PlayerMove(char board[ROW][COL], char show[ROW][COL], int row, int col,int mine, int step);
#endif //__GAME_H__


game.c

#include "game.h"

void InitBoard(char board[ROW][COL], int row, int col, char set){
    memset(board,set,row*col*sizeof(char));
}
void Display(char board[ROW][COL], int row, int col){
    int i = 0;
    int j = 0;

    for(i=1; i<row; i++){
        if(i == 1){
            for(j=1; j<col;j++){
                if(1 == j){
                    printf("   ");
                }
                printf("|%2d|",j);
            }
            printf("\n");
            for(j=1; j<col;j++){
                if(1 == j){
                    printf("   ");
                }
                printf(" ---");
            }
            printf("\n");
        }
        for(j=1; j<col;j++){
            if(1 == j){
                printf("%2d|",i);
            }
            printf("| %c ",board[i][j]);
        }
        printf("|\n");
        for(j=1; j<col;j++){
            if(1 == j){
                printf("   ");
            }
            printf(" ---");
        }
        printf("\n");
    }
        printf("\n");
}
void SetMine(char board[ROW][COL], int row, int col, int mine){
    int x = 0;
    int y = 0;
    int i = 0;
    for(i=0; i<mine; i++){
        x = rand()%(row-1)+1;  //因为传的row是8 如果7X7生成1~7的随机数
        y = rand()%(col-1)+1;
        while(board[x][y] == '1'){               //该位置已经有雷,重新选位置。
            x = rand()%(row-1)+1;  
            y = rand()%(col-1)+1;
        }
        board[x][y] = '1';
    }

}
int FindMine(char board[ROW][COL],char show[ROW][COL], int row, int col){
    //正常展开返回0,没有可扫的雷了返回1
    int flag = 0;
    int i = 0, j = 0;

    for(i=1; i<row; i++){
        for(j=1; j<col;j++){
            if(show[i][j]=='*' && board[i][j]=='0'){  //还有没扫出来的雷
                flag = 1;
                break;
            }
        }
    }
    if(!flag){
        return 1;
    }


    return 0;
}
void SpreadMine(char board[ROW][COL],char show[ROW][COL],int used[ROW][COL], int row, int col, int x, int y){
    int tmp = 0;
    int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
    int tmpx = 0, tmpy = 0;
    int i;
    if(x<1||y<1||x>=row||y>=col||used[x][y]== -1){        //row是8,到下标为8就到边界了
        return;
    }
    used[x][y] = -1;     //访问过了
    if(board[x][y]=='0'){
        show[x][y]= ' ';
    }
    tmp = board[x-1][y-1]+board[x-1][y+0]+board[x-1][y+1]+board[x+0][y-1]+board[x+0][y+1]+board[x+1][y-1]+board[x+1][y+0]+board[x+1][y+1]- 8*'0';
    if(tmp > 0 ){
        show[x][y] = tmp + '0';
        return;
    }
    for(i=0; i<4; i++){
        tmpx = x +dir[i][0];
        tmpy = y +dir[i][1];
        SpreadMine(board, show, used, row, col, tmpx, tmpy);
    }

}
int PlayerMove(char board[ROW][COL], char show[ROW][COL], int row, int col,int mine, int step){     
    int x = 0;
    int y = 0;
    int i = 0, j = 0;
    int used[ROW][COL]= {0};
    while(1){
        printf("请输入你要排雷的坐标(x,y)->\n");
        scanf("%d%d",&x,&y);
        if(0 == step && board[x][y] == '1'){
                                     //第一步是雷则把雷移开
            for(i=1; i<row; i++){
                for(j=1; j<col; j++){
                    if(board[i][j]=='0'){
                        board[i][j]='1';
                        board[x][y]='0';
                        break;
                    }
                }
            }

        }
        if(x>=row|| y>=col|| x<=0|| y<=0){
            printf("输入非法的位置!\n");
            continue;
        }

        else if(show[x][y] != '*'){
            printf("这个位置你已经知道啦!\n");
            continue;
        }
        else if(board[x][y]=='1'){

            Display(board, row, col);
            printf("************你炸了**********\n");
            return 1;                               
        }


        break;   //合法输入

    }

    SpreadMine(board, show, used, row, col, x, y);
    return 0;
}

test.c

#include <stdio.h>
#include "game.h"
#define _CRT_SECURE_NO_WARNINGS 1

void menu(){
    printf("**************************************\n");
    printf("********来一盘惊险刺激的扫雷吧********\n");
    printf("********1.入门级别********************\n");
    printf("********2.进阶级别********************\n");
    printf("********0.退出游戏********************\n");
    printf("**************************************\n");
}
void game(int choice){
    char board[ROW][COL];
    char show[ROW][COL];
    int ret = 0;          //玩家走一步之后的输赢结果
    int row = 0;
    int col = 0;
    int step = 0;         //已走步数
    int mine = 0;         //雷数
    if(choice == 1){
        row = 8;
        col = 8;
        mine = EASY_COUNT;
    }
    else {
        row = 11;
        col = 11;
        mine = MIDDLE_COUNT;
    }
    InitBoard(board, ROW, COL, '0');        //初始化雷阵
    InitBoard(show, ROW, COL, '*');         //初始化显示矩阵
    srand((unsigned int)time(NULL));
    SetMine(board, row, col, mine);
//  Display(board, row, col);
    Display(show, row, col);
    while(1){
        ret = PlayerMove(board,show, row, col, mine, step);
        if(1 == ret){                        
            break;
        }
        ret = FindMine(board, show, row, col);
        if(1 == ret){   
            Display(show, row, col);
            Display(board, row, col);
            printf("**************革命成功了!*******\n");

            break;
        }
        //Display(board, row, col);
        Display(show, row, col);
        step ++;
    }
}
int main(){
    int choice = 0;

    do{
        menu();
        printf("请输入->");
        scanf("%d",&choice);
        switch(choice){
            case PLAY:game(choice);
                continue;
            case PLAY2:game(choice);
                continue;
            case EXIT:printf("退出游戏");
                break;
            default:printf("没有这个选项,请重新输入\n");
                continue;
        }

    }while(choice);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值