C語言實現(xiàn)自定義掃雷游戲(遞歸版)
本文實例為大家分享了C語言自定義掃雷游戲的具體代碼,供大家參考,具體內(nèi)容如下
實現(xiàn)過程
對于用C語言實現(xiàn)掃雷游戲得實現(xiàn),可將游戲過程分為兩個板塊。
- 實現(xiàn)游戲關(guān)鍵功能得函數(shù)
- 搭建合理得游戲過程
實現(xiàn)游戲關(guān)鍵功能
為了將游戲功能方便管理和鍵入,首先我們創(chuàng)建一個頭文件,mine.h
對游戲功能進行聲明。
然后創(chuàng)建對應(yīng)的源文件mine.c
對這些函數(shù)進行定義。
對于游戲功能,我們首先想到的是構(gòu)建一個目標(biāo)規(guī)格的雷盤,也就是二維數(shù)組。
為了使游戲更具可玩性,所以雷盤的規(guī)格應(yīng)可以自定義。所以在mine.h
頭文件中,應(yīng)先用define定義ROW(行)和列(列)的標(biāo)識符便于自定義。
#define ROW 15 ?//先將他們的規(guī)格定義為15*15 #define COL 15 #define ROWS ROW+2 #define COLS COL+2
為什么要定義后面兩個宏?
對于雷盤的的核心功能實現(xiàn),必然是能夠當(dāng)玩家選擇坐標(biāo)以后(若該位置不是雷)能夠精確的統(tǒng)計以該坐標(biāo)為核心周圍九宮格雷的個數(shù),那么處于邊界的地方該如何精準(zhǔn)的判斷呢?
所以將真正的雷盤數(shù)組規(guī)格定義ROW+2,COL+2大小,在ROW,COL規(guī)格的雷盤中隨機置雷,使得游戲結(jié)果準(zhǔn)確。
- 定義雷盤和顯示盤的初始化
定義兩同規(guī)格的二維數(shù)組,前者是真正的雷區(qū),用‘1’和‘0’來表示雷和無雷,后者是顯示區(qū),用于玩家操作和結(jié)果顯示。
void init(char arr[ROWS][COLS], int rows, int cols, char type) //memset批量操作時傳入的是指針,即數(shù)組開始地址 { ? ? memset(arr, type, rows*cols * sizeof(mine[0][0])); }
- 在顯示區(qū)隨機放置雷
void setmine(char mine[ROWS][COLS], int count) { ? ? srand((unsigned)time(NULL)); ? ? int i = 0; ? ? int j = 0; ? ? while (count) ? ? { ? ? ? ? i = (rand() % ROW) + 1; ?//讓隨機值0-9變成1-10 實現(xiàn)操作區(qū)隨機放雷 ? ? ? ? j = (rand() % COL) + 1; ? ? ? ? if (mine[i][j] == '0') ? ? ? ? { ? ? ? ? ? ? mine[i][j] = '1'; ? ? ? ? ? ? count--; ? ? ? ? } ? ? } }
- 打印界面
void display(char board[ROWS][COLS]) {//從第一行一列開始打因元素 ? ? int i = 0; ? ? int j = 0; ? ? printf("\n ? ? ?|"); ? ? for (i = 1; i <= COL; i++)//打印操作區(qū)的列號 ? ? { ? ? ? ? printf("%4d", i); ?//打印序號 ? ? } ? ? printf("\n"); ? ? printf("------|------------------------------------------\n"); ? ? for (i = 1; i <= ROW; i++) ? ? { ? ? ? ? printf("%4d ?|", i);//打印序號 ? ? ? ? for (j = 1; j <= COL; j++) ? ? ? ? { ? ? ? ? ? ? printf("%4c", board[i][j]); ? ? ? ? } ? ? ? ? printf("\n ? ? ?\n"); ? ? } }
- 統(tǒng)計目標(biāo)點周圍雷的個數(shù)
int cal_mine(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] - (7 * '0'));//這里減7而不是8。因為這樣直接可以表示出數(shù)字字符 ? ? //此處的目的是統(tǒng)計周圍雷的個數(shù),又因為是ASCII碼,'1'和'0'只相差1,然后進去'0'的ASCII值得到1的個數(shù) }
如果目標(biāo)點周圍無雷向外擴展
在掃雷游戲過程中必然會出來一點一大片凹陷的強烈快感,但自己實現(xiàn)的過程中這是如何做到的呢?
原則是如果該點周圍無雷,那么將用空格替代,然后向四周伸展將周圍的“周圍無雷點”繼續(xù)用空格替代,若四周存在“周圍有雷點”,那么停止向周圍延伸。
在苦思冥想后,想到了用遞歸的方法來實現(xiàn)這個一點一大片功能。
void expand(char mine[ROWS][COLS], char board[ROWS][COLS], int x, int y) { ? ? if (x >= 1 && x <= ROW&&y >= 1 && y <= COL) // 遞歸防止越界 ? ? { ? ? ? ? /*if (mine[x][y] == '0')*/ ? ? ? ? { ? ? ? ? ? ? char count = cal_mine(mine, x, y); ? ? ? ? ? ? if (count == '0') ? ? ? ? ? ? { ? ? ? ? ? ? ? ? board[x][y] = ' '; ? ? ? ? ? ? ? ? if (board[x - 1][y - 1] == '*') ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? expand(mine, board, x - 1, y - 1); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (board[x - 1][y] == '*') ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? expand(mine, board, x - 1, y); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (board[x - 1][y + 1] == '*') ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? expand(mine, board, x - 1, y + 1); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (board[x][y - 1] == '*') ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? expand(mine, board, x, y - 1); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (board[x][y + 1] == '*') ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? expand(mine, board, x, y + 1); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (board[x + 1][y - 1] == '*') ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? expand(mine, board, x + 1, y - 1); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (board[x + 1][y] == '*') ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? expand(mine, board, x + 1, y); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if (board[x + 1][y + 1] == '*') ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? expand(mine, board, x + 1, y + 1); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? else ? ? ? ? ? ? { ? ? ? ? ? ? ? ? board[x][y] = count; ? ? ? ? ? ? } ? ? ? ? } ? ? } }
- 判斷勝利
若顯示區(qū)最終剩下的*等于雷數(shù),那么玩家勝利
int is_win(char board[ROWS][COLS]) { int count = 0; int i = 0, j = 0; for (i = 1; i <= ROW; i++) { ? ? for (j = 1; j <= COL; j++) ? ? { ? ? ? ? if ('*' == board[i][j]) ? ? ? ? { ? ? ? ? ? ? count++; ? ? ? ? } ? ? } } return count; }
- 玩家操作
int player(char mine[ROWS][COLS], char board[ROWS][COLS], int count) { ? ? int x = 0, y = 0; ? ? while (1)//檢測輸入錯誤區(qū) ? ? { ? ? ? ? while (2 != scanf("%d %d", &x, &y)) ? ? ? ? { ? ? ? ? ? ? while ((getchar() != '\n')) ?//如果玩家輸入了很多非法字符,那么將他們?nèi)课? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? NULL; ? ? ? ? ? ? } ? ? ? ? ? ? printf("輸?shù)氖巧锻嬉?\n"); ? ? ? ? } ? ? ? ? if (x < 1 || x > ROW || y < 1 || y > COL) ? ? ? ? { ? ? ? ? ? ? printf("輸入越界\n"); ? ? ? ? } ? ? ? ? else if (board[x][y] != '*') ? ? ? ? { ? ? ? ? ? ? printf("你踩過了!\n"); ? ? ? ? } ? ? ? ? else ? ? ? ? { ? ? ? ? ? ? if (count == 1 && (mine[x][y] == '1')) //!mine[x][y]=='1'這個條件特別重要??!如果玩家沒有踩到雷那么將會使這個位置變成雷!! ? ? ? ? //雖然這樣并不影響程序完整運行,因為檢驗雷點是通過存在的*來計數(shù)的,這個值附上去以后肯定恒為1占去了*,但是嚴(yán)謹(jǐn)?shù)耐婕铱隙ㄕf你有BUG ? ? ? ? ? ? ? ? //所以我們還是盡量寫通俗易懂的邏輯程序 下面的while循環(huán)會讓人感覺是檢測,其實是賦值轉(zhuǎn)換 ? ? ? ? ? ? { ? ? ? ? ? ? ? ? int i = 0, j = 0; ? ? ? ? ? ? ? ? while (mine[x][y] == '1') ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? i = (rand() % 10) + 1; ? ? ? ? ? ? ? ? ? ? j = (rand() % 10) + 1; ? ? ? ? ? ? ? ? ? ? mine[x][y] = mine[i][j];//將值為符號零的元素賦給操作數(shù), ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? mine[i][j] = '1';//賦值如果成功那么便讓他成為1 ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? break; ? ? } ? ? if (mine[x][y] == '1')//檢驗開始 ? ? { ? ? ? ? printf("\n新時代的董存瑞!\n"); ? ? ? ? return 1; ? ? } ? ? else ? ? { ? ? ? ? expand(mine, board, x, y); ? ? } ? ? return is_win(board); }
最后將這些聲明和定義轉(zhuǎn)入到mine.h
和mine.c
搭建合理的游戲過程
將這些函數(shù)功能合理的整個在一起后,在mian函數(shù)存在的源文件中創(chuàng)建定義game()函數(shù),將每一步連接在一起。創(chuàng)建menu()函數(shù)顯示菜單。
game()
void game() { ? ? printf("歡\n"); Sleep(250); ? ? printf("迎\n"); Sleep(250); ? ? printf("來\n"); Sleep(250); ? ? printf("到\n"); Sleep(250); ? ? printf("caco\n"); Sleep(250); ? ? printf("的\n"); Sleep(250); ? ? printf("掃\n"); Sleep(250); ? ? printf("雷!\n"); Sleep(250); ? ? printf("村"); Sleep(250); ? ? printf("!"); Sleep(150); ? ? printf("!"); Sleep(150); ? ? char mine[ROWS][COLS] = { 0 }; ? ? char board[ROWS][COLS] = { 0 }; ? ? init(mine, ROWS, COLS, '0'); ? ? init(board, ROWS, COLS, '*'); ? ? int num = 0; ? ? printf("\n要幾個雷\n?"); ? ? scanf("%d", &num); ? ? setmine(mine, num); ? ? display(mine); ? ? int count = 1; ? ? int ret = 0; ? ? while (1) ? ? { ? ? ? ? display(board); ? ? ? ? ret = player(mine, board, count); ? ? ? ? count++; ? ? ? ? if (ret == num) ?//和玩家輸入得雷數(shù)要保持一致 ? ? ? ? { ? ? ? ? ? ? printf("炸不死得諾貝爾~!\n"); ? ? ? ? ? ? break; ? ? ? ? } ? ? ? ? if (ret == 1) ? ? ? ? { ? ? ? ? ? ? break; ? //表示直接菜到雷退出 ? ? ? ? } ? ? } }
munu()
void menu() { ? ? printf("*******************************************\n"); ? ? printf("------ 我可以大口吞下炸彈而不傷身體--------\n"); ?//label 1. original test. ? ? printf("------1. ?進村 ? -------------------------\n-------------------------\n"); ? ? printf("------0. ?撤退! -------------------------\n"); ? ? printf("*******************************************\n"); } int main() { ? ? int a = 0; ? ? menu(); ? ? do ? ? { ? ? ? ? scanf("%d", &a); ? ? ? ? switch (a) ? ? ? ? { ? ? ? ? case 1: ? ? ? ? ? ? game(); ? ? ? ? ? ? menu(); ? ? ? ? ? ? break; ? ? ? ? case 0: ? ? ? ? ? ? return 0; ? ? ? ? default: ? ? ? ? ? ? printf("\n進村還是不進?\n"); ? ? ? ? } ? ? } while (a); }
main()函數(shù)
int main() { ? ? int a = 0; ? ? menu(); ? ? do ? ? { ? ? ? ? scanf("%d", &a); ? ? ? ? switch (a) ? ? ? ? { ? ? ? ? case 1: ? ? ? ? ? ? game(); ? ? ? ? ? ? menu(); ? ? ? ? ? ? break; ? ? ? ? case 0: ? ? ? ? ? ? return 0; ? ? ? ? default: ? ? ? ? ? ? printf("\n進村還是不進?\n"); ? ? ? ? } ? ? } while (a); }
程序展示
mine.h
#pragma once #define ROW 15 #define COL 15 #define ROWS ROW+2 #define COLS COL+2 void init(char mine[ROWS][COLS], int rows, int cols, char type);//初始化數(shù)組 void setmine(char mine[ROWS][COLS], int count);//放置隨機雷 void display(char board[ROWS][COLS]);//顯示界面 int cal_mine(char mine[ROWS][COLS], int x, int y);//統(tǒng)計周圍雷的個數(shù) int player(char mine[ROWS][COLS], char board[ROWS][COLS],int count);//玩家操作 void expand(char mine[ROWS][COLS], char board[ROWS][COLS], int x, int y);//遞歸展開 int is_win(char board[ROWS][COLS]);//判斷勝利
mine.c
前文已展示定義
main.h
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<Windows.h> #include"mine.h" ? ? void game() ? ? { ? ? ? ? printf("歡\n"); Sleep(250); ? ? ? ? printf("迎\n"); Sleep(250); ? ? ? ? printf("來\n"); Sleep(250); ? ? ? ? printf("到\n"); Sleep(250); ? ? ? ? printf("caco\n"); Sleep(250); ? ? ? ? printf("的\n"); Sleep(250); ? ? ? ? printf("掃\n"); Sleep(250); ? ? ? ? printf("雷!\n"); Sleep(250); ? ? ? ? printf("村"); Sleep(250); ? ? ? ? printf("!"); Sleep(150); ? ? ? ? printf("!"); Sleep(150); ? ? ? ? char mine[ROWS][COLS] = { 0 }; ? ? ? ? char board[ROWS][COLS] = { 0 }; ? ? ? ? init(mine, ROWS, COLS, '0'); ? ? ? ? init(board, ROWS, COLS, '*'); ? ? ? ? int num = 0; ? ? ? ? printf("\n要幾個雷\n?"); ? ? ? ? scanf("%d", &num); ? ? ? ? setmine(mine, num); ? ? ? ? display(mine); ? ? ? ? int count = 1; ? ? ? ? int ret = 0; ? ? ? ? while (1) ? ? ? ? { ? ? ? ? ? ? display(board); ? ? ? ? ? ? ret = player(mine, board, count); ? ? ? ? ? ? count++; ? ? ? ? ? ? if (ret == num) ?//和玩家輸入得雷數(shù)要保持一致 ? ? ? ? ? ? { ? ? ? ? ? ? ? ? printf("炸不死得諾貝爾~!\n"); ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? } ? ? ? ? ? ? if (ret == 1) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? break; ? //表示直接菜到雷退出 ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? void menu() { ? ? printf("*******************************************\n"); ? ? printf("------ 我可以大口吞下炸彈而不傷身體--------\n"); ?//label 1. original test. ? ? printf("------1. ?進村 ? -------------------------\n-------------------------\n"); ? ? printf("------0. ?撤退! -------------------------\n"); ? ? printf("*******************************************\n"); } int main() { ? ? int a = 0; ? ? menu(); ? ? do ? ? { ? ? ? ? scanf("%d", &a); ? ? ? ? switch (a) ? ? ? ? { ? ? ? ? case 1: ? ? ? ? ? ? game(); ? ? ? ? ? ? menu(); ? ? ? ? ? ? break; ? ? ? ? case 0: ? ? ? ? ? ? return 0; ? ? ? ? default: ? ? ? ? ? ? printf("\n進村還是不進?\n"); ? ? ? ? } ? ? } while (a); }
程序運行
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++實現(xiàn)String與UF8互轉(zhuǎn)
這篇文章介紹了C++實現(xiàn)String與UF8互轉(zhuǎn)的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05一篇文章帶你入門C語言數(shù)據(jù)結(jié)構(gòu):緒論
這篇文章主要介紹了C語言的數(shù)據(jù)解構(gòu)基礎(chǔ),希望對廣大的程序愛好者有所幫助,同時祝大家有一個好成績,需要的朋友可以參考下,希望能給你帶來幫助2021-08-08獲取當(dāng)前系統(tǒng)本地時間,精確到毫秒的實例
下面小編就為大家?guī)硪黄@取當(dāng)前系統(tǒng)本地時間,精確到毫秒的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11