c语言汉诺塔课设计报告,汉诺塔游戏的设计

汉诺塔游戏的设计

作者:苍竹先生

下载源代码

汉诺塔问题是最经典的递归问题,笔者就该问题设计了这个游戏,由用户交互游戏和自动演示两部分组成,支持撤销功能、选关、自动完成等功能。

首先建立了类CMap,该类主要实现用户每一步的操作和画图显示功能,记录的时候只须记录每组盘子的个数和盘子的矩形。代码和注释如下://记录每一步的盘子的情况

class CMap

{

public:

//每组盘子的个数

int iCount[3];

//3组盘子里面,每个盘子的位置,用矩形表示

RECT *Rect[3];

//构造函数

CMap()

{

//三组盘子,每组盘子的矩形

for(int i=0;i<3;i++)

Rect[i]=new RECT[NUM];

//初始化每组盘子的个数

iCount[0]=NUM;

iCount[1]=0;

iCount[2]=0;

//第一组盘子的矩形的位置

for(i=0;i

{

Rect[0][i].left=Center[0]-(NUM-i)*Dx2;

Rect[0][i].right=Center[0]+(NUM-i)*Dx2;

Rect[0][i].bottom=(NUM+1-i)*Dx;

Rect[0][i].top=(NUM-i)*Dx;

}

//第二组盘子的矩形初始化为空

for(i=0;i

{

Rect[1][i].left=0;

Rect[1][i].right=0;

Rect[1][i].bottom=0;

Rect[1][i].top=0;

}

//第三组盘子的矩形初始化为空

for(i=0;i

{

Rect[2][i].left=0;

Rect[2][i].right=0;

Rect[2][i].bottom=0;

Rect[2][i].top=0;

}

}

//运算符重载

CMap operator=(CMap Other)

{

//对新的CMap对象,应该重新分配内存

for(int i=0;i<3;i++)

Rect[i]=new RECT[NUM];

//依次赋值

for(i=0;i<3;i++)

{

iCount[i]=Other.iCount[i];

for(int j=0;j

Rect[i][j]=Other.Rect[i][j];

}

//返回

return *(this);

}

//画图,显示盘子的情况

void OnDraw(HDC hdc)

{

//画出每个盘子

for(int i=0;i<3;i++)

for(int j=0;j

Rectangle(hdc,

Rect[i][j].left,

Rect[i][j].top,

Rect[i][j].right,

Rect[i][j].bottom);

}

//析构函数

~CMap()

{

//内存的释放

for(int i=0;i<3;i++)

{

if(Rect[i]!=NULL)

{

Rect[i]=NULL;

delete Rect[i];

}

}

}

};下面是汉诺塔的主类Hanio,该类的成员函数有OnDraw(),Undo(),Move(),AutoMove()等,分别实现汉诺塔的画图显示、撤销、移动盘子、自动移动盘子等功能,代码及注释如下:class Hanio

{

public:

//当前的步数

int iStep;

//记录每一步的盘子的情况

CMap Record[MAXSTEP];

public:

//构造函数

Hanio()

{

//初始化,步数为0

iStep=0;

//初始化记录

for(int i=0;i

{

Record[i]=CMap();

}

}

//画图,显示汉诺塔的情况

void OnDraw(HDC hdc)

{

Record[iStep].OnDraw(hdc);

}

//撤销

void Undo()

{

if(iStep>0)

iStep–;

//重绘

Draw();

}

//移动盘子

void Move(int iStart,int iEnd)

{

//得到当前盘子的记录

CMap Map=Record[iStep];

//移动的情况判断,去除非法的移动

if(iStart<0||iStart>=3)

return;

if(iEnd<0||iEnd>=3)

return;

if(iStart==iEnd)

return;

if(Map.iCount[iStart]<1)

return;

//得到移动前的开始组,结束组的盘子的个数

int iStartRectNum=Map.iCount[iStart];

int iEndRectNum=Map.iCount[iEnd];

//从小盘子移动到大盘子上面的情况是不可以的。

if(iEndRectNum>0)

if(Width(Map.Rect[iStart][iStartRectNum-1])>=Width(Map.Rect[iEnd][iEndRectNum-1]))

return;

//步数累加

iStep++;

//记录新的盘子的情况

Record[iStep]=Record[iStep-1];

//移走的那一组盘子的个数减少

Record[iStep].iCount[iStart]–;

//被移到的那一组的盘子个数增加

Record[iStep].iCount[iEnd]++;

//重新计算移动后的盘子的矩形

//主要是被移到的那一组的最上面那个盘子的矩形的计算

RECT rect;

rect.left=Center[iEnd]-Width(Map.Rect[iStart][iStartRectNum-1])/2;

rect.right=Center[iEnd]+Width(Map.Rect[iStart][iStartRectNum-1])/2;

rect.bottom=(NUM+1-Map.iCount[iEnd])*Dx;

rect.top=(NUM-Map.iCount[iEnd])*Dx;

Record[iStep].Rect[iEnd][iEndRectNum]=rect;

//刷新

SendMessage(hWnd,WM_PAINT,0,0);

}

//自动移盘子

void AutoMove(int iA,int iB,int iC,int iNum)

{

//递归实现自动移盘子

//递归的出口,如果个数为3,按如下进行移动。

if(iNum==3)

{

Move(iA,iC);

::Sleep(500);

Move(iA,iB);

::Sleep(500);

Move(iC,iB);

::Sleep(500);

Move(iA,iC);

::Sleep(500);

Move(iB,iA);

::Sleep(500);

Move(iB,iC);

::Sleep(500);

Move(iA,iC);

::Sleep(500);

}

//个数大于3,递归实现移动。

else

{

//递归自动移动。

AutoMove(iA,iC,iB,iNum-1);

Move(iA,iC);

::Sleep(500);

AutoMove(iB,iA,iC,iNum-1);

}

}

};程序实现的结果如下图:

Hanio.gif

由于堆栈内存的限制,选关不可能是无限个盘子,本程序设计的最大关数是8。自动移动是用递归实现的,自动移动的过程中,其他消息无法响应,可以改成多线程或由用户控制的形式。上述的程序附有Visual C++源代码,并在Windows XP和Visual C++6.0下调试成功。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值