📄 hanio.h
字号:
#include "windows.h"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include "time.h"
#include "resource.h"
#define X 600
#define Y 400
#define ESC 27
#define Dx 20
#define Dx2 10
#define MAXLEVEL 8
#define MAXSTEP 1000
int NUM=3;
const char szTitle[]="Hanio 1.0";
const char szWndClass[]="WndClass";
const char szAuthor[]="作者:武冬生";
const char szMail[]="E-mail:cangzhu@163.com";
const char szMsg1[]="F2 撤销 F3 自动";
const char szMsg2[]="F4 上一关 F5 下一关 ESC 退出";
char szCurMsg[256];
const int Center[3]={X/6,X/2,5*X/6};
HWND hWnd;
void Draw();
BOOL MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
//矩形的宽度函数
int Width(RECT rect)
{
return abs(rect.right-rect.left);
}
//判断一点是不是在一个矩形内
BOOL PointInRect(POINT point,RECT Rect)
{
int x=point.x;
int y=point.y;
if(x>Rect.left&&
x<Rect.right&&
y>Rect.top&&
y<Rect.bottom)
return TRUE;
else
return FALSE;
}
//又由点判断该点在第几个盘子的位置
int PointToNum(POINT pt)
{
if(pt.x>=0&&pt.x<=X/3)
return 0;
if(pt.x>X/3&&pt.x<=2*X/3)
return 1;
if(pt.x>2*X/3&&pt.x<=X)
return 2;
else
return -1;
}
//记录每一步的盘子的情况
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<NUM;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<NUM;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<NUM;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<NUM;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<iCount[i];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];
}
}
}
};
class Hanio
{
public:
//当前的步数
int iStep;
//记录每一步的盘子的情况
CMap Record[MAXSTEP];
public:
//构造函数
Hanio()
{
//初始化,步数为0
iStep=0;
//初始化记录
for(int i=0;i<MAXSTEP;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);
}
}
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -