C语言扫雷游戏分析

前言

不足之处还请指正。
环境:Xcode
GitHub地址为:https://github.com/ahojcn/Practice/tree/master/bit/MyMineClearanceGame
运行结果


正文

1. 实现分析

基础实现分析:

  1. 需要一个二维数组来存储哪里有雷,哪里没有雷,由于需要判断每一个元素周围有多少雷,方便起见,将数组扩大一圈。
  2. 一个二维数组来向玩家展示玩家所选坐标是否有雷,没有的话显示周围雷的个数。
  3. 每排除一个雷计数器加1,当计数器==行*列-雷个数时玩家胜利。

进一步需求:

  1. 玩家第一步不能被炸死,如果玩家第一次输入的坐标元素为雷,则把这个雷重新分配到其他不是雷的地方。
  2. 递归实现没有雷区的展开。

2. 源码

  • main.c
//
//  main.c
//  MyMineClearanceGame
//
//  Created by hanoi_ahoj on 2018/10/20.
//  Copyright © 2018年 hanoi_ahoj. All rights reserved.
//

#include "game.h"

void game_ctrl()
{
    char board_show[ROWS][COLS] = {0}; // *
    char board_mine[ROWS][COLS] = {0}; // 0
    char sign[ROWS][COLS] = {0};    // 把雷区个数都放进来
    board_init(board_show, ROWS, COLS, '*');    // *
    board_init(board_mine, ROWS, COLS, '0');    // 0
    board_init(sign, ROWS, COLS, '0');  // 0
    
    board_print(board_show, ROW, COL);
    set_mine(board_mine, ROW, COL);
    calculate_mine(board_mine, sign);
//
//    board_print(board_mine, ROW, COL);
//    board_print(sign, ROW, COL);
//
    clear_mine(board_mine, board_show, sign, ROW, COL);
}

int main(int argc, const char * argv[])
{
    srand((unsigned int)time(NULL));
    int input = 0;
    do {
        game_menu();
        printf(">");
        scanf("%d", &input);
        switch (input)
        {
            case 1:
                game_ctrl();
                break;
            case 0:
                printf("Bye!\n");
                break;
            default:
                printf("Error!\n");
                break;
        }
    } while (input);
    
    return 0;
}
  • game.h
//
//  game.h
//  MyMineClearanceGame
//
//  Created by hanoi_ahoj on 2018/10/20.
//  Copyright © 2018年 hanoi_ahoj. All rights reserved.
//

#ifndef game_h
#define game_h

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

#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2

#define EASY 10
#define MAXOPEN 3  //一次最多展开的数量

typedef struct
{
    int x;
    int y;
}Point;

void game_menu(void);
void board_init(char board[ROWS][COLS], int rows, int cols, char set);
void board_print(char board[ROWS][COLS], int row, int col);

// 布置雷
void set_mine(char board_mine[ROWS][COLS], int row, int col);
// play
void clear_mine(char board_mine[ROWS][COLS], char board_show[ROWS][COLS], char sign[ROWS][COLS], int row, int col);
// 计算x,y周围雷数量
int get_mine_count(char board_mine[ROWS][COLS], Point p);
// 计算所有雷数,放到sign[][]里
void calculate_mine(char mine[ROWS][COLS], char sign[ROWS][COLS]);
// 展开周围没有雷的地方,直到遇到 show[][]有数字
void open_show(char mine[ROWS][COLS], char show[ROWS][COLS], char sign[ROWS][COLS], int row, int col, Point p, int count);


// Tim学长的扫雷展开函数
//void open_mine(char show[ROWS][COLS], char mine[ROWS][COLS],int x, int y);
//int GetMineCount(char mine[ROWS][COLS], int x, int y);

#endif /* game_h */
  • game.c

//
//  game.c
//  MyMineClearanceGame
//
//  Created by hanoi_ahoj on 2018/10/20.
//  Copyright © 2018年 hanoi_ahoj. All rights reserved.
//

