1. 程式人生 > >漢諾塔(內部+偽圖形)

漢諾塔(內部+偽圖形)

1.1問題描述:
假設有三個分別命名為A,B,C的塔座,在塔座A上插有n個直徑大小各不相同的圓盤,大的在下,小的在上,且從小到大編號為1,2,3…。現要求將塔座A上的n個圓盤移到塔座C上並仍按同樣的順序疊排,圓盤移動時必須遵守以下規則:
(1)每次只能移動一個圓盤
(2)圓盤可以插在A,B,C中任一塔上
(3)任何時刻都不能將一個較大的圓盤壓在較小的圓盤之上

1.2題目要求:
(1)基本解:要求漢諾塔層數n,起始柱,結束柱由鍵盤輸入;打印出移動的盤子編號以及從哪根柱子移動到哪根柱子的具體步驟。
(2)基本解(步數記錄):在(1)的基礎上要求記錄移動步數。
(3)內部陣列顯示(橫向):在(2)基礎上加入延時效果,要求動態顯示移動過程中每根柱子現有的盤子以及盤子編號,同時要求顯示速度可由鍵盤輸入進行選擇;不允許使用gotoxy();
(4)內部陣列顯示(縱向+橫向):在(3)的基礎上,要求顯示豎行。允許使用gotoxy函式,不建議使用system(“cls”);來實現清屏;內部陣列是否顯示可由鍵盤輸入進行選擇
(5)圖形解-預備-畫三個圓柱:要求加入延時效果
(6)圖形解-預備-在起始柱上畫n個圓盤:大的在下,小的在上;不同盤子不同顏色;要求加入延時效果。
(7)圖形解-預備-第一次移動:要求移動時先上移,平移,然後下移;延時。
(8)圖形解-自動移動版本:移動要求同(7);同時顯示橫向和縱向;顯示速度可由鍵盤
輸入選擇,0為手動;延時。
(9)圖形解-遊戲版:要求手動輸入柱子編號,分別表示此次移動的起始柱和目標柱;對輸入的合理性進行判斷,如大盤壓小盤,需要提示錯誤;要求記錄步數;待所有盤子移動到結束柱是顯示“遊戲結束”。
(10)以上的要求都是對上相容,即前面提到的要求若非特殊申明都是需要遵守的。
(11)要求利用遞迴方式完成,且遞迴函式不準超過15行。其餘函式程式碼量儘量不超過50行。
(12)所有小題都要求檢查輸入資料的合理性(包括要求輸入數字而輸入字母的非法情況)。
(13)最後將漢諾塔所有的實現方式集中在一個程式中,用選單方式由鍵盤輸入進行選擇。如圖所示:
(14)程式碼要求:格式對齊,不允許使用goto語句,在VS2015環境下,0warning,0error;
不允許使用所學範圍以外的內容(除了已經補充過的);允許用全域性變數,全域性陣列的方式分別記錄三根圓柱中的圓盤數,圓盤編號,總移動步數,其餘不準用全域性變數。

2.整體設計思路
面對相對複雜的程式,我選擇將其拆分成若干個小問題去解決,最終整合成最終的程式。
同時,在這些小問題中挑選出比較核心的問題,其他小問題都是圍繞著它們進行程式設計,實現。
整個程式最核心的部分是如何利用遞迴來解決漢諾塔問題。其次是顯示內部陣列部分,思路是利用“棧”的思想,對棧頂的元素進行判斷,移動(通過值的變化)。最後一部分,是偽圖形介面下圖形的移動和生成。思路是通過對游標位置的設定,用空格再“走”一遍圖形“走”過的路。

3.主要功能的實現

3.1 利用最優的搬運方式解決漢諾塔問題—遞迴演算法
分析Hanoi問題,本質上是不停的在做同一個操作,即從起始柱,藉助中間柱將盤子轉移到結束柱,因此可以設計成函式,不停的呼叫該函式,設定結束條件,即n=1時,回溯,即輸出每一步的搬運過程,即源程式中的Hanoi函式。

3.2每根柱子盤子情況顯示—“棧”
將每根柱子看成是一個數組,本質就是列印陣列內部的值。盤子的移進移出都是對當下柱子最頂部的盤子有所操作,對陣列而言,需要列印的元素個數就是當時柱子上圓盤的個數,操作是對於棧頂元素。
實現方法:
A.定義二維陣列pan[3][10],[3]代表三根柱子,[10]代表陣列大小。初始化時,起始柱最底部的柱子初始化為n,即pan[begin][i]=n-i (i=0,1,2..n-1),這樣同時完成了盤子的編號。
其餘兩根柱子(陣列)所有元素初始化為-1.通過元素編號來判斷有沒有盤子。
B.操作過程中,先進先出,通過對棧頂元素值的變化模擬柱子盤子的搬動情況。用top_a,top_b分別表示“出發柱”和“到達柱”的棧頂盤子的位置,即陣列中值大於0的元素個數-1.“到達柱”接收一個盤子後,新的棧頂元素位置為top_b=top_b+1,pan[final][top_b]=pan[beg][top_a]; “出發柱”搬出一個盤子後,將原來的棧頂元素的值賦給“到達柱”新的棧頂元素,此時原來的棧頂元素所在的位置沒有盤子,即pan[begin][top_a]=-1,同時,新的棧頂元素位置top_a=top_a-1。
C.最後輸出,只需要判斷元素的值是不是大於0,只有大於時,才輸出,就是盤子的編號。

3.3圖形方式顯示時,盤子的移動
用for迴圈,改變圖形(對空字元設定顏色,長度)的位置,加入Sleep()設定延時使效果更明顯。判斷座標變化時,在圖形,也就是盤子左右移動時,每次都需要判斷“出發柱”和“到達柱”的相對位置,來確定橫座標i++還是i- -以及空格字元列印的位置(i是列印時游標的位置,在圖形的最左端)。為此,我添加了一個整型變數q=(f(x)>f(y)?-1:1),利用i+=q就可以達到i++/- -要求。(其中f()是自定義的函式將鍵盤輸入的起始柱,目標柱的字元對應到數字,以方便於對應陣列的對應)。而空字元列印位置的確定,q==1時,圖形右移,空字元列印在i的位置;q==-1時,圖形左移,空字元列印在i+p的位置(p是(圖形長度-1))。

4.除錯過程中遇到的問題

4.1認識性錯誤引起的除錯失敗

 4.1.1  if(q)if(q>0)
   在圖形左右移動過程中對空格新增的位置判斷時,需要判斷左移還是右移,左移q=-1,右移是q=1,分別對應不同的空格輸出的位置。而我誤以為if(q)的意思是q大於零時,而實際上,if(q)是當q不等於0時!這是一個認識性錯誤,也是最難找到的錯誤!耗時近三小時!

  4.1.2  輸入回車鍵_getch()==’\n’
   程式整合後,鍵盤輸入選擇不同的功能,執行完後輸出“按回車鍵繼續”,再回到主頁面,因此需要對回車鍵進行判斷。而我在寫程式過程中,混淆了’\t’和’\n’。實際上,’\n’是對於輸出的時候,’\t’才是輸入的時候用的。(這是在看到老師給的測試程式才發現並上網查資料發現的!) 除了’\n’,其實還可以用ascll碼,13來判斷。

4.2 柱子底座有缺口
第八小題要求同時顯示圖形,豎式,橫式。除錯過程中發現搬運一開始,第一第二個底座就會出現一個缺口,大約一個字元寬度,而且正好就在豎式上方!對豎式的位置進行下移以後,顯示正確!事實上,在豎式輸出時程式的思路是,陣列元素大於0輸出元素的值,否則,輸出空格!所以,雖然顯示時沒有,但其實還是存在並佔據一定空間的!

4.3 圓盤上移“吃”下盤,下移“吐”柱子
顧名思義,就是圓盤上移時,下方的一個盤子會少一塊,移到“到達柱”柱頂時,再下移時的同時,柱子會長一個字元的長度。
吃下盤,究其原因,其實是被“掃地”的黑前景黑後景空格字元“掃”乾淨了!圓盤上移的實現方法是:先在正下方列印黑色空字串把圓盤原來的圖形“掃乾淨”,再在圓盤正上方一個單位用showch函式打非黑色的字串。而我沒有考慮到圓盤剛剛“出發”時,正下方是另一個圓盤,或者是底座!
解決方法:
在上移迴圈體內加一句判斷語句
if 縱座標 < 圓盤初始座標-做“掃地”操作

