VB編寫益智游戲“漢諾塔”
汨羅網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)建站,汨羅網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為汨羅千余家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)公司要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的汨羅做網(wǎng)站的公司定做!
海粟/文
《軟件報(bào)》2007年47期 61-74
【編程引子】
“漢諾塔”問題源自印度的一個(gè)古老傳說,對(duì)于它的算法比較常見的是應(yīng)用遞歸調(diào)用。在本例中,筆者將給大家介紹一種更簡(jiǎn)單和直觀的處理方法。
【編程分析】
漢諾塔游戲的主要目的是借助B區(qū)域,將A區(qū)域的五只盤子轉(zhuǎn)移到C區(qū)域中,要求每次移動(dòng)必須從最上層盤子開始,而且必須始終保證小號(hào)盤子在大號(hào)盤子的上方。
程序的主要技術(shù)點(diǎn),除了對(duì)上述要求的實(shí)現(xiàn)外,還要考慮到鼠標(biāo)拖放盤子以及盤子的定位、排序等內(nèi)容。在設(shè)計(jì)初期,筆者首先考慮采用單擊選定,再次單擊定位的方式來移動(dòng)盤子,但這樣做必須要讓程序記住誰是活動(dòng)盤子,而且操作的直觀性較差。所以,最后筆者還是選擇了利用鼠標(biāo)事件來模擬拖動(dòng)盤子的動(dòng)作。
而對(duì)于盤子移動(dòng)后的定位問題,如果單純靠坐標(biāo)計(jì)算來顯然,工作量是非常大的。所以,筆者在本例中應(yīng)用了“一個(gè)蘿卜一個(gè)坑”的簡(jiǎn)單原理,將目標(biāo)位置提前放置好Image控件,這樣一來,盤子的移動(dòng)和定位操作都成了對(duì)目標(biāo)控件屬性的控制,處理起來變得十分方便。
【主要代碼】
1.程序初始化
程序初始化操作在窗體加載事件中完成,另外它與“重新開始”功能模塊的作用完全相同,所以可以通過調(diào)用的方式來共享代碼。代碼的主要功能是移動(dòng)步驟清零、在A區(qū)域復(fù)位盤子,以及清除B和C兩區(qū)域盤子等,主要內(nèi)容如下:
Private Sub Command1_Click()
Label4.Caption = 0 ’移動(dòng)步驟清零
For i = 0 To 4
Image1(i).Picture = LoadPicture(App.Path "\p" i ".jpg")
Image2(i).Picture = LoadPicture("")
Image3(i).Picture = LoadPicture("")
Next i
Call SortImg(Image1, 1080) ’對(duì)齊盤子
End Sub
其中子過程SortImg是對(duì)指定區(qū)域內(nèi)盤子進(jìn)行居中對(duì)齊操作,后文中會(huì)有詳細(xì)介紹。
2.轉(zhuǎn)移盤子
該過程是整個(gè)程序的核心,需要考慮的事件包括從A區(qū)至B區(qū)和C區(qū)、從B區(qū)至A區(qū)和C區(qū)、從C區(qū)至A區(qū)和B區(qū)這樣共六種情況,為了簡(jiǎn)化代碼編寫,筆者在程序中使用了控件數(shù)組。下面是從A區(qū)向其它兩區(qū)轉(zhuǎn)移盤子的代碼,其它幾種情況與之類似:
Private Sub Image1_MouseUp(Index As Integer, Button As Integer, Shift As Integer, X As Single, Y As Single)
If Index 4 Then If Image1(Index + 1).Picture 0 Then Exit Sub ’移動(dòng)操作不合法
If X = 2000 And X = 3200 Then
Call MoveImg(Image1, Image2, Index) ’從A向B轉(zhuǎn)移
Call SortImg(Image2, 3420) ’對(duì)齊盤子3420為區(qū)域中心線X值
End If
If X = 4300 And X = 5700 Then
Call MoveImg(Image1, Image3, Index) ’從A向C轉(zhuǎn)移
Call SortImg(Image3, 5760)
End If
End Sub
通過分析可知,如果用戶所選盤子的上方還有盤子,則不符合游戲規(guī)則,會(huì)被終止。另外,程序中使用了類似其它軟件中的“熱區(qū)域”的概念,即當(dāng)拖動(dòng)鼠標(biāo)至我們規(guī)定的B區(qū)域中時(shí),將引發(fā)真正的移動(dòng)操作(即激活子過程MoveImg),其主要代碼如下:
Private Sub MoveImg(SImg As Object, DImg As Object, Idx As Integer)
For i = 0 To 4
If DImg(i).Picture = 0 Then ’當(dāng)前區(qū)域有位置
If i 0 Then
If SImg(Idx).Width DImg(i - 1).Width Then ’符合上小下大游戲條件
DImg(i).Picture = SImg(Idx).Picture ’移動(dòng)盤子
Exit For
Else
Exit Sub ’移動(dòng)操作不合法則退出
End If
Else
DImg(i).Picture = SImg(Idx).Picture ’向區(qū)域最下方移動(dòng)盤子
Exit For
End If
End If
Next i
If i = 4 Then
SImg(Idx).Picture = LoadPicture("")
Label4.Caption = Label4.Caption + 1 ’更新操作步數(shù)
End If
End Sub
在移動(dòng)子過程中,判定位置是否為空的主要依據(jù)是目標(biāo)Image控件的Picture屬性是否為0;當(dāng)獲知位置可用時(shí),再進(jìn)一步判斷當(dāng)前位置的下面位置盤子的尺寸是否大于當(dāng)前盤子(即對(duì)游戲規(guī)則的判定),條件滿足的話就可以通過傳遞Picture屬性值來完成移動(dòng)操作了;最后,還要將源位置盤子清空,并且記錄操作步數(shù)。
3.對(duì)齊盤子
在上述兩模塊中都涉及了子過程SortImg,其主要功能是對(duì)區(qū)域內(nèi)盤子進(jìn)行居中對(duì)齊處理,這是美化程序執(zhí)行效果的一項(xiàng)重要措施,同時(shí)在該部分中還加入了游戲勝利過關(guān)的判斷(即每轉(zhuǎn)移一步判斷一次),主要代碼如下:
Private Sub SortImg(Img As Object, IntCenter As Integer)
For i = 0 To 4
Img(i).Left = IntCenter - Img(i).Width / 2
Next i
For i = 0 To 4
If Image1(i).Picture 0 Then Exit For
If Image2(i).Picture 0 Then Exit For
Next i
If i 4 Then MsgBox "恭喜:你成功了!", vbOKOnly + vbInformation, "勝利"
End Sub
【編程后記】
面對(duì)一些看似復(fù)雜的程序功能,仔細(xì)研究一下,總會(huì)有好的思路和方法閃現(xiàn)出來。本例實(shí)現(xiàn)了漢諾塔游戲的基本設(shè)計(jì)思路,大家還可以在盤子數(shù)量、步數(shù)排行榜等方面予以改進(jìn),以使該程序變得更加豐富、精彩!
以下是5個(gè)盤子的漢諾塔程序,用的是遞歸算法:
#includefstream
#includeiostream
using namespace std;
ofstream fout("Honnoi.txt");
int num=1;//記錄步數(shù)
void Move(int n,char x,char y)
{
foutnum":""把"n" 號(hào)盤,從"x"柱移到"y"號(hào)柱"endl;
coutnum":""把"n" 號(hào)盤,從"x"柱移到"y"號(hào)柱"endl;
++num;
}
void Hannoi(int n,char A,char C,char B)
{
if(n==1)
Move(1,A,C);
else
{
Hannoi(n-1,A,B,C);
Move(n,A,C);
Hannoi(n-1,B,C,A);
}
}
int main()
{
Hannoi(5,'A','C','B');
cout"輸出完畢!"endl;
cout"一共"num-1"步"endl;
return 0;
}
程序?qū)⑤敵霾綌?shù)、每步操作和總步數(shù)
給你個(gè)參考:
Private Sub hanoi(n As Integer, one As String, two As String, three As String)
If n = 1 Then
Print Tab(5); one; "-------"; three
Else
Call hanoi(n - 1, one, three, two)
Print Tab(5); one; "-------"; three
Call hanoi(n - 1, two, one, three)
End If
End Sub
Private Sub Form_Click()
Dim x As Integer
x = Val(InputBox("請(qǐng)輸入圓盤的個(gè)數(shù)"))
Print Tab(5); "將" x "個(gè)圓盤從A柱移到C柱的移動(dòng)順序?yàn)?
Call hanoi(x, "A", "B", "C")
End Sub