⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hanoiview.cpp

📁 一个经典的智力游戏
💻 CPP
字号:
// HanoiView.cpp : implementation of the CHanoiView class
//

#include "stdafx.h"
#include "Hanoi.h"

#include "HanoiDoc.h"
#include "HanoiView.h"

#include "DlgOption.h"

#include "mmsystem.h"              //I added
#pragma comment(lib,"winmm.lib") 
 
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/*
enum DrawType
{
	DT_NORMAL;
	DT_MOUSEMOVE;
	DT_MOUSEDOWN;
}
*/
/////////////////////////////////////////////////////////////////////////////
// CHanoiView

IMPLEMENT_DYNCREATE(CHanoiView, CView)

BEGIN_MESSAGE_MAP(CHanoiView, CView)
	//{{AFX_MSG_MAP(CHanoiView)
	ON_WM_ERASEBKGND()
	ON_COMMAND(ID_EDIT_CUT, OnEditCut)
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
	ON_COMMAND(ID_HELP, OnHelp)
	ON_COMMAND(ID_OPTION_SET, OnOptionSet)
	ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
	ON_COMMAND(ID_OPTION_RESTART, OnOptionRestart)
	ON_COMMAND(ID_DEMO, OnDemo)
	ON_WM_LBUTTONUP()
	ON_WM_TIMER()
	ON_WM_DESTROY()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CHanoiView construction/destruction

CHanoiView::CHanoiView()
{
	// TODO: add construction code here

}


CHanoiView::~CHanoiView()
{
}

BOOL CHanoiView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs
		return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CHanoiView drawing
int FirstTime=0;
void CHanoiView::OnDraw(CDC* pDC)
{
/*	CBitmap bgBmp;
	bgBmp.LoadBitmap(IDB_BG);
	pDC->BitBlt(0,0,520,425, 
*/
//	Sleep (2000);
//	pDC->Rectangle (100,100,200,200);

/*
	int* p_temp=new int[5];
	CString temp;
	for(int i=0;i<5;i++)
	{*(p_temp+i)=2;
//	temp.Format(" %d,%d",*(p_temp+i),FirstTime);
  //	 MessageBox( temp);
	}
*/
	


	if (FirstTime==0)//作一些初始化工作!!
	{
		NUM=3;
		state= new int[NUM];
	//	for(int i=0;i<NUM;i++)	*(state+i)=1;//放到第一列!
		
		DrawType=new int[3];
	//	for( i=1;i<=3;i++)	*(DrawType+i-1)=0;//初始化为正常显示!!

		NewGame();


		DrawColumn(state,DrawType,pDC);//
	}

	FirstTime++;

	DrawColumn(state,DrawType,pDC);



  CHanoiDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
}

/////////////////////////////////////////////////////////////////////////////
// CHanoiView diagnostics

#ifdef _DEBUG
void CHanoiView::AssertValid() const
{
	CView::AssertValid();
}

