元旦时,在宿舍无聊编了一个WINAPI 的HANOI 塔问题的小程序. 我本来想做个动画效果的,结果老是一出来就显示了结果,没有动画演示的效果, 还要请高手来指导一下. :) /* stack class declarations; */ #ifndef _STACK_H_ #define _STACK_H_ #include <windows.h> #include <iostream> using namespace std; typedef struct SElemType{ int iRadius; POINT Position; }ElemType; typedef struct SNode{ ElemType data; struct SNode* pNext; }Node; class CStack{ public: CStack(); bool isEmpty(); //if stack is empty return true bool Push(ElemType elem); //push: insert an element to stack's top bool Pop(ElemType& elem); //pop : delete an element on stack's top bool itsTop(ElemType& elem); //get stack top element; int itsLength(); //get stack's length; void Traverse(HDC hDC); ~CStack(); private: Node* top; Node* base; }; #endif // _STACK_H_ /* class stack's definition; */ #include "stack.h" /* Parameter : none Return : none Description : */ CStack::CStack() { //cout<<"[class default constructor.]"<<endl; base = new Node; top = base; base->pNext = NULL; } // class default constructor /* Parameter : ElemType Return : true or false Description : */ bool CStack::Push(ElemType elem) { Node* pNode = new Node; pNode->data = elem; pNode->pNext = top; top = pNode; return true; } // Push /* Parameter : ElemType& Return : true or false Description : */ bool CStack::Pop(ElemType& elem) { if (!isEmpty()) { elem = top->data; top = top->pNext; return true; } else { return false; } } // Pop /* Parameter : ElemType& Return : true or false Description : get stack top element. */ bool CStack::itsTop(ElemType& elem) { if (!isEmpty()) { elem = top->data; return true; } else { return false; } } // itsTop /* Parameter : HDC Return : none Description : visit stack */ void CStack::Traverse(HDC hDC) { Node* peak = top; while(peak != base) { HBRUSH hBrush; HBRUSH hOldBrush; int radius; POINT pos; radius = peak->data.iRadius; pos = peak->data.Position; hBrush = CreateSolidBrush(RGB(255,0,0)); hOldBrush= (HBRUSH)SelectObject(hDC, hBrush); Rectangle(hDC, pos.x - radius, pos.y - 3, pos.x + radius, pos.y + 3); peak = peak->pNext; SelectObject(hDC, hOldBrush); } } // Traverse /* Parameter : none Return : true or false Description : if the stack is empty return true */ bool CStack::isEmpty() { if (top == base) { return true; } else { return false; } } // isEmpty /* Parameter : none Return : stack length Description : */ int CStack::itsLength() { int iLen = 0; Node* peak = top; while(peak != base) { ++iLen; peak = peak->pNext; } return iLen; } // itsLength /* Parameter : none Return : none Description : */ CStack::~CStack() { //cout<<"[class default destructor. ]"<<endl; } // class default destructor /* class cylinder decalarations. */ #ifndef _CYLINDER_H_ #define _CYLINDER_H_ #include "stack.h" class CCylinder : public CStack{ public: void Location(int ix, int iy); void Draw(HDC hDC); // draw the cylinder in the position private: POINT position; }; #endif // _CYLINDER_H_ /* class cylinder definitions. */ #include "cylinder.h" /* Parameter : none Return : none Description : */ void CCylinder::Location(int ix, int iy) { position.x = ix; position.y = iy; } // Location /* Parameter : HDC Return : none Description : */ void CCylinder::Draw(HDC hDC) { int iLen = 80; int iThick = 3; // draw seat every time Rectangle(hDC, position.x - iLen, position.y - iThick, position.x + iLen, position.y + iThick); Rectangle(hDC, position.x - 3, position.y - 180, position.x + 3, position.y - 3); // draw the dish on the cylinder Traverse(hDC); } // Draw /* class hanoi declarations. */ #ifndef _HANOI_H_ #define _HANOI_H_ #include "cylinder.h" #define TOWERONE 1 #define TOWERTWO 2 #define TOWERTHREE 3 class CHanoi{ public: CHanoi(); CHanoi(int i); int GetDish() {return iDish;} bool isStart() {return bFlag;} void Start() { bFlag = true; } void Stop() { bFlag = false;} void Render(int iDish, int iOrigin, int iAid, int iTarget, HDC hDC); void Move(int iOrigin, int iTarget, HDC hDC); ~CHanoi() {} private: int iDish; bool bFlag; CCylinder one; CCylinder two; CCylinder three; }; #endif // _HANOI_H_ /* class Hanoi definitions. */ #include "hanoi.h" /* Parameter : none Return : none Description : class default constructor. */ CHanoi::CHanoi(int i) { ElemType elem; elem.Position.x = 120; for (int j = 0; j < i; ++j) { elem.iRadius = 75 - 6 * j; elem.Position.y = 393 - 6 * j; one.Push(elem); } // set dish member variable iDish = i; bFlag = true; } // default constructor /* Parameter : int, int, int, int, HDC Return : none Description : */ void CHanoi::Render(int iDish, int iOrigin, int iAid, int iTarget, HDC hDC) { one.Location(120, 400); two.Location(320, 400); three.Location(520,400); if (iDish == 1) { Move(iOrigin, iTarget, hDC); return ; } Render(iDish - 1, iOrigin, iTarget, iAid, hDC); Move(iOrigin, iTarget, hDC); Render(iDish - 1, iAid, iOrigin, iTarget, hDC); } // Render /* Parameter : int , int Return : none Description : */ void CHanoi::Move(int iOrigin, int iTarget, HDC hDC) { ElemType OutElem; ElemType InElem; switch(iOrigin) { case 1: if (one.isEmpty()) { return ; } else { one.Pop(OutElem); } break; case 2: if (two.isEmpty()) { return ; } else { two.Pop(OutElem); } break; case 3: if (three.isEmpty()) { return ; } else { three.Pop(OutElem); } break; } // //char szRadius[30]; //wsprintf(szRadius, "radius is : %d", OutElem.iRadius); //MessageBox(NULL, szRadius, "Hanoi", MB_OK); // fill the origin rectangle with background colour HBRUSH hBrush; HBRUSH hOldBrush; HPEN hWhite; HPEN hOldPen; hWhite = CreatePen(PS_SOLID, 0, RGB(255,255,255)); hOldPen = (HPEN)SelectObject(hDC, hWhite); hBrush = CreateSolidBrush(RGB(255,255,255)); hOldBrush= (HBRUSH)SelectObject(hDC, hBrush); Rectangle(hDC, OutElem.Position.x - OutElem.iRadius, OutElem.Position.y - 3, OutElem.Position.x + OutElem.iRadius, OutElem.Position.y + 3); SelectObject(hDC, hOldBrush); SelectObject(hDC, hOldPen); switch(iTarget) { case 1: if (one.itsTop(InElem)) { InElem.Position.y -= 6; } else { InElem.Position.y = 393; } InElem.Position.x = 120; InElem.iRadius = OutElem.iRadius; one.Push(InElem); break; case 2: if (two.itsTop(InElem)) { InElem.Position.y -= 6; } else { InElem.Position.y = 393; } InElem.Position.x = 320; InElem.iRadius = OutElem.iRadius; two.Push(InElem); break; case 3: if (three.itsTop(InElem)) { InElem.Position.y -= 6; } else { InElem.Position.y = 393; } InElem.Position.x = 520; InElem.iRadius = OutElem.iRadius; three.Push(InElem); break; } // get every cylinder's dish number char buffer[13]; wsprintf(buffer, "cylinder 1: %d", one.itsLength()); TextOut(hDC, 10, 30, buffer, sizeof(buffer) ); wsprintf(buffer, "cylinder 2: %d", two.itsLength()); TextOut(hDC, 10, 50, buffer, sizeof(buffer) ); wsprintf(buffer, "cylinder 3: %d", three.itsLength()); TextOut(hDC, 10, 70, buffer, sizeof(buffer) ); if (three.itsLength() == iDish) { Stop(); } one.Draw(hDC); two.Draw(hDC); three.Draw(hDC); } // Move //----------------------------------------------------------------------------- // Copyright (c) 2009 eryar All rights reserved. // // File : main.cpp // Author : eryar@163.com // Date : 2010-01-03 // Version : 1.0v // // Description : use double buffer to demo hanoi tower. // //============================================================================= #include "hanoi.h" CHanoi hanoi(6); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { MSG Msg; HWND hWnd; WNDCLASS wc; bool bFlag = false; char* szClassName = "CHanoi"; char* szAppName = "Hanoi"; wc.style = CS_HREDRAW|CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = szClassName; if (!RegisterClass(&wc)) { MessageBox(NULL, "register window class failed! ", szAppName, MB_OK|MB_ICONERROR); return false; } hWnd = CreateWindow( szClassName, szAppName, WS_CAPTION|WS_OVERLAPPED|WS_SYSMENU, 0,0, 640, 480, NULL, NULL, hInstance, NULL); if (!hWnd) { MessageBox(NULL, "create window failed! ", szAppName, MB_OK|MB_ICONERROR); return false; } ShowWindow(hWnd, nShowCmd); UpdateWindow(hWnd); while (!bFlag) { while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) { if (Msg.message == WM_QUIT) { bFlag = true; } else { TranslateMessage(&Msg); DispatchMessage(&Msg); } } // This will call WM_PAINT which well render our scene if (hanoi.isStart()) { InvalidateRect(hWnd, NULL, true); UpdateWindow(hWnd); } } return Msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { // these hold the dimensions of the client windows area static cxClient, cyClient; // used to create the back buffer static HDC hDCBackBuffer; static HBITMAP hBitmap; static HBITMAP hOldBitmap; switch(Msg) { case WM_CREATE: HDC hDC; RECT rect; GetClientRect(hWnd, &rect); cxClient = rect.right; cyClient = rect.bottom; // create a surface for us to render to(back buffer) hDCBackBuffer = CreateCompatibleDC(NULL); hDC = GetDC(hWnd); hBitmap = CreateCompatibleBitmap(hDC, cxClient, cyClient); // select the bitmap into the memory device context hOldBitmap = (HBITMAP)SelectObject(hDCBackBuffer, hBitmap); // don't forget to release the DC ReleaseDC(hWnd, hDC); return false; case WM_PAINT: PAINTSTRUCT ps; BeginPaint(hWnd, &ps); // fill our back buffer with white BitBlt(hDCBackBuffer, 0, 0, cxClient, cyClient, NULL,NULL, NULL, WHITENESS); // render scene code here hanoi.Render(hanoi.GetDish(),TOWERONE,TOWERTWO,TOWERTHREE, hDCBackBuffer); // now blit the back buffer to front BitBlt(ps.hdc, 0, 0, cxClient, cyClient, hDCBackBuffer, 0, 0, SRCCOPY); EndPaint(hWnd, &ps); return false; case WM_KEYUP: switch(wParam) { case VK_ESCAPE: PostQuitMessage(0); return false; case VK_RETURN: hanoi.Start(); return false; case VK_SPACE: hanoi.Stop(); return false; default: return false; } return false; case WM_DESTROY: SelectObject(hDCBackBuffer, hOldBitmap); // clean up our back buffer objects DeleteDC(hDCBackBuffer); DeleteObject(hBitmap); // kill the application, this sends a WM_QUIT message PostQuitMessage(0); return false; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } } // WndProc