“吐”柱子,其實是多填補了一小段柱子!圓盤下移的實現方式是:先在正下方列印非黑色字串的圖形,再把原來字串所在的位置用黑色字串“掃乾淨”,此時,那一段範圍內的柱子也被掃掉了,於是,再補一小段柱子!而當圓盤正好在柱子頂端時,下移後原來坐在的位置本就沒有柱子,我卻補了一段!
解決方法:
在下移迴圈體內也加一句判斷
if 縱座標 > 柱子頂部所在縱座標 - 做“掃地”操作,同時填補柱子

5.心得體會

5.1經驗&體會

 5.1.1 經驗教訓

(1)反覆出現的常量,巨集定義在源程式開頭,提高程式可維護性!
(2)定義函式或者變數時,名字儘量取得有意義!防止函式,變數較多時,不停的翻源程式看對應的功能。
(3)當程式規模比較大的時候,上下滾動檢視函式很不方便!可以使用程式設計介面左側 的“減號”把一些程式“疊”起來,如 ;
這樣可以加快查詢函式的速度,同時不至於滿螢幕的程式碼看的眼花繚亂。
(4)在程式測試階段,程式規模較大時,測試時修改的地方較多!為了防止把程式改“壞”之後回不到原來“好”的時候,可以在每次成功一小步後,把原始碼複製到另外一個工程檔案中,儲存起來!
(5)遇到想不通的思路,流程時,充分利用紙筆來助我理通思路。

最後,利用函式編寫程式碼某種程度上,是對我解決複雜問題時總體思路的要求!面對複雜的問題,最好的策略應該是將其拆分成若干個小問題!每個問題的解決都對應一個或若干個函式功能的實現!因此,我需要培養自己拆分出小問題的能力和習慣!

#include<iostream>
#include<Windows.h>
#include<conio.h>
#include<time.h>
#include<cstdio>
#include"cmd_console_tools.h"
#include<iomanip>
const int basic_X = 10;
const int basic_Y = 12;
using namespace std;

int sum = 0;//步數
int n;//盤子數量
int pan[3][10];//三根柱子,每根容量為10
char beg, mid, final;



void check()//要求使用者輸入資料以及輸入正確性的檢查
{
    int f(char x);
    while (1)
    {
        cout << "請輸入漢諾塔的層數(1-10): ";
        cin >> n;
        if (n > 10 || n < 1 || cin.fail())
        {
            cin.clear();
            cin.ignore(1024, '\n');
            continue;
        }
        cout << "請輸入起始柱(A-C):";
        cin >> beg;
        if (beg > 'C' || beg < 'A' || cin.fail())
        {
            cin.clear();
            cin.ignore(1024, '\n');
            continue;
        }
        cout << "請輸入結束柱(A-C):";
        cin >> final;
        if (final > 'C' || final < 'A' || cin.fail())
        {
            cin.clear();
            cin.ignore(1024, '\n');
            continue;
        }
        break;
    }
    if (f(final) + f(beg) == 1)//通過輸入的起始柱和結束柱,判斷中間柱
        mid = 'C';
    else if (f(final) + f(beg) == 2)
        mid = 'B';
    else
        mid = 'A';
}

int f(char x)
{
    if (x == 'A')
        return 0;
    else if (x == 'B')
        return 1;
    else
        return 2;
}

void rate(int t)
{
    if (t == 0)
        getchar();
    else if (t == 1)
        Sleep(100);
    else if (t == 2)
        Sleep(80);
    else if (t == 3)
        Sleep(60);
    else if (t == 4)
        Sleep(40);
    else if (t == 5)
        Sleep(20);
}

void print()//輸出陣列值
{
    cout << setw(7) << "A: ";
    for (int k = 0; k < 10; k++)
    {
        if (pan[0][k] > 0)
            cout << pan[0][k] << " ";
        else
            cout << "  ";
    }
    cout << '\t' << "B: ";
    for (int k = 0; k < 10; k++)
    {
        if (pan[1][k] > 0)
            cout << pan[1][k] << " ";
        else
            cout << "  ";
    }
    cout << '\t' << "C: ";
    for (int k = 0; k < 10; k++)
    {
        if (pan[2][k] > 0)
            cout << pan[2][k] << " ";
        else
            cout << "  ";
    }
    cout << endl;
}


