/*本程序实现C上的汉诺塔动画移动效果,如有建议可和我联系,QQ:928853003*/
/*编写者:杰 */
/*完成时间:2012年9月25日9:02*/
/*有部分函数可参见easyx帮助,运行之前必须安装easyx*/
/*指针的运用尤为重要,尤其是指针的指针容易迷惑人心*/
/*全局变量的定义应该优先与编写函数之前*/
/*常量的定义可以节省大量的编写时间,并可以使程序简洁友善*/
#include
#include
#include
#include
#include
#define Width(N) 220-20*(N)/*计算对应编号N的盘子的宽度*/
#define H 20/* 每个盘子的高度*/
#define LINE 180/*盘子移动的上基准线*/
#define MAX 9/*盘子的最大数目,由于配置优先,数目过大不能完全运行*/
#define DOWN 580/*盘子底部基准线*/
/*-------全局变量-------------------------*/
int a[3]={0,0,0};/*存储A,B,C柱子的当前盘子数目*/
int findNum(char c)
{
switch(c)
{
case 'A':return 0;break;
case 'B':return 1;break;
case 'C':return 2;break;
}
}
struct Rec/*盘子的定义*/
{
int number;
int width;
int left;
int top;
int right;
int bottom;
};
struct Rec r[MAX];/*声明所最大数目的盘子,当然也可以动态分配内存,从而节省资源,但是当前没有必要,有兴趣的的可以自己改写*/
struct Area/*柱子的定义*/
{
char name;/*柱子的名称*/
int x;/*画图区域底边中点的横坐标*/
int y;/*画图区域底边中点的纵坐标*/
struct Rec* recs[MAX];/*定义最大数目的盘子数目*/
void Reduce()/*去除最上位置的盘子*/
{
a[findNum(name)]--;
recs[a[findNum(name)]]=NULL;
}
void Add(int n,int l,int t)/*n为盘子的编号,l为坐标left,t为坐标top---实现盘子的添加*/
{
r[n-1].number=n;
r[n-1].width=Width(n);
r[n-1].left=l;
r[n-1].top=t;
r[n-1].right=r[n-1].left+r[n-1].width;
r[n-1].bottom=r[n-1].top+H;
a[findNum(name)]++;
recs[a[findNum(name)]-1]=&r[n-1];
}
};
struct Area A,B,C;/*声明三个柱子*/
void animation(int left,int top,int right,int bottom,int distance,char direction)/*实现盘子移动的动画*/
/*left、top、right、bottom是坐标,distance是移动距离(可以为负),direction为方向(X为横向,Y为纵向)*/
{
if(distance<=0)/*反方向运动*/
{
for(int i=0;i
{
switch(direction)
{
case 'X':
{
setfillstyle(BLACK);
bar(left-i,top,right-i,bottom);
setfillstyle(WHITE);
bar(left-i-1,top,right-i-1,bottom);
break;
}
case 'Y':
{
setfillstyle(BLACK);
bar(left,top-i,right,bottom-i);
setfillstyle(WHITE);
bar(left,top-i-1,right,bottom-i-1);
break;
}
}
Sleep(5);/*暂停时间,可以修改*/
}
}
else/*正方向移动*/
{
for(int i=0;i
{
switch(direction)
{
case 'X':
{
setfillstyle(BLACK);
bar(left+i,top,right+i,bottom);
setfillstyle(WHITE);
bar(left+i+1,top,right+i+1,bottom);
break;
}
case 'Y':
{
setfillstyle(BLACK);
bar(left,top+i,right,bottom+i);
setfillstyle(WHITE);
bar(left,top+i+1,right,bottom+i+1);
break;
}
}
Sleep(5);/*暂停时间,可以修改*/
}
}
}
void move(struct Area *c,struct Area *d)/*实现盘子从c柱子到d柱子的移动*/
{
int number=a[findNum((*c).name)];
int left=(*(*c).recs[number-1]).left;
int top=(*(*c).recs[number-1]).top;
int right=(*(*c).recs[number-1]).right;
int bottom=(*(*c).recs[number-1]).bottom;
int distance=LINE-top;
animation(left,top,right,bottom,distance,'Y');/*向上运动到LINE线*/
top=LINE;
bottom=LINE+H;
distance=(*d).x-(*c).x;
animation(left,top,right,bottom,distance,'X');/*横向移动到d柱子的正上方*/
left+=distance;
right+=distance;
if(a[findNum((*d).name)]==0)
{
distance=(*d).y-LINE-H;
}
else
{
distance=(*(*d).recs[a[findNum((*d).name)]-1]).top-LINE-H;
}
animation(left,top,right,bottom,distance,'Y');/*放下盘子在d柱子上*/
(*d).Add((*(*c).recs[number-1]).number,left,top+distance);/*完成动画之后,进行d柱子盘子的添加,以及c柱子牌子的去除*/
(*c).Reduce();
}
void hanoi(int n,struct Area *x,struct Area *y,struct Area *z) /*汉诺塔原型算法*/
{
if(n==1)
{
Sleep(2);
move(x,z);
}
else
{
hanoi(n-1,x,z,y);
Sleep(2);
move(x,z);
hanoi(n-1,y,x,z);
}
}
void main()
{
int number;
printf("输入数字(不能大于%d):",MAX);
while(scanf("%d",&number))
{
if(number0)
{
break;
}
printf("请再次输入符合要求的数据:");
}
initgraph(800, 640);
A.name='A';
A.x=140;
A.y=DOWN;
B.name='B';
B.x=400;
B.y=DOWN;
C.name='C';
C.x=660;
C.y=DOWN;
a[findNum(A.name)]=0;
a[findNum(B.name)]=0;
a[findNum(C.name)]=0;
for(int i=1;i<=number;i++)
{
int x=Width(i);
A.Add(i,A.x-x/2,A.y-i*H);
}
a[findNum(A.name)]=number;
/*以上完成全局变量的赋值*/
for(int j=0;j
{
Rec r=(*A.recs)[j];
setfillstyle(WHITE);
bar(r.left,r.top,r.right,r.bottom);
}
/*以上进行初状态画面的绘制*/
hanoi(number,&A,&B,&C);
getch();
closegraph();
}