編程實現(xiàn)一個掃雷機器人_第1頁
編程實現(xiàn)一個掃雷機器人_第2頁
編程實現(xiàn)一個掃雷機器人_第3頁
編程實現(xiàn)一個掃雷機器人_第4頁
編程實現(xiàn)一個掃雷機器人_第5頁
已閱讀5頁,還剩13頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、編程實現(xiàn)一個掃雷機器人一、課題內(nèi)容和要求在一個20*20的地圖上,分布著81顆地雷,掃雷機器人走到其中一個方格上,如果是地雷,它將被炸死,如果不是,它可以探測到它周圍的八個方格中有幾個地雷?,F(xiàn)在你擁有10個掃雷機器人(10次錯誤機會),請你將這片雷區(qū)中的所有地雷標出來。二、需求分析(1)規(guī)則描述 游戲開始時,系統(tǒng)會在雷區(qū)的某些小方塊中隨機布下81顆雷,部署完畢后,系統(tǒng)會在其他非雷方塊中填充一些數(shù)字,某一個具體數(shù)字表示預(yù)期緊鄰的8個方塊中有多少雷方塊,玩家可以可以根據(jù)這些信息去判斷是否可以打開某些方塊,并把認為是地雷的方塊打上標記,當(dāng)玩家將所有地雷找出后,其余的非雷方塊區(qū)域都已打開,此時游戲勝利

2、結(jié)束,在游戲過程中,一旦錯誤地打開了雷方塊10次以上,游戲結(jié)束。(2)功能需求分析此掃雷機器人游戲是一個交互式的游戲,它的開發(fā)需滿足的要求包括以下幾個部分:一部分是此游戲界面需要在20*20的界面上實現(xiàn),并規(guī)定雷數(shù)為81顆,第二部分是實現(xiàn)掃雷要求,即掃雷機器人走到其中一個方格上,如果是地雷,它將被炸死,如果不是,它可以探測到它周圍的八個方格中有幾個地雷,該部分包括進行某種操作判斷某區(qū)域是否是雷,如果是雷該如何操作,如果不是雷該如何操作,判斷某區(qū)域是雷則如何加以標記,以及點擊某區(qū)域時,判斷與該區(qū)域相鄰的其它8個區(qū)域是否是雷并做一個標記。第三部分是此掃雷機器人有10次錯誤機會。(3)功能模塊需求分

3、析程序設(shè)計過程中涉及到的功能模塊函數(shù):1函數(shù):static int TextOut(const char* pstr ); 功能要求:在當(dāng)前位置輸出字符串,本程序根據(jù)各種操作,定義的字符串分別為"ArrowKey:MoveCursor Key1:Open Key2:Mark Key3:OpenNeighbors"代表程序標題、Congratulations! You Win! Thank you for playing!代表游戲獲勝、Game Over, thank you for playing!代表游戲失敗、Presented by 1803 . Press ESC t

4、o exit代表退出。2函數(shù):  static int GotoXY(int x , int y );功能要求:光標移至(x,y)處并得到此光標位置。3函數(shù):static int CharOut(int x, int y, const int pstr);功能要求:在(x,y)處輸出一字符。4函數(shù):static int TextOut(int x, int y, const char* pstr);功能要求:由任意位置移到(x,y)并在當(dāng)前位置輸出字符串5函數(shù):static int GetKey(); 功能要求:等待鍵1、2、3的輸入并返回此值。6函數(shù):int InitPool(in

5、t Width, int Height, int nBoom);功能要求:初始化游戲環(huán)境。 7函數(shù):int DrawPool(int bDrawBoom = 0);功能要求:根據(jù)各區(qū)域內(nèi)容輸出字符串 、 *、 #、 .。8. 函數(shù):int WaitMessage( );功能要求:根據(jù)各種輸入KEY_UP、 KEY_DOWN、 KEY_LEFT、 KEY_RIGHT、 KEY_1、 KEY_2 、KEY_3、 KEY_ESC執(zhí)行操作,通過返回的nRT來判斷失敗、勝利或未結(jié)束。9. 函數(shù):int GetShowNum(int x, int y);功能要求:確定認一點(x,y)和它周圍8個方向的總雷

6、數(shù),并把雷的數(shù)目顯示出來。10. 函數(shù):int TryOpen(int x, int y); 功能要求:打開點(x,y)并顯示雷數(shù)號碼,必須實現(xiàn)10次機會錯誤這一功能要求,若超出10次而未找出全部雷數(shù),則將游戲界面上的所有雷顯示出來(即返回EOF)。11. 函數(shù):int DFSShowNum(int x, int y);功能要求:在游戲界面范圍內(nèi),先通過調(diào)用函數(shù)int GetShowNum(int x, int y)獲得任意一點周圍的總雷數(shù),若為0,則通過遞歸調(diào)用直至將獲得的雷數(shù)顯示出來。 四、概要設(shè)計整體游戲流程圖:游戲開始執(zhí)行操作雷區(qū)GAME OVER判斷非雷區(qū)程序使用了面向?qū)ο?/p>

