日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《扫雷》游戏递归算法分析

發(fā)布時間:2024/1/8 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《扫雷》游戏递归算法分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

掃雷游戲中在點擊空白塊的時候,如果遇到了數(shù)字為空的空白塊那么他會自動的幫助點擊空板塊周圍的所有空白塊。那么在自動點開的空白塊中還是遇到了數(shù)字為空的空白塊,他就又會幫助點擊其周圍的空白塊。

效果如下圖:

為了方便理解我將空白的方塊以數(shù)字0標(biāo)識。

那么可以設(shè)計遞歸函數(shù)。如下:

結(jié)構(gòu)體如下:

struct Block {int x; // 格子的橫坐標(biāo)int y; // 格子的縱坐標(biāo) };enum LeiStatus { isNum = 0, // 該空白格為數(shù)字 isLei // 該空白格為雷};enum ShowStatus {hideNum = 0,showNum,isOk, // 玩家確認(rèn)這個是雷,即給這個格子標(biāo)上小旗isAsk // 不確定這個是什么,給這個格子標(biāo)上問號};/*** @brief The Cell 每一個格子的結(jié)構(gòu)體*/ struct Cell : Block {LeiStatus leiStatus;ShowStatus showStatus;int num; // 表示每個位置的上下左右八個位置的雷的數(shù)據(jù),如果雷的狀態(tài)是Cell(){leiStatus = isNum;num = 0;showStatus = hideNum;} };

當(dāng)前格子的周圍格子的標(biāo)識如下圖:

x,y為基礎(chǔ)坐標(biāo),當(dāng)自動點擊x-1,y-1的時候,又會以x-1,y-1作為新的基礎(chǔ)坐標(biāo)進(jìn)行計算。因此可以寫出一下算法。

我的空白格存儲沒有使用二維數(shù)組而是使用一位數(shù)組來表示二維數(shù)組,算法如下:

m_max_block_x 表示橫向坐標(biāo)的類的最大數(shù)字。

int QGameWidget::getIndex(int block_x, int block_y) {return block_x * m_max_block_x + block_y; }

第一版本

第一版本比較容易理解,將所有的格子都傳遞一遍讓其進(jìn)行更新。

void QGameWidget::updateLei(int block_x, int block_y) {m_cells[getIndex(block_x, block_y)].showStatus = showNum;if (m_cells[getIndex(block_x, block_y)].num != 0) {return;}// 右上角if (block_x - 1 >= 0 && block_y - 1 >= 0 &&m_cells[getIndex(block_x - 1, block_y - 1)].showStatus == hideNum) {m_cells[getIndex(block_x - 1, block_y - 1)].showStatus = showNum;if (m_cells[getIndex(block_x - 1, block_y - 1)].num == 0)updateLei(block_x - 1, block_y - 1);}// 上if (block_y - 1 >= 0 &&m_cells[getIndex(block_x, block_y - 1)].showStatus == hideNum) {m_cells[getIndex(block_x, block_y - 1)].showStatus = showNum;if (m_cells[getIndex(block_x, block_y - 1)].num == 0)updateLei(block_x, block_y - 1);}// 左上if (block_x + 1 < m_max_block_x && block_y - 1 >= 0 &&m_cells[getIndex(block_x + 1, block_y - 1)].showStatus == hideNum) {m_cells[getIndex(block_x + 1, block_y - 1)].showStatus = showNum;if (m_cells[getIndex(block_x + 1, block_y - 1)].num == 0)updateLei(block_x + 1, block_y - 1);}// 左if (block_x + 1 < m_max_block_x &&m_cells[getIndex(block_x + 1, block_y)].showStatus == hideNum) {m_cells[getIndex(block_x + 1, block_y)].showStatus = showNum;if (m_cells[getIndex(block_x + 1, block_y)].num == 0)updateLei(block_x + 1, block_y);}// 右下if (block_x + 1 < m_max_block_x && block_y + 1 < m_max_block_y &&m_cells[getIndex(block_x + 1, block_y + 1)].showStatus == hideNum) {m_cells[getIndex(block_x + 1, block_y + 1)].showStatus = showNum;if (m_cells[getIndex(block_x + 1, block_y + 1)].num == 0)updateLei(block_x + 1, block_y + 1);}// 下if (block_y + 1 < m_max_block_y &&m_cells[getIndex(block_x, block_y + 1)].showStatus == hideNum) {m_cells[getIndex(block_x, block_y + 1)].showStatus = showNum;if (m_cells[getIndex(block_x, block_y + 1)].num == 0)updateLei(block_x, block_y + 1);}// 左下if (block_x - 1 >= 0 && block_y + 1 < m_max_block_y &&m_cells[getIndex(block_x - 1, block_y + 1)].showStatus == hideNum) {m_cells[getIndex(block_x - 1, block_y + 1)].showStatus = showNum;if (m_cells[getIndex(block_x - 1, block_y + 1)].num == 0)updateLei(block_x - 1, block_y + 1);}// 右if (block_x - 1 >= 0 &&m_cells[getIndex(block_x - 1, block_y)].showStatus == hideNum) {m_cells[getIndex(block_x - 1, block_y)].showStatus = showNum;if (m_cells[getIndex(block_x - 1, block_y)].num == 0)updateLei(block_x - 1, block_y);}return; }

?第二版

可以看到每一個便宜的格子在計算之前都對其進(jìn)行合理性的處理。

例如(x-1,y-1)左上角的坐標(biāo),他的值是不能在游戲設(shè)定的范圍意外的。如下圖:紅色部分為異常部分因此需要將其剔除。那么我們在這個地方是可以優(yōu)化的。因為我使用的是一位數(shù)組轉(zhuǎn)代替二維數(shù)組的方式,因此我只需要對一維數(shù)組進(jìn)行判斷就行,我們可以放在函數(shù)內(nèi)部進(jìn)行。代碼可以這樣寫

int QGameWidget::getIndex(int block_x, int block_y) {if(block_x < 0 || block_y < 0 )return -1;if(block_x >= m_max_block_x || block_y >= m_max_block_y ) return -2;return block_x * m_max_block_x + block_y; } void QGameWidget::updateLei(int block_x, int block_y) {if (getIndex(block_x, block_y) < 0 ||getIndex(block_x, block_y) >= m_max_block_x * m_max_block_y) {return;}// 為避免死循環(huán),因此這里需要判斷該方塊是否已經(jīng)被點擊,如果沒被點擊就設(shè)置其狀態(tài)位點擊狀態(tài)。if (m_cells[getIndex(block_x, block_y)].showStatus == hideNum) {m_cells[getIndex(block_x, block_y)].showStatus = showNum;if (m_cells[getIndex(block_x, block_y)].num == 0) {updateLei(block_x - 1, block_y - 1);updateLei(block_x, block_y - 1);updateLei(block_x + 1, block_y - 1);updateLei(block_x + 1, block_y);updateLei(block_x + 1, block_y + 1);updateLei(block_x, block_y + 1);updateLei(block_x - 1, block_y + 1);updateLei(block_x - 1, block_y);}}return; }

?第三版

第三版是發(fā)現(xiàn)這個-1.+1啥的很容易寫錯因此可以這樣寫。

void QGameWidget::updateLei(int block_x, int block_y) {if (getIndex(block_x, block_y) < 0 ||getIndex(block_x, block_y) >= m_max_block_x * m_max_block_y) {return;}if (m_cells[getIndex(block_x, block_y)].showStatus == hideNum) {m_cells[getIndex(block_x, block_y)].showStatus = showNum;if (m_cells[getIndex(block_x, block_y)].num == 0) {for(int i = - 1; i <=1;i++){for(int j =-1;j<=1; j++){if(!(i == 0&& j ==0))updateLei(block_x + i, block_y + j);}}}}return; }

第四版

由于getIndex頻繁被調(diào)用因此可以修改為第一次調(diào)用之后復(fù)用,這樣雖然浪費了一點控件,但是節(jié)約了很多的算法時間。

代碼如下:

void QGameWidget::updateLei(int block_x, int block_y) {// 計算坐標(biāo)對應(yīng)的索引int index = getIndex(block_x, block_y);if (index < 0 ||index >= m_max_block_x * m_max_block_y) {return;}if (m_cells[index].showStatus == hideNum) {m_cells[index].showStatus = showNum;if (m_cells[index].num == 0) {for(int i = - 1; i <=1;i++){for(int j =-1;j<=1; j++){if(!(i == 0&& j ==0))updateLei(block_x + i, block_y + j);}}}}return; }

隨著代碼的一步一步優(yōu)化最終得到算法函數(shù)。

C++實現(xiàn)《掃雷》游戲(入門經(jīng)典)_啊淵的博客-CSDN博客

總結(jié)

以上是生活随笔為你收集整理的《扫雷》游戏递归算法分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。