void CHanoiView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CHanoiDoc* CHanoiView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CHanoiDoc)));
	return (CHanoiDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CHanoiView message handlers

BOOL CHanoiView::OnEraseBkgnd(CDC* pDC) 
{
	SetBG(pDC);

	return 1;

 //return CView::OnEraseBkgnd(pDC);//这句话是将客户区涂白色!!

}


void CHanoiView::DrawColumn(int* state, int* DrawType,CDC * dc)
{
 	SetBG(dc);
	int temp;
	for(int i=1;i<=3;i++)  //三列!!
	{
		CBrush Brush;
 //出现那个复杂错误,因为不能一次性创建两个刷子!!
		if(i==1)
		{
				if(*(DrawType+0)==0)		Brush.CreateSolidBrush (RGB(150,50,0));//当心,原来写成“=”导致程序失去响应!
				if(*(DrawType+0)==1)		Brush.CreateSolidBrush (RGB(255,0,0));//当心,原来写成“=”导致程序失去响应!
				if(*(DrawType+0)==2)		Brush.CreateSolidBrush (RGB(33,33,33));//当心,原来写成“=”导致程序失去响应!

		}	
	 	 else 	if(i==2)
		{
				if(*(DrawType+1)==0)		Brush.CreateSolidBrush (RGB(0,150,50));//当心,原来写成“=”导致程序失去响应!
				if(*(DrawType+1)==1)		Brush.CreateSolidBrush (RGB(0,255,0));//当心,原来写成“=”导致程序失去响应!
				if(*(DrawType+1)==2)		Brush.CreateSolidBrush (RGB(33,33,33));//当心,原来写成“=”导致程序失去响应!
		}
		 else 	if(i==3)
		{
				if(*(DrawType+2)==0)		Brush.CreateSolidBrush (RGB(50,0,150));//当心,原来写成“=”导致程序失去响应!
				if(*(DrawType+2)==1)		Brush.CreateSolidBrush (RGB(0,0,255));//当心,原来写成“=”导致程序失去响应!
				if(*(DrawType+2)==2)		Brush.CreateSolidBrush (RGB(33,33,33));//当心,原来写成“=”导致程序失去响应!
		}
		dc->SelectObject (&Brush);
		temp=0;
		for (int j=0;j<NUM;j++)
		{
			if( *(state+j)==i)
			{
				temp++;          // temp表征高度	;j表征宽度!
		 		dc->Rectangle (100+(i-1)*160-(50-j*3),400-20*temp,100+(i-1)*160+(50-j*3),400-20*(temp-1));		
			}
		}
	}
/*
//============================================================================
		temp=0;
		for (j=0;j<=NUM;j++)
		{
			if( *(state+j)==2)
			{
				temp++;
				dc->Rectangle (260-(50-j*3),400-20*temp,260+(50-j*3),400-20*(temp-1));
				//dc->Rectangle (100+(i-1)*160-(50-j*3),400-20*temp,100+(i-1)*100+(50-j*3),400-20*(temp-1));		
				//dc->Rectangle (100,100,200*j,200*j);
			}
		}
//============================================================================
		temp=0;
		for (j=0;j<=NUM;j++)
		{
			if( *(state+j)==3)
			{
				temp++;
				dc->Rectangle (420-(50-j*3),400-20*temp,420+(50-j*3),400-20*(temp-1));
				//dc->Rectangle (100+(i-1)*160-(50-j*3),400-20*temp,100+(i-1)*100+(50-j*3),400-20*(temp-1));		
				//dc->Rectangle (100,100,200*j,200*j);
			}
		}
//============================================================================
 */
}



void CHanoiView::SetBG(CDC *dc)
{
	// 设置所要求背景色的刷子 
   CBrush brush;
   CBitmap bmp;
   bmp.LoadBitmap(IDB_BG);
   brush.CreatePatternBrush(&bmp);//用位图建立刷子
   CBrush* pOldBrush = dc->SelectObject(&brush); // 同时保存旧刷子 
   CRect rect; 
   dc->GetClipBox(&rect);   // 获取擦除所需的区域 
   dc->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY); 
   dc->SelectObject(pOldBrush); 
}
 

void CHanoiView::OnEditCut() 
{
	//下面仅仅是用于测试获取dc
 	CClientDC CCDC(this);
 	CClientDC* dc=&CCDC; //能够获取当前指针!!
//	CDC* dc=GetDC( );//也能够获取当前指针!!
    SetBG(dc);	
}



int lastRegion=0;//记录了上一次所在区域

void CHanoiView::OnMouseMove(UINT nFlags, CPoint point) 
{
	int x,y;
	x=point.x;
	y=point.y;

	int temp=0;//记录经过的是哪个区域;
	if (x>20&&x<=180)		{temp=1;SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR6));}
	else if (x>180&&x<=340)	{temp=2;SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR7));}
	else if (x>340&&x<=500)	{temp=3;SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR8));}

	if( temp!=0)							//仅对有效区域中的事件作出相应
	{
	//	if(temp!=Source)*(DrawType+temp-1)=1;//置为1(Mouse_move)
		for(int i=1;i<=3;i++)
		{
			if(i==temp && i!=Source)	*(DrawType+i-1)=1;//置为1(Mouse_move)
			if(i!=temp && i!=Source)	*(DrawType+i-1)=0;//置为0(Normal)
		}


		CClientDC * dc = (CClientDC *) GetDC();

	    if(temp!=lastRegion)
		{
			DrawColumn(state,DrawType,dc);//防止同一区域内移动时频繁刷新,导致闪烁!

			CString temp("snd\\1.wav");
		//	playSnd(temp);	// 鼠标切换时候就不发声了,否则太乱!!

		}
		lastRegion=temp;
}


	CView::OnMouseMove(nFlags, point);
}