7、的方法,首先創(chuàng)建工程項目,本程序基于Win32 Console Application.程序定義了窗口類class CConsoleWnd和類模塊class CSLGame , 類中成員變量和成員函數(shù)原型聲明分別如下:(1).class CConsoleWnd public: static int TextOut(const char*); static int GotoXY(int, int); static int CharOut(int, int, const int); static int TextOut(int, int, const char*); static int GetK

8、ey(); ;(2).class CSLGame:public CConsoleWnd private: int curX,curY; int poolWidth,poolHeight; int bm_gamepoolGAME_MAX_HEIGHT+2GAME_MAX_WIDTH+2; public: CSLGame():curX(0),curY(0)poolWidth=poolHeight=0; int InitPool(int, int, int); int MoveCursor()return CConsoleWnd:GotoXY(curX, curY); int DrawPool(in

9、t); int WaitMessage(); int GetShowNum(int, int); int TryOpen(int, int); private: int DFSShowNum(int, int); private: const static int GMARK_BOOM; const static int GMARK_EMPTY; const static int GMARK_MARK;const int CSLGame:GMARK_BOOM = 0x10;const int CSLGame:GMARK_EMPTY= 0x100;const int CSLGame:GMARK_

10、MARK = 0x200;#define KEY_UP 0xE048#define KEY_DOWN 0xE050#define KEY_LEFT 0xE04B#define KEY_RIGHT 0xE04D#define KEY_ESC 0x001B#define KEY_1 '1'#define KEY_2 '2'#define KEY_3 '3'#define GAME_MAX_WIDTH 100#define GAME_MAX_HEIGHT 100算法設(shè)計包括:1 隨機布雷可以隨即獲取一個狀態(tài)為非雷的點,將它的屬性標志為雷,重復(fù)這樣的工作

11、直到將81顆雷布完。流程圖如下:是開始生成隨機的雷方塊的坐標(x,y)判斷(x,y)區(qū)域是否已經(jīng)布下雷在(x,y)區(qū)域布雷,修改狀態(tài)數(shù)據(jù)判斷是否布下所有雷結(jié)束否否是設(shè)數(shù)組bm_gamepoolyx為地雷標志數(shù)組,若此數(shù)組恒為0,則標志為雷,Windows的API有這樣的一種機制,可以生成隨機函數(shù)。先用strand()函數(shù)產(chǎn)生并返回隨機種子,可以利用系統(tǒng)的時間作為隨機數(shù)產(chǎn)生的種子,而產(chǎn)生的隨機數(shù)實際上是偽隨機數(shù),它的產(chǎn)生是根據(jù)遞推公式計算的一組數(shù)組,即int x = rand()%Width + 1, y = rand()%Height + 1,當(dāng)序列長度滿足81時,這組數(shù)值近似滿足均勻分布。2

12、. 做雷陣,即雷數(shù)目的計算和顯示在沒有雷的地方點擊后就會顯示一個數(shù)字表示它周圍有幾個雷,這是怎么實現(xiàn)的呢?我們可以把整個雷區(qū)看成一個二維數(shù)組bm_gamepoolyx,假如雷區(qū):  11  12  13  14  15  16  17  18 21  22  23  24  25  26  27  28 31  32  33  34  35  36  37 

13、 38 41  42  43  44  45  46  47  48 51  52  53  54  55  56  57  58我要知道a34周圍有幾個雷,就只有去檢測 a23,a24,a25 a33,       a35 a43,a44,a45這8個雷區(qū)是否放上了雷,仔細觀察它們成在數(shù)學(xué)關(guān)系,抽象出來就是:ai,j的雷的個數(shù)就是由&#

14、160;ai-1,j-1,ai-1,j,ai-1,j+1 a i ,j-1,           a i ,j+1 ai+1,j-1,ai+1,j,ai+1,j+1 這樣的8個雷區(qū)決定的。對于任意一點(x,y)執(zhí)行循環(huán)語句:for(int Y=-1;Y<=1;+Y) for(int X=-1;X<=1;+X) if(bm_gamepooly+Yx+X & GMARK_BOOM)+nCount; 觀察并計算它周圍8個方向雷區(qū)的總雷數(shù)。3.

