前言
不足之處還請指正。
環境:Xcode
GitHub地址爲:https://github.com/ahojcn/Practice/tree/master/bit/MyMineClearanceGame
正文
1. 實現分析
基礎實現分析:
- 需要一個二維數組來存儲哪裏有雷,哪裏沒有雷,由於需要判斷每一個元素周圍有多少雷,方便起見,將數組擴大一圈。
- 一個二維數組來向玩家展示玩家所選座標是否有雷,沒有的話顯示周圍雷的個數。
- 每排除一個雷計數器加1,當計數器==行*列-雷個數時玩家勝利。
進一步需求:
- 玩家第一步不能被炸死,如果玩家第一次輸入的座標元素爲雷,則把這個雷重新分配到其他不是雷的地方。
- 遞歸實現沒有雷區的展開。
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;
//}