C語(yǔ)言實(shí)現(xiàn)控制臺(tái)掃雷小游戲
C語(yǔ)言實(shí)現(xiàn)控制臺(tái)“掃雷”小游戲
根據(jù)以往的游戲經(jīng)驗(yàn),我們能首先可以確定掃雷游戲勝利的規(guī)則是:翻開所有不是雷的區(qū)域才能算是勝利。
接下來我們需要確定整個(gè)程序的設(shè)計(jì)思路:
1.首先,我們定義兩個(gè)9*9的二維數(shù)還是未翻開的狀態(tài)組。第一個(gè)數(shù)組用來表示雷區(qū)地圖的展開情況,即每個(gè)素組元素的位置的狀態(tài)是處于展開狀態(tài)還是未展開狀態(tài),我們命名為showMap()。第二個(gè)數(shù)組我們用來表示地雷的分布情況,素組中的每個(gè)元素位置都被標(biāo)記為是否為地雷,我們命名為minMap()。
2.初始化兩個(gè)地圖,并將地圖打印出來。
3.玩家通過輸入二維數(shù)組的坐標(biāo)進(jìn)行位置輸入,翻開地圖位置。
4.判斷玩家輸入的位置是否合法。
5.判斷玩家輸入的位置是否有地雷,如果有地雷則直接宣布游戲結(jié)束;若果沒有地雷則繼續(xù)進(jìn)行游戲。
6.如果繼續(xù)游戲,則玩家輸入的位置處會(huì)顯示附近地雷的個(gè)數(shù)。
第一步,此處通過構(gòu)造menu()函數(shù)搭建一個(gè)簡(jiǎn)單的交互菜單和玩家交互,用來判斷是否開始進(jìn)行一局游戲。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> //宏定義 #define MAX_ROW 9 #define MAX_COL 9 #define DEFAULT_MINE_COUNT 10 int menu() { printf("======================\n"); printf(" 1. 開始游戲\n"); printf(" 0. 結(jié)束游戲\n"); printf("======================\n"); printf(" 請(qǐng)輸入您的選擇: "); int choice = 0; scanf("%d", &choice); return choice; } int main() { srand((unsigned int)time(0)); while (1) { int choice = menu(); if (choice == 1) { game();//此處調(diào)用了game()函數(shù). } else if (choice == 0) { printf("Goodbye!\n"); break; } else { printf("您的輸入有誤!\n"); } } system("pause"); return 0; }
第二步,對(duì)第一步中調(diào)用的game()函數(shù)進(jìn)行構(gòu)造。game()函數(shù)為核心功能函數(shù),其主要任務(wù)是完成基本流程。
1.構(gòu)建init()函數(shù),對(duì)兩個(gè)二維數(shù)組進(jìn)行初始化操作。初始化 showMap, 將數(shù)組所有元素全都設(shè)為 * 。初始化 mineMap, 先全設(shè)為 ‘0', 然后隨機(jī)生成 N 個(gè) ‘1' ,此處的'1'就代表地雷, N 的值就是 DEFAULT_MINE_COUNT,也就是地雷的數(shù)量。
void init(char showMap[MAX_ROW][MAX_COL], char mineMap[MAX_ROW][MAX_COL]) { for (int row = 0; row < MAX_ROW; row++) { for (int col = 0; col < MAX_COL; col++) { showMap[row][col] = '*'; } } for (int row = 0; row < MAX_ROW; row++) { for (int col = 0; col < MAX_COL; col++) { mineMap[row][col] = '0'; } } int n = DEFAULT_MINE_COUNT; while (n > 0) { // 生成雷的隨機(jī)位置. int row = rand() % MAX_ROW; int col = rand() % MAX_COL; if (mineMap[row][col] == '1') { // 如果當(dāng)前位置已經(jīng)有雷了, 就直接進(jìn)入下次循環(huán), 重新 // 產(chǎn)生隨機(jī)位置. continue; } mineMap[row][col] = '1'; n--; } }
2.構(gòu)建printMap()函數(shù),該函數(shù)負(fù)責(zé)打印顯示地圖,需要注意的是,大部分情況下打印的都是 showMap, 但是在 GameOver 的時(shí)候, 就需要打印 mineMap。
void printMap(char theMap[MAX_ROW][MAX_COL]) { // 先打印出第一行, 第一行就是包含所有的列號(hào)。 // 然后在打印下面的每一行的時(shí)候再打印行號(hào)。 printf(" |"); for (int col = 0; col < MAX_COL; col++) { printf("%d ", col); } printf("\n"); printf("--+------------------\n"); for (int row = 0; row < MAX_ROW; row++) { printf(" %d|", row); for (int col = 0; col < MAX_COL; col++) { printf("%c ", theMap[row][col]); } printf("\n"); } }
3.構(gòu)建updateShowMap()函數(shù),用于根據(jù)當(dāng)前 輸入的(row, col) 的位置, 計(jì)算出當(dāng)前位置周圍有幾個(gè)雷, 并且更新顯示到 showMap 中。
void updateShowMap(char showMap[MAX_ROW][MAX_COL], char mineMap[MAX_ROW][MAX_COL], int row, int col) { int count = 0; for (int r = row - 1; r <= row + 1; r++) { for (int c = col - 1; c <= col + 1; c++) { if (r < 0 || r >= MAX_ROW || c < 0 || c >= MAX_COL) { // 如果(row, col) 下標(biāo)越界, 就直接跳過。 continue; } if (mineMap[r][c] == '1') { count++; } } } // 此時(shí) count 里面就已經(jīng)存好了 (row, col )周圍八個(gè)格子里的雷的個(gè)數(shù)。 // 把這個(gè)結(jié)果寫到 showMap 中即可。 // 需要把數(shù)字 count 轉(zhuǎn)成對(duì)應(yīng)的字符,例如: count 為 2, 就需要轉(zhuǎn)成 '2' (ASCII 50) showMap[row][col] = count + '0'; }
最后,我們整合以下功能函數(shù)就得到了我們的game()函數(shù)。
void game() { // 1. 創(chuàng)建地圖并初始化。(兩個(gè)地圖)。 char showMap[MAX_ROW][MAX_COL] = { 0 }; char mineMap[MAX_ROW][MAX_COL] = { 0 }; init(showMap, mineMap); int openedBlockCount = 0; while (1) { printMap(mineMap); printf("=================================\n"); printMap(showMap); // 2. 程序讀取玩家輸入的要翻開位置的坐標(biāo), 并校驗(yàn)。 int row = 0; int col = 0; printf("請(qǐng)輸入要翻開的坐標(biāo)(row col): "); scanf("%d %d", &row, &col); if (row < 0 || row >= MAX_ROW || col < 0 || col >= MAX_COL) { printf("您輸入的坐標(biāo)有誤!\n"); continue; } if (showMap[row][col] != '*') { printf("當(dāng)前位置已經(jīng)翻開了!\n"); continue; } // 3. 判定該位置的坐標(biāo)是否是地雷. 如果是地雷, 直接 GameOver。 if (mineMap[row][col] == '1') { printf("GameOver!\n"); // 游戲結(jié)束的時(shí)候最好再打印一遍地雷的地圖, 讓玩家死的明白。 printMap(mineMap); break; } // 4. 如果不是地雷, 統(tǒng)計(jì)當(dāng)前位置周圍雷的個(gè)數(shù), 并顯示到地圖上。 updateShowMap(showMap, mineMap, row, col); // 5. 判定游戲是否勝利,核心邏輯應(yīng)該是判斷當(dāng)前是不是把所有不是雷的位置都翻開了 //此處可以記錄翻開的格子的個(gè)數(shù)。 openedBlockCount++; if (openedBlockCount == MAX_ROW * MAX_COL - DEFAULT_MINE_COUNT) { printf("游戲勝利!\n"); printMap(mineMap); break; } } }
運(yùn)行截圖:
1.游戲啟動(dòng):
2.輸入坐標(biāo)非法提示:
3.輸入坐標(biāo)位置已翻開。
4.游戲結(jié)束。
更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專題,分享給大家:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
在C語(yǔ)言里單引號(hào)和雙引號(hào)的區(qū)別
這篇文章主要介紹了在C語(yǔ)言里單引號(hào)和雙引號(hào)的區(qū)別,本文通過代碼的實(shí)例和注釋的詳細(xì)的說明了單引號(hào)和雙引號(hào)的概念與區(qū)別,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C++ vector模擬實(shí)現(xiàn)的代碼詳解
vector是表示可變大小數(shù)組的序列容器,就像數(shù)組一樣,vector也采用的連續(xù)存儲(chǔ)空間來存儲(chǔ)元素,本質(zhì)講,vector使用動(dòng)態(tài)分配數(shù)組來存儲(chǔ)它的元素,本文將給大家詳細(xì)介紹一下C++ vector模擬實(shí)現(xiàn),需要的朋友可以參考下2023-07-07C++數(shù)據(jù)結(jié)構(gòu)與算法之反轉(zhuǎn)鏈表的方法詳解
這篇文章主要介紹了C++數(shù)據(jù)結(jié)構(gòu)與算法之反轉(zhuǎn)鏈表的方法,結(jié)合實(shí)例形式分析了C++反轉(zhuǎn)鏈表的原理、實(shí)現(xiàn)方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-08-08C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之單鏈表的實(shí)現(xiàn)
鏈表是一種物理存儲(chǔ)結(jié)構(gòu)上非連續(xù)、非順序的存儲(chǔ)結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針鏈接次序?qū)崿F(xiàn)的。本文將用C語(yǔ)言實(shí)現(xiàn)單鏈表,需要的可以參考一下2022-06-06C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的五子棋小游戲
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的五子棋小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05