15、 雷方塊拓展接著上面的例子,假如a3,4周圍雷數(shù)為1,a2,3已被標示為地雷,那么a24,a25,a33,a35,a43,a44,a45將被展開,一直波及到不可確定的雷區(qū)。這也是實現(xiàn)的關(guān)鍵。我們可以把數(shù)組的元素設(shè)定為一個類對象,它們所屬的類設(shè)定這樣的一個事件:在被展開時,檢查周圍的雷數(shù)是否與周圍標示出來的雷數(shù)相等,如果相等則展開周圍未標示的雷區(qū)。這樣新的雷區(qū)展開又觸發(fā)這個事件,就這樣遞歸下去,一直蔓延到不可展開的雷區(qū)。4. KEY_1事件在雷區(qū)鍵1的時候,光標所在的方塊將顯示提示信息,即它周圍8個方向的雷區(qū)總雷數(shù)。(1) 判斷鼠標點擊的雷區(qū)位置,計算出當(dāng)前打開的小方塊坐標。(2) 檢測小方塊的

16、狀態(tài),判斷能否打開,是則跳到無雷狀態(tài)處理。(3) 檢測小方塊的狀態(tài),判斷是否為雷,是則跳到雷狀態(tài)處理。(4) 繼續(xù)狀態(tài)處理,打開小方塊,并拓展最大可能顯示范圍。KEY_1事件流程圖如下:KEY_1事件游戲結(jié)束雷方塊定位繼續(xù)處理打開區(qū)域拓展最大的可能顯示范圍勝利失敗處理勝利處理顯示結(jié)束否是否是5. KEY_2事件對雷區(qū)域中某個小方塊的屬性做出判斷后,可以鍵2做出相應(yīng)的屬性標記,當(dāng)鍵2時,可以根據(jù)以前該雷方塊標識的狀態(tài)去計算出應(yīng)該顯示的下一狀態(tài),并標識對該雷方塊的推測屬性,人啊背后予以顯示,其實現(xiàn)步驟如下:(1)光標所在的雷區(qū)位置。(2)歷史標志狀態(tài)。(3)使狀態(tài)修改為即將顯示的狀態(tài)。(4)顯示。

17、 KEY_2的流程分析如下圖:KEY_2事件雷方塊定位判斷歷史屬性以及相關(guān)狀態(tài)修改相關(guān)狀態(tài)顯示結(jié)束6. KEY_3事件對雷區(qū)域中某個小方塊的屬性做出判斷后,可以鍵3做出相應(yīng)的雷區(qū)拓展,首先顯示該區(qū)域的方塊狀態(tài),然后判斷該方塊周圍8個方向的方塊中是否有雷,如果沒有,則在此方塊鍵3,將會打開這8個方塊中無雷的區(qū)域。實現(xiàn)步驟如下:(1) 光標所在雷區(qū)顯示的數(shù)字。(2) 相鄰8個方向的區(qū)域狀態(tài)。(3) 進行判斷,并做相應(yīng)操作。(4) 結(jié)果顯示。 KEY_3流程分析如下圖:KEY_3事件雷方塊定位判斷其屬性以及周圍方塊狀態(tài)打開其周圍非雷區(qū)顯示結(jié)束 五、詳細設(shè)計1.二維數(shù)組初始化我開的是一個22

18、*22的數(shù)組,而實際使用的雷區(qū)是20*20的數(shù)組,周圍一圈是空的,這樣對雷區(qū)的邊界,我也可以簡單的將它周圍8個點的雷數(shù)相加,而不會發(fā)生數(shù)組越界的情況,但在編程的時候,仍應(yīng)該認為雷區(qū)是一個簡單的20*20的數(shù)組,可以利用的應(yīng)該是0,19.  #define GAME_MAX_WIDTH 100#define GAME_MAX_HEIGHT 100int bm_gamepoolGAME_MAX_HEIGHT+2GAME_MAX_WIDTH+2;while(nBoom) int x = rand()%Width + 1, y = rand()%Height + 1; if(bm_gamep

19、oolyx=0) bm_gamepoolyx = GMARK_BOOM; -nBoom; 2.判斷一個區(qū)域是否是雷方塊int CSLGame:DrawPool(int bDrawBoom = 0)if(bm_gamepoolyx & GMARK_BOOM) if(bDrawBoom) putchar('*'); else putchar('.'); 3.相鄰區(qū)域的雷數(shù)獲取/ return ShowNum at (x, y) int CSLGame:GetShowNum(int x, int y) int nCount = 0; for(int Y=-1;

20、Y<=1;+Y) for(int X=-1;X<=1;+X) if(bm_gamepooly+Yx+X & GMARK_BOOM)+nCount; return nCount; 4.根據(jù)玩家的操作和雷區(qū)的分布,在游戲界面上顯示 各字符串 用來表示空、 *用來表示為雷、 #表示此區(qū)域標志為雷、 .表示未確定區(qū)域或雷數(shù),即任意一點周圍8個方向的總雷數(shù)。/ Draw game pool to Console windowint CSLGame:DrawPool(int bDrawBoom = 0) for(int y=1;y<=poolHeight;+y) CConsole

21、Wnd:GotoXY(1, y); for(int x=1;x<=poolWidth;+x) if(bm_gamepoolyx=0) putchar('.'); else if(bm_gamepoolyx=GMARK_EMPTY) putchar(' '); else if(bm_gamepoolyx>0 && bm_gamepoolyx<=8) putchar('0'+bm_gamepoolyx); Else if(bDrawBoom=0&&(bm_gamepoolyx GMARK_MARK)

22、putchar('#'); else if(bm_gamepoolyx & GMARK_BOOM) if(bDrawBoom) putchar('*'); else putchar('.'); return 0;5掃雷機器人有10次錯誤機會,執(zhí)行以下循環(huán)函數(shù)if(bm_gamepoolyx & GMARK_BOOM) i+; if(i=10)nRT = EOF; 6.雷方塊的拓展int CSLGame:DFSShowNum(int x, int y) if(0<x && x<=poolWidth) &a

23、mp;&(0<y && y<=poolHeight) && (bm_gamepoolyx=0) int nCount = GetShowNum(x, y); if(nCount=0) bm_gamepoolyx = GMARK_EMPTY; for(int Y=-1;Y<=1;+Y) for(int X=-1;X<=1;+X) DFSShowNum(x+X,y+Y); else bm_gamepoolyx = nCount; return 0; 7. 勝利的判斷與相應(yīng)處理,根據(jù)各種輸入KEY_UP、 KEY_DOWN、 KEY_L

24、EFT、 KEY_RIGHT、 KEY_1、 KEY_2 、KEY_3、 KEY_ESC執(zhí)行操作,通過返回的nRT來判斷失敗、勝利或未結(jié)束。/ Game loop, wait and process an input message/ return: 0: not end; 1: Win; otherwise: Lose int CSLGame:WaitMessage() int nKey = CConsoleWnd:GetKey(); int nRT = 0, nArrow = 0; switch (nKey) case KEY_UP: if(curY>1)-curY; nArrow=

25、1; break; case KEY_DOWN: if(curY<poolHeight) +curY; nArrow=1; break; case KEY_LEFT: if(curX>1)-curX; nArrow=1; break; case KEY_RIGHT: if(curX<poolWidth)+curX; nArrow=1; break; case KEY_1: nRT = TryOpen(curX, curY); break; case KEY_2: if(bm_gamepoolcurYcurX & (GMARK_MARK|GMARK_BOOM)=0) b

26、m_gamepoolcurYcurX = GMARK_MARK; break; case KEY_3: if(bm_gamepoolcurYcurX & 0xF) int nb = bm_gamepoolcurYcurX & 0xF; for(int y=-1;y<=1;+y) for(int x=-1;x<=1;+x) if(bm_gamepoolcurY+ycurX+x&GMARK_MARK) -nb; if(nb=0) for(int y=-1;y<=1;+y) for(int x=-1;x<=1;+x) if(bm_gamepoolcur

27、Y+ycurX+x & (0xF|GMARK_MARK) = 0) nRT |= TryOpen(curX+x, curY+y); break; case KEY_ESC: nRT = EOF; break; if(nKey = KEY_1 | nKey = KEY_3) int y=1; for(;y<=poolHeight;+y) int x=1; for(;x<=poolWidth; +x) if(bm_gamepoolyx=0)break; if(x<=poolWidth) break; if(! (y<=poolHeight) nRT = 1; if(

28、nArrow=0) DrawPool(); MoveCursor(); return nRT; 六、測試數(shù)據(jù)及其結(jié)果分析游戲開始頁面如下:在10次錯誤機會內(nèi)未獲得游戲勝利,運行結(jié)果如下:分析:(1)鍵1,打開光標所在區(qū)域并顯示其相鄰8個方向的總雷數(shù)。 (2)判斷某方塊的狀態(tài),若確定其為雷,鍵2,則在此方塊上標記,表示此為雷。 (3)判斷已打開方塊相鄰8個方向的方塊狀態(tài),若已顯示的雷數(shù)與此方塊顯示的數(shù)字相等,則在此方塊鍵3,將其相鄰方向未打開區(qū)域打開。(4)有10次錯誤機會,在10內(nèi)錯誤將不顯示游戲失敗信息,只有超過10次才會出現(xiàn)游戲失敗的提示信息。七、調(diào)試過程中的問題1.問題:在布雷時,如何實現(xiàn)隨機分布。解決為題:通過

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論