您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關C語言中如何實現掃雷小游戲的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
游戲簡介
掃雷,是一款益智類小游戲。
游戲目標是找出所有沒有地雷的方格,完成游戲;要是按了有地雷的方格,游戲失敗;玩家可標記雷的位置。游戲以完成時間來評高低。有不同的游戲難度可選擇。
實現的功能介紹
1.計時
2.初始化雷盤
3.打印雷盤
4.隨機設置雷的分布,可選擇游戲難易程度
5.統計坐標位置周圍的雷數
6.第一次排雷不會被炸死
7.擴展式排雷,展開周圍的非雷區
8.給所選坐標位置做標記,或取消標記
該程序分為三個文件:
1.game.h :包含頭文件的引用、函數的聲明和宏定義
2.game.c :包含游戲各功能函數的具體實現
3.pro.c :各功能函數的調用(程序的流程)
PS:文章末尾附完整代碼 及 游戲效果圖
因為排雷時要計算每個位置周圍八個位置的雷數,所以在創建數組時要多一圈,即行列都要加2。給用戶顯示的數組不需要加。
游戲功能代碼詳解
1.計時
運用clock函數,該函數需要的頭文件為 “time.h”
函數原型:clock_t clock(void);
功能:程序從啟動到函數調用占用CPU的時間
這個函數返回從“開啟這個程序進程”到“程序中調用clock()函數”時之間的CPU時鐘計時單元(clock tick)數,在MSDN中稱之為掛鐘時間;若掛鐘時間不可取,則返回-1。其中clock_t是用來保存時間的數據類型。
void set_time()//計時 { printf("用時:%u 秒\n", clock() / CLOCKS_PER_SEC); }
2.初始化雷盤
這里我用到的是memset函數,需要的頭文件為“memory.h”或“string.h”
函數原型:void *memset(void *s, int ch, size_t n);
功能:將s中當前位置后面的n個字節 (typedef unsigned int size_t )用 ch 替換并返回 s 。在一段內存塊中填充某個給定的值。
void init_board(char board[ROWS][COLS], int row, int col, char c)//初始化雷盤 { memset(board, c, row*col*sizeof(board[0][0])); }
3.打印雷盤
運用兩個循環體實現雷盤數組的賦值、行號、列號的打印。正式游戲時可以加上system(“CLS”); 清屏語句,每次調用時都清屏一次,使游戲畫面更簡潔清晰。
我們把計時函數放在里面,每次打印雷盤時就可以顯示所用的時間。
void disp_board(char board[ROWS][COLS], int row, int col)//打印雷盤 { int i = 0; int j = 0; //system("CLS");//清屏 for (i = 0; i <= row; i++) { printf("%2d ", i);//打印行號 } printf("\n"); for (i = 1; i <= row; i++) { printf("%2d ", i);//打印列號 for (j = 1; j <= col; j++) { printf("%2c ", board[i][j]); } printf("\n"); } printf("\n"); set_time();//打印所用的時間 }
4.隨機設置雷的分布,可選擇游戲難易程度
放置雷必須是隨機的,這里用到了rand函數,它和srand函數配合使用產生隨機數。srand(time(NULL))放在主函數中調用一次,通過系統時間提供的種子值,使rand函數生成不同的偽隨機數序列。
void set_mine(char board[ROWS][COLS], int row, int col,int count)//置雷 { int x = 0; int y = 0; while (count) { x = rand() % row + 1;//隨機位置范圍1~row y = rand() % col + 1;//隨機位置范圍1~col if (board[x][y] == '0')//判斷是否已有雷 { board[x][y] = '1';//有雷的位置賦為1 count--; } } }
5.統計坐標位置周圍的雷數 及 未掃的位置的個數
當掃到一個沒有雷的位置時,會顯示這個位置周圍一圈八個位置的含雷的總數,所以我們要寫一個“數雷”函數來數。
int count_mine(char mine[ROWS][COLS], int x, int y)//數雷 { return mine[x - 1][y] + mine[x - 1][y + 1] + mine[x][y + 1] + mine[x + 1][y + 1] + mine[x + 1][y] + mine[x + 1][y - 1] + mine[x][y - 1] + mine[x - 1][y - 1] - 8 * '0';//數周圍一圈八個位置的雷數 } int count_print(char print[ROWS][COLS], int row, int col)//數未掃位置 { int count = 0; int i = 0; for (i = 1; i <= row; i++) { int j = 0; for (j = 1; j <= col; j++) { if (print[i][j] == '@' ||print[i][j] == '*') { count++; } } } return count; }
6.第一次排雷不會被炸死
為了增加游戲的可玩性,加入“第一次排雷不被炸死”這個函數。當第一次排就遇到雷時,我們把雷偷偷挪走,隨機放在一個原本無雷的位置。
void safe_mine(char mine[ROWS][COLS],char print[ROWS][COLS],int x,int y,int row,int col)//第一次排雷不炸死 { char ch = 0; int ret = 1; int number = 0; if (mine[x][y] == '1')//第一次踩到雷后補救 { mine[x][y] = '0'; char ch = count_mine(mine, x, y); print[x][y] = ch + '0';//數字對應的ASCII值和數字字符對應的ASCII值相差48,即'0'的ASCII值 extend_board(mine, print, x, y); while (ret)//在其余有空的地方設置一個雷 { int x = rand() % row + 1;//產生1到row的隨機數,在數組下標為1到10的范圍內布雷 int y = rand() % col + 1;//產生1到col的隨機數,在數組下標為1到10的范圍內布雷 if (mine[x][y] == '0')//找不是雷的地方布雷 { mine[x][y] = '1'; disp_board(print, row, col); //disp_board(mine, row, col); ret--; break; } } } }
7.擴展式排雷,展開周圍的非雷區
當游戲中排到一個周圍一圈都無雷的位置時,運用遞歸,實現擴展展開周圍的一片無雷區。
void extend_board(char mine[ROWS][COLS], char print[ROWS][COLS], int x, int y)//運用遞歸擴展周圍 { int n = 0; n = count_mine(mine, x, y); if (n == 0)//當該位置周圍雷數為0時擴展 { print[x][y] = ' ';//擴展的位置變為“空格”打印出來 if (mine[x - 1][y] == '0' && print[x - 1][y] == '@') { extend_board(mine, print, x - 1, y);//遞歸 } if (mine[x + 1][y] == '0' && print[x + 1][y] == '@') { extend_board(mine, print, x + 1, y); } if (mine[x][y + 1] == '0' && print[x][y + 1] == '@') { extend_board(mine, print, x, y + 1); } if (mine[x - 1][y + 1] == '0' && print[x - 1][y + 1] == '@') { extend_board(mine, print, x - 1, y + 1); } if (mine[x + 1][y + 1] == '0' && print[x + 1][y + 1] == '@') { extend_board(mine, print, x + 1, y + 1); } if (mine[x][y - 1] == '0' && print[x][y - 1] == '@') { extend_board(mine, print, x, y - 1); } if (mine[x + 1][y - 1] == '0' && print[x + 1][y -1] == '@') { extend_board(mine, print, x + 1, y - 1); } if (mine[x - 1][y - 1] == '0' && print[x - 1][y - 1] == '@') { extend_board(mine, print, x - 1, y - 1); } } else print[x][y] = n + '0'; } int find_mine(char mine[ROWS][COLS], char print[ROWS][COLS], int row, int col,int count)//排雷 { int x = 0; int y = 0; int number = 0; int ret = 0; while (1) { printf("輸入坐標掃雷\n"); scanf("%d%d", &x, &y);//玩家輸入掃雷的坐標位置 if ((x >= 1 && x <= row) && (y >= 1 && y <= col))//判斷輸入坐標是否有誤,輸入錯誤重新輸入 { if (mine[x][y] == '0')//沒踩到雷 { number++;//記錄掃雷的次數 char ch = count_mine(mine, x, y);//數雷數 print[x][y] = ch + '0';//數字對應的ASCII值和數字字符對應的ASCII值相差48,即'0'的ASCII值 extend_board(mine, print, x, y); disp_board(mine, row, col); disp_board(print, row, col); if (count_print(print, row, col) == count)//剩余未掃位置=雷數 時勝利 { return 0; } to_sign(print);//判斷是否標記 disp_board(print, row, col); } else if (mine[x][y] == '1')//踩到雷 { if (ret == 0 && number == 0) { ret++; safe_mine(mine,print,x,y,row,col); } else return 1; } } else { printf("輸入錯誤!請重新輸入\n"); } } }
8.給所選坐標位置做標記,或取消標記
掃雷游戲還有一個功能:可以給你認為是雷的位置標記,或者取消標記。
我通過三個函數來實現,一個判斷用戶是否需要標記;一個實現標記功能,將@標記成* ;一個實現取消標記功能,將* 改回@。
void to_sign(char board[ROWS][COLS])//判斷是否標記 { int chose_b = 0; int x = 0; int y = 0; printf("是否需要標記/取消標記:>\n(1.標記 ;2.取消標記 ;3.跳過該步驟) :>"); scanf("%d", &chose_b); do{ switch (chose_b) { case 1: { printf("請輸入需要標記的位置坐標:>\n"); scanf("%d%d", &x, &y); sign(board, x, y); break; } case 2: { printf("請輸入取消標記的位置坐標:>\n"); scanf("%d%d", &x, &y); unsign(board, x, y); break; } case 3: { printf("跳過此步驟。\n"); chose_b = 0; break; } default: { printf("輸入錯誤!\n"); chose_b = 0; break; } } chose_b = 0; } while (chose_b); } void sign(char board[ROWS][COLS], int x, int y)//用‘*'標記雷 { if (board[x][y] == '@') { board[x][y] = '*'; } } void unsign(char board[ROWS][COLS], int x, int y)//取消標記 { if (board[x][y] == '*') { board[x][y] = '@'; } }
附:完整代碼
game.h
#ifndef _GAME_H_ #define _GAME_H_ //用到的頭文件 #include<stdio.h> #include<stdlib.h> #include<time.h> #include<string.h> #include<windows.h> //定義打印的雷盤行、列 #define _ROW 9 #define _COL 9 #define ROW 16 #define COL 16 //定義數組的行、列 #define _ROWS _ROW+2 #define _COLS _COL+2 #define ROWS ROW+2 #define COLS COL+2 //定義難、易程度雷數 #define EASY_COUNT 10 #define HARD_COUNT 40 //定義游戲中的函數 void init_board(char board[ROWS][COLS],int row, int col, char c);//初始化 void disp_board(char board[ROWS][COLS],int row,int col);//打印 void set_mine(char board[ROWS][COLS], int row, int col,int count);//置雷 void safe_mine(char mine[ROWS][COLS], char print[ROWS][COLS], int x, int y, int row, int col);//第一次排雷不炸死 int find_mine(char mine[ROWS][COLS], char print[ROWS][COLS], int row, int col,int count);//排雷 int count_mine(char mine[ROWS][COLS], int x, int y);//數雷 void extend_board(char mine[ROWS][COLS], char print[ROWS][COLS], int x, int y);//擴展 void to_sign(char board[ROWS][COLS]);//判斷是否標記 void sign(char board[ROWS][COLS], int x, int y);//標記 void unsign(char board[ROWS][COLS], int x, int y);//取消標記 int count_print(char print[ROWS][COLS], int row, int col);//數未掃位置 #endif//_GAME_H_
game.c
#define _CRT_SECURE_NO_WARNINGS #include "game.h" void set_time()//計時 { printf("用時:%u 秒\n", clock() / CLOCKS_PER_SEC); } void init_board(char board[ROWS][COLS], int row, int col, char c)//初始化雷盤 { memset(board, c, row*col*sizeof(board[0][0])); } void disp_board(char board[ROWS][COLS], int row, int col)//打印雷盤 { int i = 0; int j = 0; system("CLS");//清屏 for (i = 0; i <= row; i++)//加行號 { printf("%2d ", i); } printf("\n"); for (i = 1; i <= row; i++)//加列號 { printf("%2d ", i); for (j = 1; j <= col; j++) { printf("%2c ", board[i][j]); } printf("\n"); } printf("\n"); set_time();//打印所用的時間 } void set_mine(char board[ROWS][COLS], int row, int col,int count)//置雷 { int x = 0; int y = 0; while (count) { x = rand() % row + 1;//隨機位置范圍1~row y = rand() % col + 1;//隨機位置范圍1~col if (board[x][y] == '0')//判斷是否已有雷 { board[x][y] = '1'; count--; } } } void safe_mine(char mine[ROWS][COLS],char print[ROWS][COLS],int x,int y,int row,int col)//第一次排雷不炸死 { char ch = 0; int ret = 1; int number = 0; if (mine[x][y] == '1')//第一次踩到雷后補救 { mine[x][y] = '0'; char ch = count_mine(mine, x, y); print[x][y] = ch + '0';//數字對應的ASCII值和數字字符對應的ASCII值相差48,即'0'的ASCII值 extend_board(mine, print, x, y); while (ret)//在其余有空的地方設置一個雷 { int x = rand() % row + 1;//產生1到row的隨機數,在數組下標為1到10的范圍內布雷 int y = rand() % col + 1;//產生1到col的隨機數,在數組下標為1到10的范圍內布雷 if (mine[x][y] == '0')//找不是雷的地方布雷 { mine[x][y] = '1'; disp_board(print, row, col); //disp_board(mine, row, col); ret--; break; } } } } int count_mine(char mine[ROWS][COLS], int x, int y)//數雷 { return mine[x - 1][y] + mine[x - 1][y + 1] + mine[x][y + 1] + mine[x + 1][y + 1] + mine[x + 1][y] + mine[x + 1][y - 1] + mine[x][y - 1] + mine[x - 1][y - 1] - 8 * '0';//數周圍一圈八個位置的雷數 } int count_print(char print[ROWS][COLS], int row, int col)//數未掃位置 { int count = 0; int i = 0; for (i = 1; i <= row; i++) { int j = 0; for (j = 1; j <= col; j++) { if (print[i][j] == '@' ||print[i][j] == '*') { count++; } } } return count; } void extend_board(char mine[ROWS][COLS], char print[ROWS][COLS], int x, int y)//運用遞歸擴展周圍 { int n = 0; n = count_mine(mine, x, y); if (n == 0)//當該位置周圍雷數為0時擴展 { print[x][y] = ' ';//擴展的位置變為“空格”打印出來 if (mine[x - 1][y] == '0' && print[x - 1][y] == '@') { extend_board(mine, print, x - 1, y);//遞歸 } if (mine[x + 1][y] == '0' && print[x + 1][y] == '@') { extend_board(mine, print, x + 1, y); } if (mine[x][y + 1] == '0' && print[x][y + 1] == '@') { extend_board(mine, print, x, y + 1); } if (mine[x - 1][y + 1] == '0' && print[x - 1][y + 1] == '@') { extend_board(mine, print, x - 1, y + 1); } if (mine[x + 1][y + 1] == '0' && print[x + 1][y + 1] == '@') { extend_board(mine, print, x + 1, y + 1); } if (mine[x][y - 1] == '0' && print[x][y - 1] == '@') { extend_board(mine, print, x, y - 1); } if (mine[x + 1][y - 1] == '0' && print[x + 1][y -1] == '@') { extend_board(mine, print, x + 1, y - 1); } if (mine[x - 1][y - 1] == '0' && print[x - 1][y - 1] == '@') { extend_board(mine, print, x - 1, y - 1); } } else print[x][y] = n + '0'; } int find_mine(char mine[ROWS][COLS], char print[ROWS][COLS], int row, int col,int count)//排雷 { int x = 0; int y = 0; int number = 0; int ret = 0; while (1) { printf("輸入坐標掃雷\n"); scanf("%d%d", &x, &y);//玩家輸入掃雷的坐標位置 if ((x >= 1 && x <= row) && (y >= 1 && y <= col))//判斷輸入坐標是否有誤,輸入錯誤重新輸入 { if (mine[x][y] == '0')//沒踩到雷 { number++;//記錄掃雷的次數 char ch = count_mine(mine, x, y);//數雷數 print[x][y] = ch + '0';//數字對應的ASCII值和數字字符對應的ASCII值相差48,即'0'的ASCII值 extend_board(mine, print, x, y); // disp_board(mine, row, col); disp_board(print, row, col); if (count_print(print, row, col) == count)//剩余未掃位置=雷數 時勝利 { return 0; } to_sign(print);//判斷是否標記 disp_board(print, row, col); } else if (mine[x][y] == '1')//踩到雷 { if (ret == 0 && number == 0) { ret++; safe_mine(mine,print,x,y,row,col); } else return 1; } } else { printf("輸入錯誤!請重新輸入\n"); } } } void sign(char board[ROWS][COLS], int x, int y)//用‘*'標記雷 { if (board[x][y] == '@') { board[x][y] = '*'; } } void unsign(char board[ROWS][COLS], int x, int y)//取消標記 { if (board[x][y] == '*') { board[x][y] = '@'; } } void to_sign(char board[ROWS][COLS])//判斷是否標記 { int chose_b = 0; int x = 0; int y = 0; printf("是否需要標記/取消標記:>\n(1.標記 ;2.取消標記 ;3.跳過該步驟) :>"); scanf("%d", &chose_b); do{ switch (chose_b) { case 1: { printf("請輸入需要標記的位置坐標:>\n"); scanf("%d%d", &x, &y); sign(board, x, y); break; } case 2: { printf("請輸入取消標記的位置坐標:>\n"); scanf("%d%d", &x, &y); unsign(board, x, y); break; } case 3: { printf("跳過此步驟。\n"); chose_b = 0; break; } default: { printf("輸入錯誤!\n"); chose_b = 0; break; } } chose_b = 0; } while (chose_b); }
pro.c
#define _CRT_SECURE_NO_WARNINGS #include "game.h" void menu() { printf("+---------------------------------+\n"); printf("+ Welcome to 掃雷世界 ! +\n"); printf("+ ο(=>ω<=)ρ⌒☆ +\n"); printf("+ 1、play +\n"); printf("+ 0、exit +\n"); printf("+---------------------------------+\n"); } void game() { char mine[ROWS][COLS] = { 0 }; char print[ROWS][COLS] = { 0 }; int chose_m = 0; int ret = 0; printf("請選擇模式(1、簡單 2、困難):>");//選擇游戲難易程度,產生不同大小的棋盤和雷數 scanf("%d", &chose_m); switch (chose_m) { case 1: { init_board(mine, ROWS, COLS, '0');//初始化雷盤 init_board(print, ROWS, COLS, '@'); set_mine(mine, _ROW, _COL, EASY_COUNT);//布雷 // disp_board(mine, _ROW, _COL);//打印雷盤 disp_board(print, _ROW, _COL); int ret = find_mine(mine, print, _ROW, _COL, EASY_COUNT);//掃雷,踩到雷返回1,沒有踩到雷返回0 while (1)//循環掃雷 { if (ret == 0)//若返回0則勝利 { disp_board(print, _ROW, _COL); printf("WOW~ YOU WIN!\n\n"); break; } if (ret)//若返回1則失敗 { disp_board(mine, _ROW, _COL);//打印雷盤 printf("GAME OVER!\n"); break; } disp_board(print, _ROW, _COL);//打印玩家棋盤 } break; } case 2: { init_board(mine, ROWS, COLS, '0');//初始化雷盤 init_board(print, ROWS, COLS, '@'); set_mine(mine, ROW, COL, HARD_COUNT);//布雷 // disp_board(mine, ROW, COL);//打印雷盤 disp_board(print, ROW, COL); while (1)//循環掃雷 { int ret = find_mine(mine, print, ROW, COL, HARD_COUNT);//掃雷,踩到雷返回1,沒有踩到雷返回0 if (ret == 0)//若返回0勝利 { disp_board(print, ROW, COL); printf("WOW~ YOU WIN!\n\n"); break; } if (ret)//若返回1失敗 { disp_board(mine, ROW, COL);//打印雷盤 printf("GAME OVER!\n"); break; } disp_board(print, ROW, COL);//打印玩家棋盤 } break; } default: { printf("輸入錯誤!\n"); break; } } } void text() { srand((unsigned int)time(NULL));//產生隨機值發生器 int chose = 0;//選擇是否開始游戲 do { menu();//菜單 printf("請選擇:>"); scanf("%d", &chose); switch (chose) { case 1: game();//開始游戲 break; case 0: printf("退出游戲\n"); break; default: printf("輸入錯誤,沒有該選項\n"); break; } } while (chose); } int main() { text(); system("pause"); return 0; }
游戲效果圖
①開始選擇菜單、難易模式選擇
②兩種難度掃雷
↓9×9雷盤 10顆雷
↓16×16雷盤 40顆雷
③演示標記
④GAME OVER 玩家失敗演示
⑤WIN 玩家成功演示
感謝各位的閱讀!關于“C語言中如何實現掃雷小游戲”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。