#include "game.h"

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

void board_init(char board[ROWS][COLS], int rows, int cols, char set)
{
    memset(&board[0][0], set, rows*cols*sizeof(board[0][0]));
}

void board_print(char board[ROWS][COLS], int row, int col)
{
    system("clear");
    for (int i=0; i<=col; i++)
    {
        printf("%d ", i);
    }
    printf("\n");
    
    for (int i=1; i<=row; i++)
    {
        printf("%d ", i);
        for (int j=1; j<=col; j++)
        {
            printf("%c ", board[i][j]);
        }
        printf("\n");
    }
    printf("-------------------\n");
}

// 布置雷
void set_mine(char board_mine[ROWS][COLS], int row, int col)
{
    Point p;
    int count = EASY;
    while (count)
    {
        p.x = rand()%row + 1;
        p.y = rand()%col + 1;
        if (board_mine[p.x][p.y] == '0')
        {
            board_mine[p.x][p.y] = '1';
            count--;
        }
    }
}

// play
void clear_mine(char board_mine[ROWS][COLS], char board_show[ROWS][COLS], char sign[ROWS][COLS], int row, int col)
{
    Point p;
    int win = 0;
    int cnt = 0;
    while (win<row*col-EASY)
    {
        cnt++;
        printf(">");
        scanf("%d%d", &p.x, &p.y);
        if (p.x>=1 && p.x<=row && p.y>=1 && p.y<=col)
        {
//             第一次踩到雷
            if (board_mine[p.x][p.y]=='1' && cnt==1)
            {
//                重新计算sign中的值
                board_mine[p.x][p.y] = '0';
                Point tmp;
                tmp.x = p.x;
                tmp.y = p.y;
                while (p.x==tmp.x && p.y==tmp.y)
                {
                    p.x = rand()%row+1;
                    p.x = rand()%col+1;
                    if (board_mine[p.x][p.y] == '0' && (p.x!=tmp.x || p.y!=tmp.y))
                    {
                        board_mine[p.x][p.y] = '1';
                        calculate_mine(board_mine, sign);
        test
//                        board_print(board_mine, row, col);
//                        board_print(sign, row, col);
        test
                        break;
                    }
                    else
                    {
                        continue;
                    }
                }
            }/*if() 第一次踩到雷*/
            else if(board_mine[p.x][p.y] == '1')    // 第一次以后踩到雷了
            {
                board_print(board_mine, row, col);
                printf("you die!\n");
                break;
            }
            else    // 没踩到雷
            {
                int count = get_mine_count(board_mine, p);
                board_show[p.x][p.y] = count + '0';
                int cnt = MAXOPEN;
                open_show(board_mine, board_show, sign, row, col, p, cnt);
//                open_mine(board_show, board_mine, p.x, p.y);
                board_print(board_show, row, col);
                win++;
            }
        }
        else
        {
            printf("illegal input!\n");
        }
    }// while() 雷没排完
    if(win==row*col-EASY)
    {
        board_print(board_mine, row, col);
        printf("you win!\n");
    }
}

// 计算x,y周围雷数量
int get_mine_count(char board_mine[ROWS][COLS], Point p)
{
    return board_mine[p.x-1][p.y]+
    board_mine[p.x-1][p.y-1]+
    board_mine[p.x][p.y-1]+
    board_mine[p.x+1][p.y-1]+
    board_mine[p.x+1][p.y]+
    board_mine[p.x+1][p.y+1]+
    board_mine[p.x][p.y+1]+
    board_mine[p.x-1][p.y+1]-8*'0';
}

// 计算所有雷数,放到sign[][]里
void calculate_mine(char mine[ROWS][COLS], char sign[ROWS][COLS])
{
    Point p;
    for (int i=0; i<ROWS; i++)
    {
        for (int j=0; j<COLS; j++)
        {
            p.x = i;
            p.y = j;
            sign[i][j] = '0' + get_mine_count(mine, p);
        }
    }
}