void CHanoiView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	int x,y;
	x=point.x;
	y=point.y;
//	if (x>20&&x<180)MessageBox("sfd");
	int temp=0;//记录经过的是哪个区域;
	if (x>20&&x<=180)temp=1;
	else if (x>180&&x<=340)temp=2;
	else if (x>340&&x<=500)temp=3;
	
	int Last=-1;						//记录Source最后一次出现,也即Source列的最上面!
	bool Success=true;					//判断是否可以移动!!

 	if (temp!=0)					//仅对有效区域中的事件作出相应
	{
		if (Source==0)
		{
			Source=temp;
			*(DrawType+temp-1)=2; 


			CString temp("snd\\2.wav");
			playSnd(temp);	// TODO: Add your command handler code here

		}//Source==0必是奇数次按键,

		else
		{
			Dest=temp;
			for(int i=0;i<NUM;i++)
			{
				if(*(state+i)==Source)Last=i;       //通过不断刷新,记录了最后一次出现的位置
			}
		//	CString aa;
		//	aa.Format ("%d",Last);
		//	MessageBox (aa);
		  
			if(Last==-1)Success=false; //虽然没有此句,到最后也不过把一个State前面的置值,但毕竟不爽,还是这样完美!

			
			for(i=Last;i<NUM;i++)
			{
				if(*(state+i)==Dest)Success=false;       //若后面有同号者,则不成功!(具体缘由请见我的程序设计报告)
			}
			if (Success==false)
			{
				*(DrawType+Source-1)=0;
				Source=0;
				Dest=0;// 对失败时多余,但为整洁而保留
			}
			else if (Success==true)
			{
				*(DrawType+Source-1)=0;
				*(state+Last)=Dest;
				Source=0;
				Dest=0;//  保留

				steps++;
//===============================SetPanel=========================================
				CString tem;
				CStatusBar *pStatus;
				pStatus=(CStatusBar *)AfxGetApp()->m_pMainWnd->GetDescendantWindow(AFX_IDW_STATUS_BAR);
				
				tem.Format ("本局已执行 %d 步",steps);

				pStatus->SetPaneText (0,tem);
//===============================SetPanel=========================================



				CString temp("snd\\3.wav");
				playSnd(temp);	// TODO: Add your command handler code here

			}
			
			for(i=1;i<=3;i++)*(DrawType+i-1)=0;//全部变成正常!!




		}
		CClientDC * dc = (CClientDC *) GetDC();
		DrawColumn(state,DrawType,dc);//

//======================判断是否已经成功================
		int EndOfGame=0;
		for(int i=0;i<NUM;i++)
		{
			if(*(state+i)!=3)	EndOfGame++;
		}
		if (EndOfGame==0)
		{
			CString temp;
			

			CString tem("snd\\end.wav");
			playSnd(tem);	// TODO: Add your command handler code here


			
			Sleep(100);

			temp.Format ("恭喜,您成功了!您共走了 %d 步!",steps);
			MessageBox(temp);

	NewGame();

		}
//======================判断是否已经成功================
	}
 


	
	/*========================Test=========================
	CClientDC * dc = (CClientDC *) GetDC();
	CString test;
	test.Format ("%d -> %d",Source,Dest);
	dc->TextOut (0,0,test);
	for (int i=0;i<NUM;i++){
		test.Format ("%d",*(state+i));
		dc->TextOut (12*i,30,test);
	}
	//========================Test=========================*/

	SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR2));
	CView::OnLButtonDown(nFlags, point);
}

void CHanoiView::OnEditCopy() 
{
	// 这里仅仅是测试播放声音!!
	CString temp("siren.wav");
	playSnd(temp);
//	playSnd(temp);

 
}


bool CHanoiView::playSnd(CString Filename)
{
	/*
	WORD m_wDeviceID;

Load:

	MCI_OPEN_PARMS OpenParms;
	OpenParms.lpstrDeviceType="waveaudio";
	OpenParms.lpstrElementName=Filename; //这样是可以的!!
	if(mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_ELEMENT|MCI_OPEN_TYPE,(DWORD)(LPVOID)&OpenParms))
		return FALSE;
	m_wDeviceID=OpenParms.wDeviceID;

Play:	
    MCI_PLAY_PARMS PlayParms;
	mciSendCommand(m_wDeviceID,MCI_SEEK,MCI_SEEK_TO_START,NULL);
	if(mciSendCommand(m_wDeviceID,MCI_PLAY,NULL,(DWORD)(LPVOID)&PlayParms))
		return FALSE;
 
	Sleep(1500);

Stop:
	mciSendCommand(m_wDeviceID,MCI_STOP,NULL,NULL);
*/
	::PlaySound(Filename, NULL, SND_ASYNC | SND_FILENAME);//发现不用MCI,直接有函数!!
	return true;


}

