一、基本思路
1.建立8*8迷宫数组,使用0,1,2,3初始化,0,1,2,3分别表示墙、通道、入口、出口,使用地图贴图知识建立迷宫;
2.建立堆栈结构记录走过的方格编号,即走到某个方格就把该方格编号压入堆栈;若发现路不通,就把该编号出栈,栈顶元素表示
小球所在的方格编号;
3.根据迷宫数组中的值,在初始化函数中对每一格进行贴图,墙贴蓝色的,其余均为白色,找到迷宫入口,记录编号并压入堆栈,
record数组记录走过的棋格,将该编号对应的方格设为0;
4.到了MyPaint函数,根据编号确定小球的贴图坐标,把小球贴到对应方格;
5.根据小球编号判断其上、下、左、右是否能走,假设下能走,那就把下对应的编号压入堆栈,更新record及Nowpos和Prepos;
6.如果发现到了某一格走不动了,就退回到上一格,更新Nowpos和Prepos;
二、效果
三、代码如下
#include "stdafx.h"
#include <stack>
using namespace std;
const int rows = 8,cols = 8;
HINSTANCE hInst;
HBITMAP ball;
HDC hdc,mdc,bufdc;
HWND hWnd;
DWORD tPre,tNow;
char *str;//记录目前搜寻状态的字符串指针
int nowPos,prePos;//nowPos--小球目前位置的方格编号,小球贴图;prePos--小球之前位置的方格编号,以此编号白色覆盖小球贴图
bool find;//是否找到迷宫出口
stack<int> path;//建立int型堆栈path
//0,1,2,3代表墙、通道、入口和出口
int mapIndex[rows*cols] = { 0,2,0,0,0,0,0,0, //材1
0,1,0,1,1,1,1,0, //材2
0,1,0,1,0,1,1,0, //材3
0,1,0,0,0,1,1,0, //材4
0,1,1,1,1,1,1,0, //材5
0,1,0,0,0,0,1,0, //材6
0,0,1,1,1,1,1,0, //材7
0,0,0,0,0,0,3,0 }; //材8
int record[rows*cols];//标记不可通过的方格(墙)及走过的方格
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void MyPaint(HDC hdc);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
while( msg.message!=WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
tNow = GetTickCount();
if(tNow-tPre >= 100)
MyPaint(hdc);
}
}
return msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "canvas";
wcex.hIconSm = NULL;
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HBITMAP bmp;
hInst = hInstance;
hWnd = CreateWindow("canvas", "绘图窗口" , WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
MoveWindow(hWnd,200,100,430,450,true);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hdc = GetDC(hWnd);
mdc = CreateCompatibleDC(hdc);
bufdc = CreateCompatibleDC(hdc);
bmp = CreateCompatibleBitmap(hdc,cols*50,rows*50);
SelectObject(mdc,bmp);
HBITMAP tile;
int rowNum,colNum;
int i,x,y;
tile = (HBITMAP)LoadImage(NULL,"tile.bmp",IMAGE_BITMAP,50,50,LR_LOADFROMFILE);//加载迷宫背景图
ball = (HBITMAP)LoadImage(NULL,"ball.bmp",IMAGE_BITMAP,50,50,LR_LOADFROMFILE);//加载小球图
//按照“mapIndex”数组中的定义进行地图拼接
for (i=0;i<rows*cols;i++)
{
record[i] = mapIndex[i];
rowNum = i / cols; //求列编号
colNum = i % cols; //求行编号
x = colNum * 50; //贴图X的坐标
y = rowNum * 50; //贴图Y的坐标
SelectObject(bufdc,tile);//把墙背景图存到bufdc
if(!mapIndex[i])//遇到墙贴蓝色背景图
BitBlt(mdc,x,y,50,50,bufdc,0,0,SRCCOPY);
else
{
if(mapIndex[i] == 2) //find迷宫入口
{
nowPos = i;//把球的当前位置设为该元素值所代表的迷宫方格
path.push(i);//把该元素编号压入堆栈
record[i] = 0;//表示该编号对应的方格已走过
}
BitBlt(mdc,x,y,50,50,bufdc,0,0,WHITENESS);//该元素对应的方格设为白色
}
}
prePos = cols * rows + 1;//第一次在窗口外;之后画面更新后再记录小球前一次贴图位置
MyPaint(hdc);
return TRUE;
}
void MyPaint(HDC hdc)
{
int rowNum,colNum;//列编号和行编号
int x,y;//贴图坐标
int up,down,left,right;
//清除上次贴图
rowNum = prePos / cols;//列编号
colNum = prePos % cols;//行编号
x = colNum * 50;
y = rowNum * 50;
SelectObject(bufdc,ball);
BitBlt(mdc,x,y,50,50,bufdc,0,0, WHITENESS);
//小球贴图
rowNum = nowPos / cols;
colNum = nowPos % cols;
x = colNum * 50;
y = rowNum * 50;
SelectObject(bufdc,ball);
BitBlt(mdc,x,y,50,50,bufdc,0,0, SRCCOPY);
if(!find)
{
str = "找寻出口中......";
up = nowPos - cols;//小球所在位置上方编号为'Up'的方格
down = nowPos + cols;//小球所在位置下方编号为'Down'的索引值
left = nowPos - 1;
right = nowPos + 1;
if(up>=0 && record[up]) //Up要大于等于数组的最小索引值0(第一个数)
{
path.push(up);
record[up] = 0;
prePos = nowPos;
nowPos = up;//球到了上面去
if(mapIndex[nowPos] == 3) //判断是不是出口
find = true;
}
else if(down<=cols*rows-1 && record[down]) //down要小于等于数组最大索引值
{
path.push(down);
record[down] = 0;
prePos = nowPos;
nowPos = down;
if(mapIndex[nowPos] == 3)
find = true;
}
else if(left>=rowNum*cols&& record[left]) //小球所在列的最小索引值,第0列就是0号;第1列就是8号
{
path.push(left);
record[left] = 0;
prePos = nowPos;
nowPos = left;
if(mapIndex[nowPos] == 3)
find = true;
}
else if(right<=(rowNum+1)*cols-1 && record[right]) //小球所在列的最大索引值,第0列就是7号;第1列就是15号
{
path.push(right);
record[right] = 0;
prePos = nowPos;
nowPos = right;
if(mapIndex[nowPos] == 3)
find = true;
}
else
{
if(path.size() <= 1)//经过一番探索之后,反复的入栈出栈,最后退回到起点
str = "迷宫无出口...";
else
{
path.pop();//path.size>1,则退回到之前的方格
prePos = nowPos;
nowPos = path.top();//重设当前位置
}
}
}
else
{
str = "找到迷宫出口!";
}
TextOut(mdc,0,0,str,strlen(str));
BitBlt(hdc,10,10,cols*50,rows*50,mdc,0,0,SRCCOPY);
tPre = GetTickCount();
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_KEYDOWN:
if(wParam==VK_ESCAPE)
PostQuitMessage(0);
break;
case WM_DESTROY:
DeleteDC(mdc);
DeleteDC(bufdc);
DeleteObject(ball);
ReleaseDC(hWnd,hdc);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}