/*------------------------------------ 项目 : 汉诺塔演示软件实现最少的移动次数 目标 : 设计算法 用最少的移动次数将塔座 A 上的 n 个圆盘移到塔座 C 上,并仍按同样顺序叠置。 编译环境 : Dev-C++ 5.11 文件 :主程序共包括MAIN.cpp, Color.h,menu.h ,variable.h四个文件 开发人 :绳金塔小组 (3人) -------------------------------------*/ #include"variable.h"//头文件、全局变量与函数声明 #include"menu.h" //菜单文件 #include"Color.h" //颜色绘制文件 int main() { start_up(); beginner(); while (loop) { system("cls"); option=menu(); switch (option) { case 1: HideCursor(); do{ printf("需要叠的层数:"); scanf("%d", &N); if(N<=0) { printf("输入错误!\n\n"); // 清除输入缓冲区,避免无效输入影响下一次循环 while (getchar() != '\n') continue; } }while(N<=0); break; case 2: int mode; do { printf("请输入你要选择的模式,[1]手动[2]自动\n"); scanf("%d", &mode); if (mode == 1) autoPlay = 0; // 用户选择手动模式,autoPlay 设置为 0 else if (mode == 2) autoPlay = 1; // 用户选择自动模式,autoPlay 设置为 1 else { printf("输入错误!\n\n"); // 清除输入缓冲区,避免无效输入影响下一次循环 while (getchar() != '\n') continue; } } while (mode != 1 && mode != 2); break; case 3: init(); getchar(); hanoi(N, 'A', 'B', 'C'); break; case 4: init(); getchar(); pillarhanoi(N, 'A', 'B', 'C'); break; case 5: coloreset=0;// 重置颜色 colorinit(); getchar(); colorhanoi(N, 'A', 'B','C'); break; case 6: dectction();//判断盘数是否正确 coloreset=0;// 重置颜色 parityinit(); getchar(); parityhanoi(N, 'A', 'B','C'); break; case 7: speedMenu(); getchar(); break; case 8: Help(); break; case 9: printAbout(); break; case 0: conclusion(); break; default: break; } } return 0; } void dectction(){ if(N % 2 == 1) { getchar(); printf("该模式下,您的圆盘数必须为偶数,详细信息请看“规则说明”\n\n"); do{ printf("修改需要叠的层数:"); scanf("%d", &N); if(N<=0||N % 2 == 1) { printf("输入错误!\n\n"); // 清除输入缓冲区,避免无效输入影响下一次循环 while (getchar() != '\n') continue; } }while(N<=0||N % 2 == 1); } } // 指定光标跳转到x,y的坐标处 // 水平x,竖直y void gotoxy(int x,int y) { HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); COORD pos; pos.X = x; pos.Y = y; SetConsoleCursorPosition(handle,pos); } //定义隐藏光标函数 void HideCursor() { CONSOLE_CURSOR_INFO cursor; cursor.bVisible = FALSE; cursor.dwSize = sizeof(cursor); HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorInfo(handle, &cursor); } //清空x,y地方的绘制 //并且绘制下一处 长度为n 的汉诺塔 void drawHanoi(int &x,int &y,int n,int next) { // 清空原来的 char replace[2*n+1] = ""; for(int i = 0; i < 2*n + 1; i++){ replace[i] = ' '; if(i == n && y != 1){ replace[i] = pillar; } if(i == 2*n){ replace[i+1] = '\0'; } } gotoxy(x - n,y); printf("%s",replace); // 绘制新的 if(next != -1){ x += next_go[next][0]; y += next_go[next][1]; } for(int i = 0; i < 2*n + 1; i++){ if(i == n && y != 1){ replace[i] = pillar; }else if(i == 0){ replace[i] = hanoiLeft; }else if(i == 2*n){ replace[i] = hanoiRight; }else{ replace[i] = hanoiAir; } if(i == 2*n){ replace[i+1] = '\0'; } } gotoxy(x - n,y); printf("%s",replace); Sleep(sleepTime); } void init() { steps=0; system("cls"); HideCursor(); // 初始化柱子信息 abc_pillar[0][0] = N; for(int i = 1; i <= N; i++ ){ abc_pillar[0][i] = N + 1 - i; } //高度 = 上下墙(2) + deep(4) + 上空行(1) //宽度 = 左右墙(2) + 3个区块[3*(deep*2+1)] + 两个中间空行(2) mapHeight = 2 + N + 1; mapWidth = 2 + 3 * (N * 2 + 1) + 2; //柱子0(a)水平坐标 = 左边墙(1) + deep(4) //柱子1(b)水平坐标 = 柱子1 + 2*deep + 2 //柱子2(c)水平坐标 = 柱子2 + 2*deep + 2 abc_x[0] = 1 + N; abc_x[1] = abc_x[0] + 2* N + 2; abc_x[2] = abc_x[1] + 2* N + 2; // 绘制地图 for(int i = 0; i < mapHeight; i++){ for(int j = 0; j < mapWidth; j++){ //墙体绘制 if(i == 0 || i == mapHeight - 1 || j == 0 || j == mapWidth - 1){ gotoxy(j,i); printf("%c",wall); } //绘制柱子 else if( i > 1 && i < mapHeight - 1){ if(j == abc_x[0] || j == abc_x[1] || j == abc_x[2]){ //初始化绘制圆盘 int abc_x_index = 0; if(j == abc_x[0]) abc_x_index = 0; else if(j == abc_x[1]) abc_x_index = 1; else if(j == abc_x[2]) abc_x_index = 2; drawHanoi(j,i,abc_pillar[abc_x_index][N - i + 2],-1); } } } } } // a ==> c // startx starty == > toX toY void move(char from,char to) { gotoxy(0,mapHeight+1); printf("%c--->%c\n",from,to); // 获取from的柱子有多少高定位从哪开始 int fromHeight = abc_pillar[from-'A'][0]; int n = abc_pillar[from-'A'][fromHeight]; int x = abc_x[from-'A']; int y = 2 + N - fromHeight; abc_pillar[from-'A'][0]--; // 获取to 的柱子有多高 定位到哪结束 abc_pillar[to-'A'][0]++; int toHeight = abc_pillar[to-'A'][0]; abc_pillar[to-'A'][toHeight] = n; int toX = abc_x[to-'A']; int toY = 2 + N - toHeight; // 取出盘 ==> 上升至顶部 while(y > 1){ drawHanoi(x,y,n,up); } // 移动盘 ==> 移动至指定盘 if(x < toX){ while(x < toX){ drawHanoi(x,y,n,right); } }else if(x > toX){ while(x > toX){ drawHanoi(x,y,n,left); } } // 放置盘 ==> 下降到上面 while(y < toY){ drawHanoi(x,y,n,down); } //手动播放 if(autoPlay == 0){ gotoxy(0,mapHeight+3); printf("请按回车进行下一步. . ."); getchar(); } steps++; } /** * from 从哪开始 * temp 暂时经过 * to 移动到哪 */ void hanoi(int n,char from ,char temp,char to) { if(n==1){ // from到to只有一个需要移动就直接移动 if(key1== code1){ gotoxy(0,mapHeight+3); printBlank(50); gotoxy(0,mapHeight+3); printf("请按回车键开始\n"); getchar(); gotoxy(0,mapHeight+3); printBlank(30); key1++; } move(from, to); //递归截止条件 } else{ hanoi(n-1,from ,to,temp); //移动from 上面的n-1 ==> temp 暂存 move(from,to); //移动from 剩下的1 ==> to 目的地 hanoi(n-1,temp,from,to); //移动temp 暂存的n-1 ==> to 目的地 } // 动画结束后清除所有柱子上的圆盘 if(n==N){ code1++; clearPillar(0);// 清除A柱子 clearPillar(1);// 清除B柱子 clearPillar(2);// 清除C柱子 gotoxy(0, mapHeight + 3); printf(" 动画结束,共移动了%d步。\n按R重复播放,按任意键退出. . .",steps); char choice = getch(); // 获取用户的选择 if (choice == 'R' || choice == 'r') { system("cls"); HideCursor(); init(); hanoi(N, 'A', 'B', 'C'); } } } void pillarhanoi(int n, char source, char temp, char goal) { if (n == 1) { if(key2== code2){ gotoxy(0,mapHeight+3); printf("请按回车键开始\n"); getchar(); gotoxy(0,mapHeight+3); printBlank(30); key2++; } move( source, temp); move( temp, goal); } else { pillarhanoi(n - 1, source, temp, goal); move( source, temp); pillarhanoi(n - 1, goal, temp, source); move(temp, goal); pillarhanoi(n - 1, source, temp, goal); } // 动画结束后清除所有柱子上的圆盘 if(n==N){ code2++; clearPillar(0); // 清除A柱子 clearPillar(1); // 清除B柱子 clearPillar(2); // 清除C柱子 gotoxy(0, mapHeight + 3); printf(" 动画结束,共移动了%d步。\n按R重复播放,按任意键退出. . .",steps); char choice = getch(); // 获取用户的选择 if (choice == 'R' || choice == 'r') { system("cls"); HideCursor(); init(); pillarhanoi(N, 'A', 'B', 'C'); } } }