void CHanoiView::OnHelp() 
{
//	WinExec("\"G:\\game\\***.exe\" 参数",SW_SHOWDEFAULT);
//	WinExec("c:\\windows\\hh.exe hanoi.chm",SW_SHOWDEFAULT); 也可以的!

	WinExec("hh.exe hanoi.chm",SW_SHOWDEFAULT);
	
}

void CHanoiView::OnOptionSet() 
{

	CDlgOption dlg;
	dlg.m_num =NUM;
	if(dlg.DoModal ()==IDOK)
	{
		NUM=dlg.m_num ;
		NewGame();	
	}
}

void CHanoiView::OnEditPaste() 
{
	CString temp("siren.wav");
	playSnd(temp);	// TODO: Add your command handler code here
	
}

void CHanoiView::DELAY(int mSeconds)//实际未用,采用的是sleep!
{
	DWORD dwStart = GetTickCount();
	while( GetTickCount() - dwStart >= mSeconds );

}

void CHanoiView::OnOptionRestart() 
{
	// TODO: Add your command handler code here
	NewGame();	

	CClientDC * dc = (CClientDC *) GetDC();
	DrawColumn(state,DrawType,dc);


}

void CHanoiView::OnDemo() 
{
	NewGame();

	CClientDC * dc = (CClientDC *) GetDC();
	DrawColumn(state,DrawType,dc);

	hanoi(NUM,1,2,3);

	CString temp("snd\\end.wav");
	playSnd(temp);	// TODO: Add your command handler code here

	Sleep(1600);
	NewGame();

}

void CHanoiView::NewGame()
{
	for(int i=0;i<NUM;i++)
	{
		 *(state+i)=1;		//全部复位!!
	}
	for( i=1;i<=3;i++)	*(DrawType+i-1)=0;//初始化为正常显示!!

	Source=0;
	Dest=0;

	steps=0;//未走子

	SetTimer(1,1000,NULL);

	startTime=CTime::GetCurrentTime ();
}



void CHanoiView::hanoi(int n, int Column1, int Column2, int Column3)
{
	if(n==1)move(Column1,Column3);
	else
	{
		hanoi(n-1,Column1,Column3,Column2);
		move(Column1,Column3);
		hanoi(n-1,Column2,Column1,Column3);
	}

}

void CHanoiView::move(int a, int b)
{
	Sleep(800);
	int Last=-1;
	for(int i=0;i<NUM;i++)
	{
		if(*(state+i)==a)Last=i;       //通过不断刷新,记录了最后一次出现的位置
	}
	if (Last==-1)MessageBox("sfd");
	*(state+Last)=b;
	CClientDC * dc = (CClientDC *) GetDC();
	DrawColumn(state,DrawType,dc);
}



void CHanoiView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR2));	
	CView::OnLButtonUp(nFlags, point);

}

void CHanoiView::OnTimer(UINT nIDEvent) 
{

	CString temp;
	CStatusBar *pStatus;
	pStatus=(CStatusBar *)AfxGetApp()->m_pMainWnd->GetDescendantWindow(AFX_IDW_STATUS_BAR);
	CTime time=CTime::GetCurrentTime ();
	if (time.GetSecond() -startTime.GetSecond ()>=0)
	{
		temp.Format ("这一局您已经走了:%d分%d秒 ",time.GetMinute() -startTime.GetMinute() ,time.GetSecond() -startTime.GetSecond ());
	}
	else if (time.GetSecond() -startTime.GetSecond ()<0)
	{
		temp.Format("这一局您已经走了:%d分%d秒 ",time.GetMinute() -startTime.GetMinute()-1 ,time.GetSecond() -startTime.GetSecond ()+60);
	}
	pStatus->SetPaneText (2,temp);
	CView::OnTimer(nIDEvent);
}

void CHanoiView::OnDestroy() 
{
	CView::OnDestroy();
	
	KillTimer(1);	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -