設計並實現一個游戲:漢諾塔。
完成這個實驗,涉及C++面向對象編程以及基本的數據結構知識(如棧和隊列)但具此次實現並沒有使用STL庫。
1. 漢諾塔問題
漢諾塔是一個著名的數學問題。它由三根桿子和若干不同大小的盤子組成。開始時,所有的盤子都在第一根桿子上,並按照從上到下大小升序排列(也就是說,最小的在最上面)。這個問題的目標是將所有盤子移到另一根桿子上,並遵守以下簡單的規則:
- 每次只能移動一個盤子。
- 每次移動都是將其中一根桿子的最上面的盤子取出,放到另一根桿子上。
- 任何較大的盤子都不能放在較小的盤子上面。
解決這個問題的經典方法是遞歸。該算法可以描述為以下偽代碼:
function hanoi(n, A, B, C) { // move n disks from rod A to rod B, use rod C as a buffer
hanoi(n - 1, A, C, B);
move(n, A, B); // move the nth disk from rod A to rod B
haoni(n - 1, C, B, A);
}
2. 實驗描述
在本實驗中,桿子的數量總是等於3,盤子的數量可以是1~5。其中,第1根桿子為初始桿,第2根為目標桿。
本實驗的任務包括以下內容:
- 完成一個交互式的漢諾塔游戲程序,根據用戶輸入的指令移動相應的盤子,並在用戶勝利時打印提示;
- 通過命令行界面,將漢諾塔游戲的狀態繪制出來,包括3根桿子和若干盤子;
- 根據漢諾塔問題的遞歸算法,提供一個自動求解程序,能夠從任一狀態出發,通過若干步移動達到目標狀態。
具體而言,程序的流程如下:
- 首先,程序打印
How many disks do you want? (1 ~ 5)
,要求輸入盤子的數量(要求為1~5)。如果輸入Q
,則退出程序。不合法的輸入應當忽略。 - 接下來程序將打印漢諾塔的狀態,隨后打印
Move a disk. Format: x y
,要求用戶給出指令。指令的形式是from to
(例如,2 3
的意思是將桿2最上面的盤子移動到桿3上),不合法的輸入或是不可執行的指令應該忽略。在這之后,無論指令是否合法,程序總是重新打印一遍當前狀態,並重新要求用戶輸入。 - 如果輸入的指令為
0 0
,則進入自動模式。程序需要首先將用戶已經執行的指令反過來執行一遍,復原到初始狀態,然后再按照遞歸算法執行。每次執行時,程序通過輸出Auto moving:x->y
告知用戶所執行的指令。注意:即使有其他方法從當前狀態直接到達目標狀態,也請按照先復原后執行的方式進行。這是因為自動評測的時候會直接比對輸出內容。 - 無論是通過用戶指令或是自動模式,只要達成目標狀態(即所有盤子都移到桿2上),就打印游戲勝利的提示信息,然后重新回到第1步。
打印漢諾塔狀態的要求:我們用|
表示桿子,-
表示底座,一排*
表示盤子。每個盤子從小到大分別用3、5、7、9、11個*
表示(最多5個盤子)。無論盤子數量多少,輸出的整個畫布的大小固定為11x41。
例如,一共5個盤子,均按照從小到大放在桿1上,此時輸出的結果應該如下:
| | |
*** | |
| | |
***** | |
| | |
******* | |
| | |
********* | |
| | |
*********** | |
-----|--------------|--------------|-----//縱向11個|,橫向-加|共41個
而如果只有3個盤子,輸出如下(注意畫布的大小不變):
| | |
| | |
| | |
| | |
| | |
*** | |
| | |
***** | |
| | |
******* | |
-----|--------------|--------------|-----
輸入輸出
這里給出兩個樣例,分別使用自動模式和手動模式。這里行首的>
<
代表是程序的輸入還是輸出。
樣例1:
< How many disks do you want? (1 ~ 5)
> 2
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< *** | |
< | | |
< ***** | |
< -----|--------------|--------------|-----
< Move a disk. Format: x y
> 0 0
< Auto moving:1->3
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< ***** | ***
< -----|--------------|--------------|-----
< Auto moving:1->2
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | ***** ***
< -----|--------------|--------------|-----
< Auto moving:3->2
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | *** |
< | | |
< | ***** |
< -----|--------------|--------------|-----
< Congratulations! You win!
< How many disks do you want? (1 ~ 5)
> Q
樣例2:
< How many disks do you want? (1 ~ 5)
> 2
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< *** | |
< | | |
< ***** | |
< -----|--------------|--------------|-----
< Move a disk. Format: x y
> 1 2
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< ***** *** |
< -----|--------------|--------------|-----
< Move a disk. Format: x y
> 2 3
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< ***** | ***
< -----|--------------|--------------|-----
< Move a disk. Format: x y
> 1 2
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | ***** ***
< -----|--------------|--------------|-----
< Move a disk. Format: x y
> 3 2
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | | |
< | *** |
< | | |
< | ***** |
< -----|--------------|--------------|-----
< Congratulations! You win!
< How many disks do you want? (1 ~ 5)
> Q