[C]專案--掃雷遊戲
阿新 • • 發佈:2018-12-22
掃雷
- 楔子:
掃雷遊戲是我們小時候無聊時消磨時間的小玩意,雖然更新到Win10系統後經典的掃雷遊戲不再了,不過它現在仍以一種抓蟲子的遊戲形式存在於Windows這個系統平臺,不禁感慨遊戲還是那個遊戲,不過人已經不是那些人了啊. - 其實掃雷遊戲的實現也主要運用了陣列和函式封裝與呼叫的知識,具體請看程式.
以下為程式主體:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
//定義方格大小
#define MAX_ROW 10
#define MAX_COL 10
//定義方格雷陣中的地雷數
#define DEFAULT_MINE_COUNT 10
//製作圖形化遊戲介面函式(選單)
int Menu() {
printf("=============================\n");
printf("|| <掃雷遊戲> ||\n");
printf("|| 1.開始遊戲 0.退出遊戲 ||\n");
printf("=============================\n");
int choice = 0;
while (1) {
scanf("%d", &choice);
if (choice != 0 && choice != 1) {
printf("您的輸入有誤,請重新輸入!\n");
continue;
}
return choice;
}
}
//清空方格函式 這裡地雷表示為 * ,安全無地雷表示為 0
void Init(char show_map[MAX_ROW + 2][MAX_COL + 2],
char mine_map[MAX_ROW + 2][MAX_COL + 2]) {
for (int row = 0; row < MAX_ROW + 2; ++row) {
for (int col = 0; col < MAX_COL + 2; ++col) {
show_map[row][col] = '*';
}
}
for (int row = 0; row < MAX_ROW + 2; ++row) {
for (int col = 0; col < MAX_COL + 2; ++col) {
mine_map[row][col] = '0';
}
}
//能夠隨機的構造出 N 個數,放在雷陣中
int mine_count = DEFAULT_MINE_COUNT;
while (mine_count > 0) {
//隨機佈置地雷
int row = rand() % MAX_ROW + 1;
int col = rand() % MAX_COL + 1;
if (mine_map[row][col] == '1') {
continue;
}
mine_map[row][col] = '1';
--mine_count;
}
}
void DisplayMap(char map[MAX_ROW + 2][MAX_COL + 2]) {
printf(" ");
//列印座標橫行
for (int row = 1; row <= MAX_ROW; ++row) {
printf("%d ", row);
}
printf("\n");
//列印上邊框
for (int row = 1; row <= MAX_ROW; ++row) {
printf("---");
}
printf("\n");
for (int row = 1; row <= MAX_ROW; ++row) {
printf("%02d|", row);
for (int col = 1; col <= MAX_COL; ++col) {
printf("%c ", map[row][col]);
}
printf("\n");
}
printf("\n");
printf("\n");
printf("\n");
}
void UpdateShowMap(char show_map[MAX_ROW + 2][MAX_COL + 2],
char mine_map[MAX_ROW + 2][MAX_COL + 2], int row, int col) {
//這個函式要根據mine_map來計算row,col位置上週圍是有幾個地雷
//把結果寫到對應的show_map位置上
//===========此處這8個位置對應的下標不會越界======
//===========因為引入了一圈邊框===================
//row和col取值是[1,MAX_ROW]
//陣列下標取值為[0,MAX_ROW + 1]
int mine_count = 0;
for (int i = row - 1; i <= row + 1; ++i) {
for (int j = col - 1; j <= col + 1; ++j) {
mine_count =
mine_map[i - 1][j - 1] - '0' +
mine_map[i - 1][j] - '0' +
mine_map[i - 1][j + 1] - '0' +
mine_map[i][j - 1] - '0' +
mine_map[i][j + 1] - '0' +
mine_map[i + 1][j - 1] - '0' +
mine_map[i + 1][j] - '0' +
mine_map[i + 1][j + 1] - '0';
if (mine_map[i][j] == '1') {
show_map[i][j] = '*';
}
else {
show_map[i][j] = '0' + mine_count;
}
}
}
}
//遊戲主邏輯,入口
void Game() {
//具體的一局掃雷遊戲
//兩個二維陣列來表示地圖
//第一個陣列表示給玩家展示的地圖
char show_map[MAX_ROW + 2][MAX_COL + 2];
//此處加上一圈邊框(防止陣列下標越界)
//對於show_map:裡面元素有2種情況:
//1.這個位置沒有被掀開,用 * 表示
//2.這個位置已經被掀開了,用一個具體的數字來表示(例如字元'2'來表示)
char mine_map[MAX_ROW + 2][MAX_COL + 2];
//第二個陣列表示雷陣
//對於mine_map,裡面的元素以下情況:
//1.這個位置是地雷,使用字元'1'表示
//2.這個位置不是地雷,使用字元'0'表示
int blank_count = 0;//空格數 不包含地雷,被掀開的格子數
//1.對這兩個陣列進行初始化
//2.列印初始地圖
Init(show_map, mine_map);
DisplayMap(show_map);
while (1) {
//3.讓玩家輸入座標,判定是否合法
int row, col;
printf("請輸入座標:\n");
scanf("%d %d", &row, &col);
if (row <= 0 || row > MAX_ROW
|| col <= 0 || col > MAX_COL) {
printf("您的輸入不合法,重新輸入!\n");
continue;
}
//4.判斷玩家是否踩雷,如果是,遊戲結束
if (mine_map[row][col] == '1') {
printf("遊戲結束!\n");
printf("掃雷失敗!\n");
DisplayMap(mine_map);
break;
}
//5,如果沒踩雷,判定是否掀開了全部格子(玩家勝利)
//6.就統計該位置周圍有幾個雷,並把這個數字更新到地圖上
UpdateShowMap(show_map, mine_map, row, col);
DisplayMap(show_map);
int blank_cnt = 0;
for (row = 1; row <= MAX_ROW; ++row)
{
for (col = 1; col <= MAX_COL; ++col)
{
if (show_map[row][col] != '*')
{
++blank_cnt;
if (blank_cnt == MAX_ROW * MAX_COL - DEFAULT_MINE_COUNT)
{
DisplayMap(mine_map);
printf("掃雷成功,遊戲結束\n");
break;
}
}
}
}
printf("\n");
}
}
void Start() {
//這是遊戲入口函式,遊戲選單
while (1) {
int choice = Menu();
if (choice == 0) {
break;
}
Game();
}
}
//主函式
int main() {
Start();//由開始函式引導遊戲開始
system("pause");
return 0;
}
需要注意的是:
- 大佬可以通過更改程式首部的巨集定義來改變方格大小,擴充介面大小以提高難度.
- 整個遊戲邏輯必須明晰:
列印方格
隨機佈置雷陣
玩家輸入掀開方格座標
判斷是否踩雷(若是,遊戲結束.否則顯示出周圍八個數的地雷數)
若未踩雷判斷是否除了地雷外掀開了所有方格(若是,掃雷成功.否則繼續遊戲)
更新表示地圖
迴圈步驟,返回至使用者輸入環節,繼續遊戲,直至遊戲截止.
- 總結:
程式內部需要有許多的注意點,比如引入一圈邊框,他的作用就是為了確保更新地圖時陣列下標不會越界,是一種保護機制,但是這種機制的構建可能會在程式其他地方的完善工作帶來不小的工程量,但是有這麼一道設定,總比程式直接報錯或者執行一段時間由玩家反饋這個bug來的划算/值得一些,所以儘可能在開發環節做到極致,以免折騰後面修改程式碼缺陷的自己.