void print2(int y1, int y2, int y3)//輸出陣列豎式值
{
    HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
    for (int k = 0; k<10; k++)
    {
        y1--;
        gotoxy(hout, basic_X + 1, y1);//不該把y--以及定位語句放在if語句內!
        if (pan[0][k] > 0)
            cout << pan[0][k];
        else
            cout << "  ";
    }
    for (int k = 0; k<10; k++)
    {
        y2--;
        gotoxy(hout, basic_X + 15, y2);
        if (pan[1][k] > 0)
            cout << pan[1][k];
        else
            cout << "  ";
    }
    for (int k = 0; k<10; k++)
    {
        y3--;
        gotoxy(hout, basic_X + 30, y3);
        if (pan[2][k] > 0)
            cout << pan[2][k];
        else
            cout << "  ";
    }
}

void print_3(int m)
{
    HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
    if (m)
        gotoxy(hout, basic_X, basic_Y + 14);
    else
        gotoxy(hout, basic_X, basic_Y);
    cout << "=================================" << endl;
    if (m)
        gotoxy(hout, basic_X + 1, basic_Y + 15);
    else
        gotoxy(hout, basic_X, basic_Y + 1);
    cout << "A" << "\t\t" << "B" << "\t\t" << "C" << endl;
    cout << endl;
    gotoxy(hout, 0, basic_Y + 8);
    if (m)
        gotoxy(hout, 0, basic_Y + 19);
    cout << "起始:";
    print();

}

void draw()//畫三根柱子
{
    const HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE); //取標準輸出裝置對應的控制代碼
    setconsoleborder(hout, 100, 35);
    int X = 5;
    for (int i = 0; i < 3; i++)
    {
        showch(hout, X + i * 30, 15, ' ', COLOR_HYELLOW, COLOR_HYELLOW, 20);
        Sleep(50);
    }
    for (int j = 15; j >2; j--)
    {
        showch(hout, X + 10, j, ' ', COLOR_HYELLOW, COLOR_HYELLOW, 1);
        Sleep(50);
        showch(hout, X + 40, j, ' ', COLOR_HYELLOW, COLOR_HYELLOW, 1);
        Sleep(50);
        showch(hout, X + 70, j, ' ', COLOR_HYELLOW, COLOR_HYELLOW, 1);
        Sleep(50);
    }
    showch(hout, 0, 28, ' ', 0, 7, 1);
}

void draw_pan()
{
    const HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE); //取標準輸出裝置對應的控制代碼
    for (int j = 14, p = n; p> 0; j--, p--)
    {
        showch(hout, (15 + 30 * f(beg) - p), j, ' ', p, p, 2 * p + 1);
        Sleep(50);
    }
    showch(hout, 0, 33, ' ', 0, 7, 1);
}

void move_pan(int p, char x, char y, int j, int k, int t)
{
    HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
    for (int s = 15 - j; s > 2; s--)
    {
        showch(hout, 15 + 30 * f(x) - p, s - 1, ' ', p, p, p * 2 + 1);
        if (s < 15 - j)
        {
            showch(hout, 15 + 30 * f(x), s, ' ', COLOR_HYELLOW, COLOR_HYELLOW, 1);
            showch(hout, 15 + 30 * f(x) - p, s, ' ', 0, 7, p);
            showch(hout, 15 + 30 * f(x) + 1, s, ' ', 0, 7, p);
        }
        if (t == 0)
            Sleep(50);
        else
            rate(t);
    }
    int q = ((f(x) > f(y)) ? (-1) : 1);
    for (int i = 15 + 30 * f(x) - p; i != 15 + 30 * f(y) - p; i += q)
    {
        showch(hout, i + q, 2, ' ', p, p, p * 2 + 1);
        if (q == 1)
            showch(hout, i, 2, ' ', 0, 7, 1);
        else
            showch(hout, i + 2 * p, 2, ' ', 0, 7, p * 2 + 1);
        if (t == 0)
            Sleep(50);
        else
            rate(t);
    }
    for (int w = 3; w <14 - k; w++)
    {
        showch(hout, 15 + 30 * f(y) - p, w, ' ', p, p, p * 2 + 1);
        if (w >3)
            showch(hout, 15 + 30 * f(y), w - 1, ' ', COLOR_HYELLOW, COLOR_HYELLOW, 1);
        else
            showch(hout, 15 + 30 * f(y), w - 1, ' ', 0, 7, 1);
        showch(hout, 15 + 30 * f(y) - p, w - 1, ' ', 0, 7, p);
        showch(hout, 15 + 30 * f(y) + 1, w - 1, ' ', 0, 7, p);
        if (t == 0)
            Sleep(50);
        else
            rate(t);
    }
    showch(hout, 0, 28, ' ', 0, 7, 1);
}


void move(int i, char x, char y, int pace, int leap, int t, int m) //移動過程//m值是否要移動圖形
{//漢諾塔過程pace指是否列印步數   //leap指內部陣列隨步驟的顯示,t指是否需要延時,以及列印豎式
    HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
    if (t >= 0)
        rate(t);
    sum++;
    if (pace)
    {
        if (t >= 0)
            gotoxy(hout, 0, basic_Y + 8);
        if (m)
            gotoxy(hout, 0, basic_Y + 19);
        cout << "第" << setw(4) << sum << "步 " << '(' << setw(2) << i << "):" << x << "-->" << y;
        if (!leap)
            cout << endl;
    }
    else
        cout << i << '#' << ':' << x << "-->" << y << endl;
    if (leap)
    {
        int j = 0, k = 0;//過程參考 提示,棧
        while (pan[f(x)][j] != -1 && j < n)
            j++;
        while (pan[f(y)][k] != -1 && k < n)
            k++;
        pan[f(y)][k] = pan[f(x)][j - 1];
        pan[f(x)][j - 1] = -1;
        print();
        if (t >= 0)
            if (m)
            {
                print2(basic_Y + 14, basic_Y + 14, basic_Y + 14);
                move_pan(i, x, y, j - 1, k - 1, t);//////
            }
            else
                print2(basic_Y, basic_Y, basic_Y);
    }

}


void hanoi(int n, char A, char B, char C, int pace, int leap, int t, int m)//漢諾塔過程pace指是否列印步數
{                                                 //leap指內部陣列隨步驟的顯示,t指是否需要延時,以及列印豎式
    if (n == 1)
        move(n, A, C, pace, leap, t, m);
    else
    {
        hanoi(n - 1, A, C, B, pace, leap, t, m);
        move(n, A, C, pace, leap, t, m);
        hanoi(n - 1, B, A, C, pace, leap, t, m);
    }
}



void basic()
{
    check();
    hanoi(n, beg, mid, final, 0, 0, -1, 0);
    cout << endl;
    cout << ",按回車鍵繼續...";
    while (_getch() != '\r');
}

void basic_inner()
{
    check();
    hanoi(n, beg, mid, final, 1, 0, -1, 0);
    cout << endl;
    cout << ",按回車鍵繼續...";
    while (_getch() != '\r');
}

void show_inner()
{
    check();
    for (int i = 0; i <10; i++)//為陣列,即各柱子盤子數賦初值//!!!!
    {
        pan[f(beg)][i] = n - i;
        pan[f(mid)][i] = -1;
        pan[f(final)][i] = -1;
    }
    system("cls");
    system("mode con cols=100");
    cout << "起   始:          ";
    print();
    hanoi(n, beg, mid, final, 1, 1, -1, 0);
    cout << endl;
    cout << ",按回車鍵繼續...";
    while (_getch() != '\r');
}

void show_2(int m)
{
    HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
    int t;
    check();
    while (1)
    {
        cout << "請輸入移動速度(0-5),0-按回車單步演示,1-延時最長,5-延時最短:";
        cin >> t;
        if (cin.fail() || t < 0 || t > 5)
        {
            cin.clear();
            cin.ignore();
            continue;
        }
        break;
    }
    for (int i = 0; i < 10; i++)//為陣列,即各柱子盤子數賦初值
    {
        pan[f(beg)][i] = n - i;
        pan[f(mid)][i] = -1;
        pan[f(final)][i] = -1;
    }
    system("cls");
    gotoxy(hout, 0, 0);
    cout << "從" << beg << "移動到" << final << ",共" << n << "層,延時設定為" << t << endl;
    print_3(m);
    rate(t);
    print2(basic_Y, basic_Y, basic_Y);
    hanoi(n, beg, mid, final, 1, 1, t, m);
    system("cls");
    system("mode con cols=100");
    cout << endl;
    cout << "按回車鍵繼續...";
    while (_getch() != '\r');
}

void draw_2()
{
    check();
    draw();
    draw_pan();
    HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
    gotoxy(hout, 0, 28);
    cout << ",按回車鍵繼續...";
    while (_getch() != '\r');
}

void first()
{
    HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
    check();
    draw();
    draw_pan();
    move_pan(1, beg, mid, n - 1, -1, 1);
    gotoxy(hout, 0, 33);
    cout << ",按回車鍵繼續...";
    while (_getch() != '\r');
}