// 展开周围没有雷的地方,直到遇到 show[][]有数字
void open_show(char mine[ROWS][COLS], char show[ROWS][COLS], char sign[ROWS][COLS], int row, int col, Point p, int count)
{
    Point tmp;
    if (count>=0)
    {
        if (mine[p.x-1][p.y-1] == '0')
        {
            tmp.x = p.x-1;
            tmp.y = p.y-1;
            show[tmp.x][tmp.y] = sign[tmp.x][tmp.y];
            count--;
            open_show(mine, show, sign, row, col, tmp, count);
        }
        if(mine[p.x-1][p.y] == '0')
        {
            tmp.x = p.x-1;
            tmp.y = p.y;
            show[tmp.x][tmp.y] = sign[tmp.x][tmp.y];
            count--;
            open_show(mine, show, sign, row, col, tmp, count);
        }
        if(mine[p.x-1][p.y+1] == '0')
        {
            tmp.x = p.x-1;
            tmp.y = p.y+1;
            show[tmp.x][tmp.y] = sign[tmp.x][tmp.y];
            count--;
            open_show(mine, show, sign, row, col, tmp, count);
        }
        if(mine[p.x][p.y+1] == '0')
        {
            tmp.x = p.x;
            tmp.y = p.y+1;
            show[tmp.x][tmp.y] = sign[tmp.x][tmp.y];
            count--;
            open_show(mine, show, sign, row, col, tmp, count);
        }
        if(mine[p.x+1][p.y+1] == '0')
        {
            tmp.x = p.x+1;
            tmp.y = p.y+1;
            show[tmp.x][tmp.y] = sign[tmp.x][tmp.y];
            count--;
            open_show(mine, show, sign, row, col, tmp, count);
        }
        if(mine[p.x+1][p.y] == '0')
        {
            tmp.x = p.x+1;
            tmp.y = p.y;
            show[tmp.x][tmp.y] = sign[tmp.x][tmp.y];
            count--;
            open_show(mine, show, sign, row, col, tmp, count);
        }
        if(mine[p.x+1][p.y-1] == '0')
        {
            tmp.x = p.x+1;
            tmp.y = p.y-1;
            show[tmp.x][tmp.y] = sign[tmp.x][tmp.y];
            count--;
            open_show(mine, show, sign, row, col, tmp, count);
        }
        if(mine[p.x][p.y-1] == '0')
        {
            tmp.x = p.x;
            tmp.y = p.y-1;
            show[tmp.x][tmp.y] = sign[tmp.x][tmp.y];
            count--;
            open_show(mine, show, sign, row, col, tmp, count);
        }
    }
    else
    {
        NULL;
    }
}


 下面这个是Tim学长的扫雷展开函数
//int GetMineCount(char mine[ROWS][COLS], int x, int y)
//{
//
//    return (mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1]
//            + mine[x][y - 1] + mine[x][y + 1]
//            + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0');
//}
//
//void open_mine(char show[ROWS][COLS], char mine[ROWS][COLS],int x, int y)//坐标周围展开函数
//{
//    if (show[x][y] == '*' && ((x >= 1) && (x <= 9)) && ((y >= 1) && (y <= 9)))
//    {
//        if (GetMineCount(mine,x, y) != 0)
//        {
//            show[x][y] = GetMineCount(mine, x, y) + '0';
//        }
//        else
//        {
//            show[x][y] = ' ';
//            open_mine(show, mine,x - 1, y);
//            open_mine(show, mine, x - 1, y - 1);
//            open_mine(show, mine, x - 1, y + 1);
//            open_mine(show, mine, x, y - 1);
//            open_mine(show, mine, x, y + 1);
//            open_mine(show, mine, x + 1, y - 1);
//            open_mine(show, mine, x + 1, y);
//            open_mine(show, mine, x + 1, y + 1);
//        }
//    }
//    return;
//}

完,不足之处还请指正。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值