📄 hanoitowerview.cpp
字号:
// HanoiTowerView.cpp : implementation of the CHanoiTowerView class
//
#include "stdafx.h"
#include "HanoiTower.h"
#include "HanoiTowerDoc.h"
#include "HanoiTowerView.h"
#include "Tower.h"
#include "ParaDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CHanoiTowerView
IMPLEMENT_DYNCREATE(CHanoiTowerView, CView)
BEGIN_MESSAGE_MAP(CHanoiTowerView, CView)
//{{AFX_MSG_MAP(CHanoiTowerView)
ON_COMMAND(ID_RUN_SETUP, OnRunSetup)
ON_COMMAND(ID_RUN_START, OnRunStart)
ON_COMMAND(ID_RUN_RESET, OnRunReset)
ON_COMMAND(ID_RUN_PAUSE, OnRunPause)
ON_WM_TIMER()
ON_UPDATE_COMMAND_UI(ID_RUN_START, OnUpdateRunStart)
ON_UPDATE_COMMAND_UI(ID_RUN_SETUP, OnUpdateRunSetup)
ON_UPDATE_COMMAND_UI(ID_RUN_RESET, OnUpdateRunReset)
ON_UPDATE_COMMAND_UI(ID_RUN_PAUSE, OnUpdateRunPause)
ON_WM_KEYDOWN()
ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
ON_COMMAND(ID_BAR_PAUSE, OnBarPause)
ON_COMMAND(ID_BAR_RESET, OnBarReset)
ON_COMMAND(ID_BAR_START, OnBarStart)
ON_COMMAND(ID_BAR_STOP, OnBarStop)
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CHanoiTowerView construction/destruction
CHanoiTowerView::CHanoiTowerView()
{
// TODO: add construction code here
m_pDisc=NULL;
m_strSpeed="中速";
m_nDelay=500;
m_nArrowPos=1;
m_nCapDiscNum=0;
m_nIsAuto=0;
m_nIsStart=0;
m_nIsReset=0;
m_nIsPause=0;
m_bIsCapDisc=FALSE;
m_bIsFirst=TRUE;
m_enumTimeDelay=DISPLAY;
m_enumTimeMove=MOVE;
}
CHanoiTowerView::~CHanoiTowerView()
{
m_pDisc=NULL;
}
BOOL CHanoiTowerView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CHanoiTowerView drawing
void CHanoiTowerView::OnDraw(CDC* pDC)
{
CHanoiTowerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
m_nDiscNum=pDoc->m_nDiscNum;
m_pDisc=pDoc->m_pDisc;
//m_bIsOpenFile=pDoc->m_bIsOpenFile;
// TODO: add draw code for native data he
DisplayMode(pDoc, pDC); //显示游戏模式
DrawTower(pDoc, pDC); //绘汉诺塔
DrawDisc(pDoc, pDC); //绘disc
if(m_nIsAuto==1)
{
DrawArrow(pDoc, pDC);
if( IsFinishGame() && (!m_bIsCapDisc) )
{
AfxMessageBox("恭喜您完成了游戏",NULL);
m_bIsFirst=TRUE;
m_nArrowPos=1;
pDoc->OnNewDocument();
Invalidate();
}
}
}
/////////////////////////////////////////////////////////////////////////////
// CHanoiTowerView printing
BOOL CHanoiTowerView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CHanoiTowerView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printin
}
void CHanoiTowerView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
/////////////////////////////////////////////////////////////////////////////
// CHanoiTowerView diagnostics
#ifdef _DEBUG
void CHanoiTowerView::AssertValid() const
{
CView::AssertValid();
}
void CHanoiTowerView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CHanoiTowerDoc* CHanoiTowerView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CHanoiTowerDoc)));
return (CHanoiTowerDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CHanoiTowerView message handlers
void CHanoiTowerView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
// TODO: Add your specialized code here and/or call the base class
CRect rectClient;
GetClientRect(rectClient);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(1320,1000);
pDC->SetViewportExt(rectClient.right, -rectClient.bottom);
pDC->SetWindowOrg(-660,900);//将逻辑点(-660,900),映射到设备点(0,0)
//相当于把坐标源点从设备点(0,0)移动到(660,-900)
CView::OnPrepareDC(pDC, pInfo);
}
//利用Doc,Tower数据绘画出汉诺塔
void CHanoiTowerView::DrawTower(CHanoiTowerDoc *pDoc, CDC *pDC)
{
if(m_bIsFirst)
{
m_TowerA.InitialTower(pDoc->m_TowerA.m_nTowerSerialNum,
pDoc->m_TowerA.m_nTopDiscSerialNum,
pDoc->m_TowerA.m_nTotalDiscNum);
m_TowerB.InitialTower(pDoc->m_TowerB.m_nTowerSerialNum,
pDoc->m_TowerB.m_nTopDiscSerialNum,
pDoc->m_TowerB.m_nTotalDiscNum);
m_TowerC.InitialTower(pDoc->m_TowerC.m_nTowerSerialNum,
pDoc->m_TowerC.m_nTopDiscSerialNum,
pDoc->m_TowerC.m_nTotalDiscNum);
m_bIsFirst=FALSE;
}
int i=pDC->SaveDC();
pDC->SelectStockObject(LTGRAY_BRUSH);
//绘塔柱
pDC->Rectangle(m_TowerA.GetPole());
pDC->Rectangle(m_TowerB.GetPole());
pDC->Rectangle(m_TowerC.GetPole());
//绘塔基
pDC->Rectangle(m_TowerA.GetBase());
pDC->Rectangle(m_TowerB.GetBase());
pDC->Rectangle(m_TowerC.GetBase());
//写出塔标号
pDC->TextOut(m_TowerA.m_pointCenter.x-20, m_TowerA.m_pointCenter.y, "塔1");
pDC->TextOut(m_TowerB.m_pointCenter.x-20, m_TowerB.m_pointCenter.y, "塔2");
pDC->TextOut(m_TowerC.m_pointCenter.x-20, m_TowerC.m_pointCenter.y, "塔3");
pDC->RestoreDC(i);
}
void CHanoiTowerView::DrawDisc(CHanoiTowerDoc *pDoc, CDC *pDC)
{
int ref=pDC->SaveDC();
for(int i=0; i<m_nDiscNum; i++)
{
CBrush brush;
brush.CreateSolidBrush((m_pDisc+i)->m_DiscColor);
pDC->SelectObject(&brush);
pDC->Ellipse((m_pDisc+i)->GetDisc());
}
pDC->RestoreDC(ref);
}
void CHanoiTowerView::OnRunSetup()
{
CHanoiTowerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: Add your command handler code here
ParaDlg dlgSetup;
dlgSetup.m_nDiscNum=m_nDiscNum;
dlgSetup.m_nIsAuto=m_nIsAuto;
dlgSetup.m_strSpeed=m_strSpeed;
if(dlgSetup.DoModal()==IDOK)
{
UpdateData(TRUE);
m_nDiscNum=dlgSetup.m_nDiscNum;
m_TowerA.m_nTotalDiscNum=m_nDiscNum;
m_strSpeed=dlgSetup.m_strSpeed;
m_nIsAuto=dlgSetup.m_nIsAuto;
m_bIsFirst=TRUE; //设置标志位,从doc中更新Tower信息
m_bIsOpenFile=FALSE;
m_nIsReset=2;
pDoc->m_nDiscNum=m_nDiscNum; //从对话框中读入参数,并传回Doc类
pDoc->m_nIsAuto=m_nIsAuto;
pDoc->m_bIsOpenFile=FALSE;
pDoc->m_DiscStepList.RemoveAll(); //清除队列中的数据
pDoc->OnNewDocument(); //根据参数初始化游戏
//判断速度选择值
if (m_strSpeed=="高速")
{
m_nDelay=250;
}
else if (m_strSpeed=="中速")
{
m_nDelay=600;
}
else if (m_strSpeed=="低速")
{
m_nDelay=1200;
}
else
{
AfxMessageBox("速度选择不正确,采用默认值(中速)\n 要修改请重新进行游戏选择",
MB_OK);
m_nDelay=500;
m_strSpeed="中速";
}
pDoc->m_nDelay=m_nDelay;
pDoc->m_strSpeed=m_strSpeed;
if(pDoc->m_DiscStepList.IsEmpty() && !m_nIsAuto)
{
pDoc->AutoPlay();
}
//重画屏幕
Invalidate();
}
}
void CHanoiTowerView::DisplayMode(CHanoiTowerDoc *pDoc, CDC *pDC)
{
m_nIsAuto=pDoc->m_nIsAuto;
CFont newfont;
newfont.CreateFont( 45, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
"宋体");
CFont *oldfont=pDC->SelectObject(&newfont);
if(m_nIsAuto==0)
{
pDC->TextOut(-650, 900, "当前游戏模式:自动演示");
}
else
{
pDC->TextOut(-650, 900, "当前游戏模式:手动游戏(用'空格键'和'方向键'控制)");
}
m_strSpeed=pDoc->m_strSpeed;
pDC->TextOut(-650, 860, m_strSpeed);
pDC->SelectObject(oldfont);
}
void CHanoiTowerView::OnRunStart()
{
if(m_nIsStart)
{
return;
}
CHanoiTowerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CClientDC dc(this);
OnPrepareDC(&dc);
MSG message;
m_bIsOpenFile=pDoc->m_bIsOpenFile;
// TODO: Add your command handler code here
if(!m_bIsOpenFile)
{
if(m_nIsPause==0)
{
//每次开始设计标志位
m_nIsStart=1;
m_nIsReset=0;
//第一次,没有初始化矩形列表时,初始化之
if(pDoc->m_DiscStepList.IsEmpty())
{
pDoc->AutoPlay();
}
pDoc->m_nDelay=m_nDelay;
pDoc->m_strSpeed=m_strSpeed;
//开启计时器
SetTimer(m_enumTimeDelay, m_nDelay, NULL);
m_bTimeUp=FALSE;
}
else
{
m_nIsStart=1;
m_nIsPause=0;
}
}
else
{
//如果读入了文件,初始化标志位
m_nIsStart=1;
m_nIsPause=0;
m_nIsReset=0;
m_nDelay=pDoc->m_nDelay;
//开启计时器
SetTimer(m_enumTimeDelay, m_nDelay, NULL);
m_bTimeUp=FALSE;
}
//开始循环显示汉诺塔搬移过程
while( !(pDoc->m_DiscStepList.IsEmpty()) )
{
if(m_nIsReset)
{
break;
}
if(m_bIsOpenFile)
{
pDoc->m_bIsOpenFile=FALSE;
m_bIsOpenFile=FALSE;
}
if(m_nIsStart)
{
//起点矩形
CRect *FromRect;
FromRect=(CRect*)pDoc->m_DiscStepList.GetHead();
pDoc->m_DiscStepList.RemoveHead();
//判断当前移动disc,并修改其位置值
for (int i=0; i<m_nDiscNum; i++)
{
CSize sz=FromRect->Size();
sz.cy=-sz.cy;
if ((m_pDisc+i)->m_sizeDisc==sz)
{
(m_pDisc+i)->m_pointCenterBottom=FromRect->CenterPoint();
(m_pDisc+i)->m_pointCenterBottom.y-=15;
}
}
dc.LPtoDP(FromRect);
InvalidateRect(FromRect);
//终点矩形
CRect *ToRect;
//在新位置画出碟子
ToRect=pDoc->m_DiscStepList.GetHead();
pDoc->m_DiscStepList.RemoveHead();
//判断当前移动disc,并修改其位置值
for ( i=0; i<m_nDiscNum; i++)
{
CSize sz=ToRect->Size();
sz.cy=-sz.cy;
if ((m_pDisc+i)->m_sizeDisc==sz)
{
(m_pDisc+i)->m_pointCenterBottom=ToRect->CenterPoint();
(m_pDisc+i)->m_pointCenterBottom.y-=15;
}
}
dc.LPtoDP(ToRect);
InvalidateRect(ToRect);
pDoc->SetPathName(" ");
}
//定时器延时
while(!m_bTimeUp)
{
if(::PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
{
::TranslateMessage(&message);
::DispatchMessage(&message);
}
}
m_bTimeUp=FALSE; //重新进入延时循环
}
//销毁计时器
KillTimer(m_enumTimeDelay);
m_bTimeUp=FALSE;
//提示完成
if(!m_nIsReset)
{
AfxMessageBox("完成自动演示");
}
else if(m_nIsReset==1)
{
m_nIsReset=0; //取消重置标志位
AfxMessageBox("停止自动演示,并重新设置游戏");
}
//如果运行过程中打开了新文件,
//则不进行链表和disc数组初始化
if(m_bIsOpenFile)
{
AfxMessageBox("读入新游戏演示");
pDoc->InitializeTower();
//取消演示标志位
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -