You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

362 lines
9.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*------------------------------------
项目 汉诺塔演示软件实现最少的移动次数
目标 设计算法 用最少的移动次数将塔座 A 上的 n 个圆盘移到塔座 C 上,并仍按同样顺序叠置。
编译环境 Dev-C++ 5.11
文件 主程序共包括MAIN.cpp Color.hmenu.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);
}
}
// 指定光标跳转到xy的坐标处
// 水平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);
}
//清空xy地方的绘制
//并且绘制下一处 长度为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');
}
}
}