void aotu()
{
    HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
    check();
    int t;
    while (1)
    {
        cout << "請輸入移動速度(0-5),0-按回車單步演示,1-延時最長,5-延時最短:";
        cin >> t;
        if (cin.fail() || t < 0 || t > 5)
        {
            cin.clear();
            cin.ignore();
            continue;
        }
        break;
    }
    for (int i = 0; i < 10; i++)//為陣列,即各柱子盤子數賦初值
    {
        pan[f(beg)][i] = n - i;
        pan[f(mid)][i] = -1;
        pan[f(final)][i] = -1;
    }
    draw();
    draw_pan();
    gotoxy(hout, 0, 0);
    cout << "從" << beg << "移動到" << final << ",共" << n << "層,延時設定為" << t << endl;
    print_3(1);
    rate(t);
    print2(basic_Y + 14, basic_Y + 14, basic_Y + 14);
    hanoi(n, beg, mid, final, 1, 1, t, 1);
    cout << endl;
    cout << ",按回車鍵繼續...";
    while (_getch() != '\r');
}

void game()
{
    HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
    check();
    draw();
    draw_pan();
    for (int i = 0; i < 10; i++)//為陣列,即各柱子盤子數賦初值
    {
        pan[f(beg)][i] = n - i;
        pan[f(mid)][i] = -1;
        pan[f(final)][i] = -1;
    }
    print_3(1);
    print2(basic_Y + 14, basic_Y + 14, basic_Y + 14);
    while (1)
    {
        gotoxy(hout, 0, 29);
        cout << "請輸入移動的柱號(命令形式:AC A頂端的盤子移到C):";
        cout << "     ";
        gotoxy(hout, 51, 29);
        char c[2];
        for (int i = 0; i < 2; i++)
            cin >> c[i];
        int j = 0, k = 0;//過程參考 提示,棧
        while (pan[f(c[0])][j] != -1 && j < n)
            j++;
        while (pan[f(c[1])][k] != -1 && k < n)
            k++;
        if (pan[f(c[0])][j - 1] > pan[f(c[1])][k - 1] && pan[f(c[1])][k - 1]>0)
        {

            cout << "大盤壓小盤,非法移動!";
            Sleep(500);
            gotoxy(hout, 0, 30);
            cout << "                                 ";
            continue;
        }
        if (c[0] == c[1])
            continue;
        else
        {
            int b = pan[f(c[0])][j - 1];
            move(b, c[0], c[1], 1, 1, 0, 1);
        }
        j = 0, k = 0;//過程參考 提示,棧
        while (pan[f(beg)][j] != -1 && j < n)
            j++;
        while (pan[f(final)][k] != -1 && k < n)
            k++;
        if (j == 0 && k == n)
        {
            cout << "遊戲結束!" << endl;
            break;
        }

    }
    cout << ",按回車鍵繼續...";
    while (_getch() != '\r');
}

int main()
{
    int choice = 1;
    while (choice != 0)
    {
        system("cls");
        cout << "-------------------------------------------------" << endl;
        cout << "1.基本解\n2.基本解(步數記錄)\n3.內部陣列顯示(橫向)" << endl;
        cout << "4.內部陣列顯示(縱向+橫向)\n5.圖形解-預備-畫三個圓柱" << endl;
        cout << "6.圖形解-預備-在起始柱上畫n個盤子\n7.圖形解-預備-第一次移動" << endl;
        cout << "8.圖形解-自動移動版本\n9.圖形解-遊戲版本\n0.退出" << endl;
        cout << "---------------------------------------------------\n[請選擇0-9]" << endl;
        cin >> choice;
        switch (choice)
        {
        case 0:
            break;
        case 1:
            basic();
            break;
        case 2:
            sum = 0;
            basic_inner();
            break;
        case 3:
            sum = 0;
            show_inner();
            break;
        case 4:
            sum = 0;
            show_2(0);
            break;
        case 5:
            draw();
            cout << ",按回車鍵繼續...";
            while (_getch() != '\r');
            break;
        case 6:
            draw_2();
            break;
        case 7:
            sum = 0;
            first();
            break;
        case 8:
            sum = 0;
            aotu();
            break;
        case 9:
            sum = 0;
            game();
            break;
        }
    }
    return 0;
}