好姑娘中文在線觀看國語高清免費深圳白帽優(yōu)化
文接上一篇博文C語言:三子棋小游戲。本篇博文是使用C語言來實現(xiàn)掃雷小游戲的。這里不對掃雷的規(guī)則進行贅述。玩家通過鍵盤輸入坐標來探雷。博主在實現(xiàn)掃雷之前從未看過掃雷實現(xiàn)的相關視頻,所以這里實現(xiàn)的掃雷完全是博主的原生思路,具有邏輯性。下面詳細介紹一下如何實現(xiàn)掃雷。
(建議在閱讀過上一篇博文再閱讀本文,因為再本文中對重復的問題不會再次解讀。)
步驟一:制定框架
框架是什么?如何制定框架?這些問題在三子棋的實現(xiàn)中就已經(jīng)解答了,這里也不多講。這里的框架與三子棋的框架完全相同。
#include"detect.h"
int main()
{srand((unsigned)time(NULL));//這里設置了隨機種子,為了之后隨機生成雷int n = 0;do{menu();printf("your choice:\n");scanf("%d", &n);switch (n){case 1:system("cls");game();break;case 0:system("cls");printf("exit game\n");break;default:printf("input error,again:\n");Sleep(1000);system("cls");}} while (n);return 0;
}
menu是什么在三子棋實現(xiàn)中也提過,這里使用了Sleep函數(shù)(程序暫停運行多少毫秒)和system("cls")(清屏)是為了更好的游戲體驗。這里的detect.h代碼如下:
#pragma once
#define ROW 10
#define COL 10
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>
void menu();
void game();
步驟二:實現(xiàn)game函數(shù)
跟三子棋的game函數(shù)一樣,我們需要事先想好整個game的流程。
分析過程:既然有雷,我們需要將雷的位置記錄下來,那我們就需要一個字符二維數(shù)組,雷用大寫字符'O'表示,雷的位置就初始化為'O',其他位置為空格。另外,開局時我們一個地方都沒探測,我們難道要將帶雷的數(shù)組直接打印上去嗎?顯然這樣雷就直接被打印出來了。我們可以想到用第二個字符二維數(shù)組,里面初始時全是空格字符,這個數(shù)組是用來打印的。我們在這個數(shù)組中進行探測。
結束條件:如果探的是雷,那么直接宣告失敗,結束本次游戲;如果這一次避開了所有的雷,那么直接宣告成功,結束本次游戲;如果這一次沒探到雷而且沒有結束,那么顯示此處旁邊雷的個數(shù)
那我們怎么知道探出的是不是雷?其實很簡單,在數(shù)組一中此處如果是雷,說明這次探到雷了
下面是game的代碼
void game()
{char map1[ROW][COL] = { 0 };char map2[ROW][COL] = { 0 };mapInit(map1, ROW, COL);//真正存儲炸彈mapInit(map2, ROW, COL);//用來打印BoomInit(map1, ROW, COL);system("cls");showMap(map2, ROW, COL);while (1){int ret=playerMove(map1, map2, ROW, COL,ROW*COL/8);if (ret==1)//炸了{system("cls");showMap(map1, ROW, COL);printf("game over\n");system("pause");break;}else if (ret== 2)//排除了所有炸彈{system("cls");showMap(map1, ROW, COL);//展示所有炸彈位置printf("detect successfully\n");Sleep(2000);break;}system("cls");showMap(map2, ROW, COL);}
}
當然只是代碼還是很模糊的,下面依然需要對game中的各個部分進行講解。
map1:即數(shù)組一,用來存放炸彈的
map2:即數(shù)組二,用來打印的
ROW,COL:宏定義,這個宏定義在"detect.h"中,之前已經(jīng)給出
mapInit:用來初始化兩個數(shù)組,將兩個數(shù)組的每一個元素變成空格字符
BoomInit:用來將map1的隨機位置放上炸彈
showMap:將map2打印出來(連帶格子的線條,之后會詳細實現(xiàn))
playerMove:返回值為int類型,玩家在map2中的一個位置進行探測,如果在map1中相應位置是炸彈就返回1,避開所有炸彈就返回2,其他情況返回0;
?步驟三:實現(xiàn)game中的函數(shù)
?
?
void mapInit(char map[ROW][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){map[i][j] = ' ';}}
}//這個函數(shù)很簡單,不作講解
void BoomInit(char map[ROW][COL], int row, int col)
{int boomNum = row * col / 6;//6分之一是炸彈//設置炸彈進mapint curNum = 0;int x = 0;int y = 0;while (curNum != boomNum){x = rand() % row;y = rand() % col;if (map[x][y] == ' ')//如果是空格才能正常放入,如果已經(jīng)是炸彈就不放,重新生成一個坐標{map[x][y] = 'O';curNum++;}}
}void showMap(char map[ROW][COL], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){printf(" %c ", map[i][j]);if (j < col - 1)printf("|");}printf("\n");if (i < row - 1){for (int x = 0; x < col; x++){printf("---");if (x < col - 1)printf("|");}printf("\n");}//這一段其實是將畫格子線和棋子一并畫出,//需要自己動手操作一下才能明白這段代碼每一句是在做什么//不動手再怎么講都不會弄明白}
}
//warning函數(shù)是為了完成playerMove函數(shù)而寫的,請先看playerMove函數(shù)
char warning(char map[ROW][COL], int row, int col, int x, int y)
{int countBoom = 0;//最大為8,加上'0'變成字符for (int i = x - 1; i <= x + 1;i++){for (int j = y - 1; j <= y + 1; j++){if (i >= 0 && i <= row && j >= 0 && j <= col)//越界了就不判斷是不是雷{if (map[i][j] == 'O')countBoom++;}}}return countBoom +'0';
}
int playerMove(char map1[ROW][COL],char map2[ROW][COL], int row, int col,int boomNum)
{int x = 0;int y = 0;static count = 0;//靜態(tài)局部變量,記錄用戶一共開了幾個格子while (1){printf("input x:\n");scanf("%d", &x);printf("input y:\n");scanf("%d", &y);x--;y--;//用戶輸入的1就是第一個位置,數(shù)組下標就是0if (x < 0 || x >= row || y < 0 || y >= col || map2[x][y] != ' '){printf("wrong place,again\n");//非法坐標,重新輸入}else{break;//合法,退出循環(huán)}}//如果探到雷了,map2的該位置就改成'O',沒探到雷就顯示旁邊有幾個雷//這里的warning函數(shù)就是用來給出map1的相應位置旁邊有幾個雷,返回值是char類型map2[x][y] = map1[x][y]=='O'?'O':warning(map1,ROW,COL,x,y);if (map2[x][y] == 'O')return 1;//探到雷了,返回1else//判斷是否排除完{count++;if (count == col * row - boomNum){count = 0;//歸零,下一次進行游戲count還是從0開始計數(shù),否則count還是之前的值return 2;//避開了所有的雷,返回2}}return 0;//正常進行下一次探測,返回0
}??
?到這里為止,所有的工作就完成了,我們來看看效果
測試:

?配合清屏和睡眠函數(shù)效果還是不錯的,只是和原版的掃雷少了一個功能。我們知道,原版的掃雷在探到一個格子旁邊沒有一個炸彈時,也就這里實現(xiàn)的掃雷顯示'0'時,會自動將旁邊的格子顯示出來,只是這個功能實現(xiàn)起來有點困難。當時想過用遞歸解決這個問題,就是說如果map2中探到一個0雷格,將旁邊八個格子打開,如果這八個格子還有0雷格,就會進行遞歸,繼續(xù)將旁邊的格子打開,只是這樣會有一個問題,0雷格挨在一起的話會陷入死遞歸。個人感覺這個問題使用遞歸是最好解決的,之后想到了解決方案會更新博文。