C语言——扫雷游戏详解
1.關于掃雷游戲的介紹
首先如果我們要實現掃雷游戲的話,要明白掃雷游戲是如何運行的!
這里是一個網頁版的掃雷游戲的鏈接,可以先玩一下,這樣可以對我們實現掃雷游戲的代碼有非常大的幫助!
掃雷游戲網頁版 - Minesweeper
2.關于掃雷游戲原理的介紹
a.
?根據上面三張圖我們可以了解到,對于掃雷游戲我們每次可以進行的操作是,對相關點進行標記或者對相關點進行清掃。
b.而對該點進行清掃的話,又會有兩中情況發生,其一是如果該點是雷,哇,金色傳說!恭喜你,被雷炸死了!其二,就是如果該點不是雷,那么將返回該點周圍一圈八個點的雷數,如果該點周圍沒有雷,那么將對大量無雷點進行地毯式清掃。
c.那么我們要清掃的點如果是非雷點我們要怎樣去實現返回該點附近的雷數呢!
? 在這里我所用的方法是用兩個二維數組去實現的,一個是數組是用來布雷的,而另一個是用來返回非雷點附近的雷數的
3.掃雷游戲相關代碼的實現
a.掃雷游戲的菜單界面
?做為一個游戲程序,我們在游戲開始前當然要詢問玩家是否要開始進行游戲!
#pragma once#include<stdio.h> #include<stdlib.h> #include<time.h> #define ROWS 11 #define COLS 11 #define row 9 #define col 9 #define quantity 10void menu(); //游戲菜單 void mine_clearance_game(); //游戲程序 void Initmine(char [][COLS], int, int, char); //對雷區初始化 void Displaymine(char[][COLS], int, int); //打印雷區 void Thunder_release(char[][COLS], int, int); //放雷 int mine_clearance(char[][COLS], char [][COLS], int, int); //掃雷 int thunder_number(char[][COLS], int, int); //計算該點附近的雷數 int judge(char [][COLS], int, int); //返回已掃點的個數 void flag(char [][COLS], int, int); //對雷區做標記 void menu1(); void mine_clearance1(char[][COLS], char[][COLS], int, int); //掃雷并平鋪 void Tile(char[][COLS], char[][COLS], int, int);上面的代碼段是掃雷游戲的頭文件
#include"mine_clearance.h"int main(void) {int value = 0;srand((unsigned)time(NULL));do{printf("是否要玩掃雷玩家請做出你的選擇:\n");menu();scanf("%d",&value);switch (value){case 1:mine_clearance_game();break;case 0:printf("程序退出!\n");break;default:printf("您輸入錯誤請重新輸入:\n");break;}} while (value);return 0; } void menu() {printf("***********************************\n""************ 1.play ************\n""************ 0.exit ************\n""***********************************\n""***********************************\n"); }?在主函數中我們首先聲明了一個名為value的int類型的變量用來介紹玩家做出的選擇是1還是0,然后,接著就是調用srand()庫函數,初始化隨機數的生成器,然后是,do{}while循環讓玩家先進菜單界面,通過switch多重選擇結構來實現對play還是exit的選擇,當然玩家只可以在1或0之間選擇如果玩家輸入其他的數值,將重新輸入!
當玩家選擇0就會退出程序!
b.掃雷游戲的進行
void mine_clearance_game() {char mine[ROWS][COLS] = { 0 };char mine1[ROWS][COLS] = { 0 };Initmine(mine, row, col, '0');Initmine(mine1, row, col, '*');//Displaymine(mine, row, col);system("cls");Displaymine(mine1, row, col);Thunder_release(mine, row, col);Displaymine(mine, row, col);int input = 0;int flagf = 1;while (flagf){system("cls");Displaymine(mine1, row, col);//Displaymine(mine, row, col);printf("玩家請你做出選擇:\n");menu1();scanf("%d",&input);if (input){system("cls");flagf=mine_clearance(mine, mine1, row, col);}else{system("cls");flag(mine1, row, col);}}//mine_clearance1(mine, mine1, row, col); }?當玩家選擇1后,程序的執行將進入mine_clearance_game()函數中,首先創建雷陣mine和雷陣mine1兩個都為char類型的二維數組,然后調用Initmine()函數實現對兩個雷陣的初始化,放雷陣均初始話為字符0,反數陣均初始化為字符*
void Initmine(char mine[][COLS], int a, int b, char get) {int i = 0;int j = 0;for (i = 0; i < ROWS; i++){for (j = 0; j < COLS; j++){mine[i][j] = get;}} }Displaymine()函數是對數組的打印
void Displaymine(char mine[][COLS], int a, int b) {printf("- - - - 掃雷 - - - -\n");int i = 0;int j = 0;for (i = 0; i <= a; i++){printf("%d ",i);}printf("\n");for (i = 1; i <= a; i++){printf("%d ", i);for (j = 1; j <= b; j++){printf("%c ",mine[i][j]);}printf("\n");} }Thunder_release()函數是在雷陣中放置雷
void Thunder_release(char mine[][COLS], int a, int b) {int x = 0;int y = 0;int n = quantity;while (n > 0){x = rand() % a+1;y = rand() % b+1;if (mine[x][y] == '0'){mine[x][y] = '1';n--;}} }rand()函數是生成一個隨機數,然后我們對這個隨機數進行求模運算在加1就會得到1到a的數值quantity是一個字符常量值為要放置的雷數;
然后接著就是while循環,在循環中讓玩家做出選擇要標記點還是要清掃點
void menu1() {printf("***********************************\n""************ 1.mine_clearance **\n""************ 0.flag ************\n""***********************************\n""***********************************\n"); }選擇1是進行清掃點
int mine_clearance(char mine[][COLS],char mine1[][COLS], int a, int b) {int x = 0;int y = 0;int count = 0;int number = 0;int input = 0;while (number<a*b- quantity){system("cls");Displaymine(mine1, row, col);printf("玩家請做出選擇:\n");scanf("%d %d", &x, &y);if (mine[x][y] == '1'&&mine1[x][y]=='*'){system("cls");printf("該點有雷你被炸死了!\n");Displaymine(mine, row, col);return 0;}else if(mine1[x][y]=='*'){count = thunder_number(mine, x, y);mine1[x][y] = count + '0';system("cls");Displaymine(mine1, row, col);}else if(mine1[x][y]==' '){system("cls");printf("這個是標記點不可被清掃,請重新輸入:\n");continue;}else{printf("給點已經被你掃的很干凈了,請你掃一掃其他點吧,求求了!\n");continue;}number = judge(mine1, a, b);if (number < a * b - quantity){system("cls");Displaymine(mine1, row, col);printf("玩家你是否還要繼續掃雷:\n");menu();scanf("%d", &input);if (!input){break;}}}if (number == a * b - quantity){printf("你完成了掃雷!\n");return 0;}return 1; } int thunder_number(char mine[][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] -8 * '0'; } int judge(char mine[][COLS], int a, int b) {int i = 0;int j = 0;int sum = 0;for (i = 1; i <=a; i++){for (j = 1; j <=b; j++){if (mine[i][j] != '*'){sum++;}}}return sum; }注意在掃雷過程中要注意該點是不是標記點,且已經清掃過的點就不需要在清掃了,這里返回的是int類型的值,對flags的值進行改變,當return 1說明玩家可以繼續進行掃雷游戲,return 0說明玩家不是被炸死了就是玩家贏得了掃雷游戲的勝利!
選擇0是進行標記
void flag(char mine1[][COLS], int a, int b) {int x = 0;int y = 0;static int number = 0;int input = 0;while (number<= quantity){Displaymine(mine1, row, col);printf("玩家請你做出標記:\n");scanf("%d %d", &x, &y);if (mine1[x][y] == '*'){mine1[x][y] = ' ';number++;Displaymine(mine1, row, col);}else{system("cls");printf("該點已被清掃不可在被標記,請重新標記:\n");continue;}system("cls");Displaymine(mine1, row, col);printf("玩家你是否還要做標記:\n");menu();scanf("%d",&input);if (!input){break;}} }此時我們的掃雷游戲簡單版就完成了!下面是運行實例圖
?
c.遞歸實現返回數并平鋪
?
?用遞歸來解決問題時,是將問題由大變小細化,然后一步一步先解決小的問題在解決大的問題,在用遞歸處理問題時主要是尋找問題的大模塊和小模塊之間的粘連性,找到了粘連性也就找到了用遞歸處理問題的關鍵!
而對于本問題,當該點不是雷且該點周圍的八個點的雷數為0,那么就進行平鋪清掃!
當然對于要清掃的點最關鍵的還是返回該點周圍八個點的雷數,那么對于平鋪清掃這個問題的用遞歸處理的時,該問題的粘連性是什么呢?
就像往一個平面倒水一樣,水要覆蓋地面,前提是該點上無物體,就相當于我們要有清掃一個點,這個點的周圍沒有雷那么文件要繼續對周圍的點進行清掃,直到有雷點,
這里要注意原清掃點不可以再被清掃,否則就無法出遞歸了,還有在遞歸的時候要注意不能發生數組下標的越界!
?
?在這里有一個問題就是如果雷數過少,代碼就會出錯誤,因為遞歸每次都是開辟新的存儲空間,如果雷數過少就會發生棧溢出,就像這樣,如果雷數為0,程序進行就是如圖
當雷數調為20
?
總結
以上是生活随笔為你收集整理的C语言——扫雷游戏详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java学习笔记之JDBC和连接池
- 下一篇: 东风小康为什么是dfsk_助力地摊经济瑞