一. 功能需求:
1. 能夠讓玩家擺棋,並讓電腦判斷是否正確
2. 能讓電腦給予幫助(給出所有可能結果)
3. 實現悔棋功能
4. 實現重置功能
5. 添加點按鍵音效果更佳
二. 總體設計計:
1. 核心算法:
遞歸實現(回溯算法):
思路:按行分別安排皇后(Q),Q數目目前爲8.
Q1從第一行第一列開始到最後一列,先放在第一列;
Q2從第二行第一列到最後一列,每次都檢查衝突,不衝突纔可以落子;
依次嘗試Qm… 如果Qm沒有可擺放的位置,則返回Qm-1,同時Qm-1放棄剛纔的位置;
當Q1嘗試過首行的所有列的位置後,算法結束。
統計遞歸併羅列所有解法。
2. 具體功能實現的設計:
(1) 電腦判斷玩家的擺法正確與否:
對每一個棋子向右、下、右下和左下四個方向檢查,若遇到任何一個方向存在棋子,則返回錯誤,若八個棋子都遍歷完後都不衝突,則返回正確。
(2) 電腦給予幫助:
調用核心算法,遍歷所有結果,並顯示結果
(3) 實現悔棋:
用棧來存儲每個棋子的位置,以實現悔棋。
(4) 實現重置:
將二維數組賦值爲空,並顯示。
(5) 加音樂:
使用sndPlaySound(lpSound1,SND_ASYNC|SND_MEMORY)函數播放音樂。
三. 詳細設計:
1. 電腦判斷玩家的擺法正確與否:
//-------------電腦檢查玩家擺放是否正確----------------
bool CQueenDlg::Check()
{
intcolumn = -1;
introw = -1;
intcount = 0;
for(int i = 0; i < 8; i++)
{
for(int j = 0 ; j < 8; j++)
{
if(Image[i][j]== 1 || Image[i][j] == 2)//若找到皇后,向左、下、右下、左下掃描看是否有與其在同一條線上的皇后
{
count++;
if(column== j || row == i) //若右或下方是否有與其在一條斜線上的棋子
{
returnfalse;
}
column= j;
row= i;
intm = i+1;
intn = j+1;
while(m< 8 && n < 8) //檢查其右下方是否有與其在一條斜線上的棋子
{
if(Image[m][n]== 1 || Image[m][n] == 2)
{
returnfalse;
}
m++;
n++;
}
m= i+1;
n= j-1;
while(m < 8 && n >-1)//檢查其左下方是否有與其在一條斜線上的棋子
{
if(Image[m][n]== 1 || Image[m][n] == 2)
{
returnfalse;
}
m++;
n--;
}
}
}
}
if(count!= 8)
{returnfalse;}
returntrue;
}
2. 電腦給予幫助:
//------------------存儲擺放的結果.----------------
voidCQueenDlg::StoreAllResult()
{
inti,j;
// InitImage();
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
if(line[i]==j)
{
if(Image[j][i]== 0)
{
StoreImage[answer][j][i] = 1;
}
elseif(Image[j][i] == -1)
{
StoreImage[answer][j][i] = 2;
}
}
}
}
answer++;
}
//-----------判斷擺放的位置是否正確,不正確返回1,正確返回0.-------------
int CQueenDlg::Judge(int t)
{
inti,n=0;
for(i=0;i<t;i++)
{
if(line[i]==line[t])
{
n=1;
break;
}
if(line[i]+i==line[t]+t)
{
n=1;
break;
}
if(line[i]-i==line[t]-t)
{
n=1;
break;
}
}
returnn;
}
//--------------主要控制函數.----------------
void CQueenDlg::control(intn)
{
intt=8;
for(line[n]=0;line[n]<t;line[n]++)
{
if(Judge(n))
continue;
else
{
if(n!=7)
control(n+1);
else
{
StoreAllResult();
}
}
}
}
3. 實現悔棋:
//---------悔棋(消息響應函數)-----------------
void CQueenDlg::OnBtnReback()
{
//TODO: Add your control notification handler code here
introw,column;
if(!IsComputerHelp)
{
if(queen!= 0)
{
queen--;
row= storeStep[queen].row;//存放每個棋子的位置(即列號)
column= storeStep[queen].column;
if(Image[row][column]== 1) //原皇后背景爲白色,設置爲白色
{
Image[row][column]= 0;
}
elseif(Image[row][column] == 2) //原皇后背景爲黑色,設置爲黑色
{
Image[row][column]= -1;
}
Invalidate(FALSE);
}
}
}
4. 實現重置:
//-----------初始化界面的二維數組---------------
void CQueenDlg::InitImage()
{
intm = 0;
for(inti = 0; i < 8 ; i++)
{
for(intj = 0; j < 8; j++)
{
if(m%2== 0)
{
Image[i][j]= 0;
}
else
{
Image[i][j]= -1;
}
m++;
}
m++;
}
}
5. 加音樂:
void CQueenDlg::PlayMusic(int Id)
{
////////////加按鍵音
switch(Id)
{
case1:res=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_WAVE_PUTSTONE),"WAVE");break;//落子音樂
case 2:res=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_WAVE_ERROR),"WAVE");break;//不能落子音樂
case3:res=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_WAVE_WIN),"WAVE");break; //玩家勝利音樂
case4:res=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_WAVE_LOSE),"WAVE");break; //玩家失敗音樂
default:break;
}
hSound1=LoadResource(::AfxGetApp()->m_hInstance,res);
lpSound1=(LPSTR)LockResource(hSound1);
sndPlaySound(lpSound1,SND_ASYNC|SND_MEMORY);
}
四. 測試與實現:
五. 總結:
通過對八皇后問題的求解,使我對遞歸算法有了更進一步的瞭解,類似八皇后及迷宮這樣的問題都可以用回溯算法來解決。這些都是數據結構與算法中重要的算法,當時學的不是很好,通過不斷地練習才逐步掌握了。
本程序的優點:實現了八皇后的基本功能,實現了悔棋功能,界面友好,有音樂提示等。
本程序的缺點:只實現了八皇后,而沒能實現五皇后、六皇后等其他格式,提示與找出玩家錯誤不足等。