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

完,不足之處還請指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章