C語言小游戲掃雷實現

      網友投稿 859 2022-05-28

      掃雷的介紹

      掃雷就是要把所有非地雷的格子揭開即勝利;踩到地雷格子就算失敗。 游戲主區域由很多個方格組成。 使用鼠標左鍵隨機點擊一個方格,方格即被打開并顯示出方格中的數字;方格中數字則表示其周圍的8個方格隱藏了幾顆雷。

      部分效果展示

      游戲實現

      開始準備

      C語言小游戲:掃雷實現

      開始界面

      我們可以首先打印菜單,提醒玩家是否開始游戲,通過while循環控制,可以達到一次玩完不過癮還能接著玩的目的

      int main() { int input = 0; do { menu(); printf("請選擇:>"); scanf("%d", &input); switch (input) { case 1: printf("游戲開始!\n"); game();//封裝的游戲主體,后文介紹 break; case 0: printf("退出游戲\n"); system("pause"); break; default: printf("選擇錯誤,重新選擇!\n"); break; } } while (input); return 0; }

      菜單函數如下

      void menu() { printf("*********************************\n"); printf("*****歡迎游玩掃雷游戲!**********\n"); printf("*****made by 東條希爾薇**********\n"); printf("*******1. play***************\n"); printf("*******0. exit***************\n"); printf("*********************************\n"); }

      打印效果如下

      初始化棋盤

      我們在這里需要定義兩個二維數組,一個數組用于展示給玩家,并儲存排雷信息,一個數組用于在后臺隨機生成雷并儲存。用兩個數組儲存可以有效的防止排雷過程中產生的歧義(例如,把雷設為‘1’,那么就不清楚‘1’到底是給玩家的提示還是放置的雷)。

      當然,我們最好將雷設為‘1’,至于為什么這樣設置,見下文

      void make_board(char board[ROWS][COLS], int rows, int cols, char set) { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { board[i][j] = set; } } }

      在初始化的時候

      char show[ROWS][COLS];//ROWS已經在#define中定義為11,ROW,已定義為9 char mine[ROWS][COLS]; make_board(show, ROWS, COLS, '*');//將*設置為不知道信息的區域 make_board(mine, ROWS, COLS, '0');//0來初始化,設為非雷區

      我們模擬的是簡單模式的99,那為什么要把數組初始化為1111的呢?

      為了防止數組越界

      畫圖示意

      打印棋盤

      我們只需要打印中間的9*9區域即可,而且只需要打印show數組,存儲雷的數組不需要顯示給玩家

      void display_board(char board[ROWS][COLS], int rows, int cols) { int i = 0; int j = 0; for (i = 0; i < rows-1; i++)//打印行數,方便玩家操作 { printf("%d ", i); } printf("\n"); for (i = 1; i < rows - 1; i++) { printf("%d ", i);//打印列數 for (j = 1; j < cols - 1; j++) { printf("%c ", board[i][j]); } printf("\n"); } }

      效果如下

      隨機生成雷

      我們可以使用stdlib.h中的rand函數來隨機生成雷的坐標,為了能保證每次游戲的隨機生成結果不同,可以在main函數中使用srand和time函數。

      void set_mine(char board[ROWS][COLS], int row, int col) { int count = COUNT;//COUNT已用#define定義,方便后期維護,使用簡單難道的雷數 while (count) { int x = rand() % row + 1; int y = rand() % col + 1; if (board[x][y] != '1') { board[x][y] = '1'; count--;//只有在坐標沒被占用時才會放置,防止最后生成的雷數小于10個 } } }

      準備工作分界線

      排雷過程

      排雷函數主體

      需要玩家選擇排雷的坐標,并將該坐標周圍的信息反饋給玩家,當然,玩家可能會不慎選擇不合法的坐標,所以可以通過循環讓玩家反復選擇,直到選擇到合法的坐標為止

      void find_mine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count1 = 0; while (1) { printf("請選擇要排的坐標\n"); scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col)//合法的坐標范圍 { if (mine[x][y] == '1') { printf("很遺憾,你被炸死了!\n");//玩家踩到雷了 display_board(mine, ROWS, COLS); system("pause"); break; } else { if (show[x][y] != '*') { printf("坐標被占用!重新輸入\n");//玩家輸入的坐標已經被開過了 } else { open_board(mine,show, ROW, COL, x, y);//后文會提到的信息函數 display_board(show, ROWS, COLS);//將每次更新的信息呈現給玩家 printf("你是否需要標記?1是 or 0否\n");//后文將會提到的標記函數 int ret = 0; scanf("%d", &ret); if (ret == 1) { printf("開始標記\n"); count1 = flag(mine, show, row, col); if (count1 == COUNT) { printf("恭喜,你贏了!\n"); break; } } else printf("繼續\n"); } } } else { printf("坐標非法!重新輸入!\n");//輸入坐標超出棋盤范圍 } } }

      信息函數

      這里我們使用了函數的遞歸,可以實現以下的效果,能有效防止反復操作的問題

      void open_board(char mine[ROWS][COLS], char show[ROWS][COLS],int row,int col,int x,int y) { if (x >= 1 && x <= row && y >= 1 && y <= col) { if (show[x][y] == ' ') { return;//遞歸的停止條件 } else if (count_mine(mine, x, y) != 0)//判斷周圍是否有雷,不用直接遍歷判斷,有就呈現信息 { show[x][y] = count_mine(mine, x, y) + '0';//后文提到的計算雷數的函數 } else { show[x][y] = ' ';//標記,防止重復調用,造成遞歸死循環 for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { open_board(mine, show, row, col, i, j);//查看以該坐標中心的周圍8格區域 } } } } }

      計算周圍雷數的函數

      這里將‘1’設為雷的優越性就體現出來了。

      可以直接把‘1’減去字符0,將其轉化為數字相加,在呈現信息的時候再加上‘0’轉化為字符。

      int count_mine(char mine[ROWS][COLS], int x, int y) { int count = 0; for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { count += (mine[i][j] - '0'); } } return count; }

      呈上效果圖

      雷區標記函數

      我們可以模擬掃雷游戲中的標記功能,供玩家標記他們認為有可能有雷的坐標,當然,如果標記錯了,可以隨時取消

      int flag(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int input = 0; int count = 0; int x = 0; int y = 0; do { printf("請標記你認為的雷的位置,輸入已經標記的坐標已取消\n"); scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col)//判斷坐標是否合法 { if (show[x][y] == '*') { show[x][y] = '$';//用$作為旗幟標記 for (int i = 1; i <= row; i++) { for (int j = 1; j <= col; j++) { if (show[i][j] == '$' && mine[i][j] == '1') { count++;//下文提到的判斷輸贏的方式 } } } display_board(show, ROWS, COLS);//每次標記完后打印棋盤 } else if (show[x][y] == '$') { show[x][y] = '*';//實現取消標記的功能 } else { printf("坐標被占用!\n");//坐標已經被開過或者已經被標記過 } } else { printf("坐標非法,重新輸入!\n"); } printf("是否繼續?1是 or 0否\n"); scanf("%d", &input); } while (input);//可以讓玩家一直標記,直到玩家主動停止標記 return count; }

      判斷輸贏

      我們上文中的flag函數有個返回值,返回show數組中的旗幟$和mine數組中的雷重合的個數,判斷,如果重合個數等于了COUNT就判斷贏了,如果踩到雷,就判斷輸了

      count1 = flag(mine, show, row, col); if (count1 == COUNT) { printf("恭喜,你贏了!\n"); break; } if (mine[x][y] == '1') { printf("很遺憾,你被炸死了!\n"); display_board(mine, ROWS, COLS); system("pause"); break; }

      為了驗證我們邏輯的正確性,將雷數設置為1,來測試一下我們的小游戲

      完整代碼實現

      main.c文件

      #include"game.h" void game() { char show[ROWS][COLS]; char mine[ROWS][COLS]; make_board(show, ROWS, COLS, '*'); make_board(mine, ROWS, COLS, '0'); set_mine(mine, ROW, COL); display_board(show, ROWS, COLS); //display_board(mine, ROWS, COLS); find_mine(show, mine, ROW, COL); } int main() { srand((unsigned int)time(NULL)); int input = 0; do { menu(); printf("請選擇:>"); scanf("%d", &input); switch (input) { case 1: printf("游戲開始!\n"); game(); break; case 0: printf("退出游戲\n"); system("pause"); break; default: printf("選擇錯誤,重新選擇!\n"); break; } } while (input); return 0; }

      game.c文件

      #include"game.h" void menu() { printf("*********************************\n"); printf("*****歡迎游玩掃雷游戲!**********\n"); printf("*****made by 東條希爾薇**********\n"); printf("*******1. play***************\n"); printf("*******0. exit***************\n"); printf("*********************************\n"); } void make_board(char board[ROWS][COLS], int rows, int cols, char set) { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { board[i][j] = set; } } } void display_board(char board[ROWS][COLS], int rows, int cols) { int i = 0; int j = 0; for (i = 0; i < rows-1; i++) { printf("%d ", i); } printf("\n"); for (i = 1; i < rows - 1; i++) { printf("%d ", i); for (j = 1; j < cols - 1; j++) { printf("%c ", board[i][j]); } printf("\n"); } } void set_mine(char board[ROWS][COLS], int row, int col) { int count = COUNT; while (count) { int x = rand() % row + 1; int y = rand() % col + 1; if (board[x][y] != '1') { board[x][y] = '1'; count--; } } } void find_mine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int count1 = 0; while (1) { printf("請選擇要排的坐標\n"); scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) { if (mine[x][y] == '1') { printf("很遺憾,你被炸死了!\n"); display_board(mine, ROWS, COLS); system("pause"); break; } else { if (show[x][y] != '*') { printf("坐標被占用!重新輸入\n"); } else { open_board(mine,show, ROW, COL, x, y); display_board(show, ROWS, COLS); printf("你是否需要標記?1是 or 0否\n"); int ret = 0; scanf("%d", &ret); if (ret == 1) { printf("開始標記\n"); count1 = flag(mine, show, row, col); if (count1 == COUNT) { printf("恭喜,你贏了!\n"); break; } } else printf("繼續\n"); } } } else { printf("坐標非法!重新輸入!\n"); } } } int count_mine(char mine[ROWS][COLS], int x, int y) { int count = 0; for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { count += (mine[i][j] - '0'); } } return count; } int flag(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int input = 0; int count = 0; int x = 0; int y = 0; do { printf("請標記你認為的雷的位置,輸入已經標記的坐標已取消\n"); scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) { if (show[x][y] == '*') { show[x][y] = '$'; for (int i = 1; i <= row; i++) { for (int j = 1; j <= col; j++) { if (show[i][j] == '$' && mine[i][j] == '1') { count++; } } } display_board(show, ROWS, COLS); } else if (show[x][y] == '$') { show[x][y] = '*'; } else { printf("坐標被占用!\n"); } } else { printf("坐標非法,重新輸入!\n"); } printf("是否繼續?1是 or 0否\n"); scanf("%d", &input); } while (input); return count; } void open_board(char mine[ROWS][COLS], char show[ROWS][COLS],int row,int col,int x,int y) { if (x >= 1 && x <= row && y >= 1 && y <= col) { if (show[x][y] == ' ') { return; } else if (count_mine(mine, x, y) != 0)//判斷周圍是否有雷,不用直接遍歷判斷 { show[x][y] = count_mine(mine, x, y) + '0'; } else { show[x][y] = ' ';//標記,防止重復調用 for (int i = x - 1; i <= x + 1; i++) { for (int j = y - 1; j <= y + 1; j++) { open_board(mine, show, row, col, i, j); } } } } }

      game.h文件

      #pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include #include #include #include #define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 #define COUNT 10 void menu(); void make_board(char board[ROWS][COLS], int rows, int cols, char set); void display_board(char board[ROWS][COLS], int rows, int cols); void set_mine(char board[ROWS][COLS], int row, int col); void find_mine(char show[ROWS][COLS], char mine[ROWS][COLS], int row, int col); int count_mine(char mine[ROWS][COLS], int x, int y); void open_board(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,int x,int y); int flag(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);

      C 語言

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:【2018華為云技術私享會成果分享-西安站】SQL Server上云最佳實踐
      下一篇:android如何提升性能技巧(下)
      相關文章
      2020天堂在线亚洲精品专区| 亚洲午夜久久久精品电影院| 亚洲一区AV无码少妇电影| 亚洲成人高清在线观看| 亚洲成a人片7777| 亚洲国产中文在线视频| 18亚洲男同志videos网站| 亚洲国语精品自产拍在线观看| 亚洲av无码不卡| 亚洲AV第一页国产精品| 久久伊人久久亚洲综合| 午夜亚洲www湿好大| 亚洲天堂中文字幕| 亚洲欧洲综合在线| 亚洲综合久久一本伊伊区| 亚洲а∨天堂久久精品9966| 亚洲中文字幕乱码AV波多JI| 亚洲一日韩欧美中文字幕在线| 亚洲一日韩欧美中文字幕在线| 亚洲精品宾馆在线精品酒店| 久久无码av亚洲精品色午夜| 亚洲国产成人久久一区久久| 亚洲美女在线国产| 亚洲精品无码乱码成人| 亚洲Av无码精品色午夜| 亚洲系列国产精品制服丝袜第| 亚洲区视频在线观看| 亚洲综合在线一区二区三区| 精品国产亚洲AV麻豆| 亚洲人成无码网站久久99热国产| 在线亚洲97se亚洲综合在线| 亚洲av女电影网| 亚洲国产精品乱码在线观看97| 99热亚洲色精品国产88| 国产精品久久久久久亚洲影视| 亚洲精品视频久久久| 亚洲国产精品成人久久 | 久久久久亚洲AV无码观看| 亚洲二区在线视频| 亚洲国产欧美日韩精品一区二区三区 | 亚洲日韩v无码中文字幕|