一直感覺Windows自帶的掃雷程序挺有意思的。學習VC也有很長的時間了,一直沒有真正的用心作過什麼東西。決定先做個掃雷練練手。由於對MFC掌握的不是很好,程序中的小臭蟲還希望各位兄弟們多多指教,共同進步。
一、主要思路及實現方法
對於界面部分:采取的是貼圖技術即在窗口上設置上各種背景圖片。在有鼠標以及鍵盤操作的時候進行相應的替換。此處主要用到的都是對於後台部分:在第一次點擊雷區的時候埋下所有的雷,同時開始計時。然後在每一次鼠標點擊的時候進行判斷,若觸雷或標記錯誤的展開則失敗,若成功挖出最後一顆雷則勝利。為記錄每一個表示雷的小窗體的信息,程序中定義了一個MINEWND的結構體,保存了小窗體的行,列,是否為雷,初始狀態和最終狀態的信息。然後在主窗體類CMineWnd中定義了一個二維數組m_pMines[24][30]存儲最大雷區的小窗體數組。每次點擊鼠標的時候,首先獲得小窗體的指針,然後對相應的數組中的元素進行操作。
二、代碼說明:
布下所有的雷:
void CMineWnd::LayMines(UINT row, UINT col)
{
srand( (unsigned)time( NULL ) );
UINT i, j;
for(UINT index = 0; index < m_uMineNum;) {
i = rand() % m_uYNum;
j = rand() % m_uXNum;
if (i == row && j == col) continue;
if(m_pMines[i][j].uAttrib != ATTRIB_MINE) {
m_pMines[i][j].uAttrib = ATTRIB_MINE;
index++;
}
}
}
此處的srand( (unsigned)time( NULL ) );是為了每次產生的隨機數都不相同。展開空白窗體周圍的區域:
void CMineWnd::ExpandMines(UINT row, UINT col)
{
UINT i, j;
UINT minRow = (row == 0) ? 0 : row - 1;
UINT maxRow = row + 2;
UINT minCol = (col == 0) ? 0 : col - 1;
UINT maxCol = col + 2;
UINT around = GetAroundNum(row, col);
m_pMines[row][col].uState = 15 - around;
m_pMines[row][col].uOldState = 15 - around;
// redraw special MINEWND
DrawSpecialMine(row, col);
if (around == 0) {
for (i = minRow; i < maxRow; i++) {
for (j = minCol; j < maxCol; j++) {
if (!(i == row && j == col) && m_pMines[i][j].uState == STATE_NORMAL
&& m_pMines[i][j].uAttrib != ATTRIB_MINE) {
if (!IsInMineArea(i, j)) continue;
ExpandMines(i, j);
}
}
}
}
}
此處為一個遞歸函數,查找需要展開的小窗體周圍的8個小窗體,若再次查找到空白,再進行查找,直到把能展開的全部展開。其他的幾個主要的函數代碼量比較大,各位可以到附帶的實例代碼中去看,就不在這裡祥述了 。
四、結束語
程序代碼參考了lpq9907的掃雷程序的代碼。在此對lpq9907表示感謝:) 另外,程序實現代碼中的注釋都是用的英文,本人英文水平不高,純屬練習,若有什麼錯誤還望不要笑我同時希望能告訴我改正。
本文配套源碼