相关分类 VC实例 ->实例 ->VCShare

VC实例迷宫问题寻路鼠标

关键字 VC实例 迷宫 寻路 鼠标 行列 标志

点击查看效果  

查看分析

下载源代码 

一,新建一个单文档程序Ex0605。

二,增加两个类,最好放在单独的文件中,放在视图类也行,就是不规范。

以上是头文件的内容

class CMazeMap//迷宫地图类

{

public:

bool SearchPath();//查找路径

bool IslegalRowCol(int iRow,int iCol);//行列是否合法

CRect ChangeMapState(CRect r,CPoint pt);//根据范围和鼠标点击的坐标改变状态

void CopyData(const CMazeMap& other);//复制数据,不改变行列号

CMazeMap();

CMazeMap(const CMazeMap& other);

~CMazeMap();

void Draw(CDC* pDC,CRect r);//绘出迷宫地图的信息

void SetMapState(int iRow,int iCol,int iState);//设置某一块的状态

void ChangeRowCol(int iRow ,int iCol);//改变行列数,行列数变小时,会丢部分数据

int GetMapState(int iRow,int iCol){return m_pMapData[iRow][iCol];};

int GetRowNum(){return m_iRowNum;};

int GetColNum(){return m_iColNum;};

private:

void SetColNum(int iColNum);//设置列数,数据不变

void SetRowNum(int iRowNum);//设置行数,数据不变

void ReleaseData();//释放数据

int** CreateInitData();//new数据,并初始化

int** m_pMapData ;//数据内容,0表示不可到达,1表示可到达,2表示处于当前路径

int m_iRowNum ;//行号

int m_iColNum ;//列号

};

class CSearchPath//寻找第一条路径算法类

{

public:

bool GetAStepRowCol(int iStepNO,int& iRow,int& iCol);//取得某一步的行列

int GetStepNum();//取得总步数

CSearchPath(CMazeMap& map);

bool Search();//查找每第一条路径

private:

bool Back();//退回

bool Move(int iType);//移动(右移下移左移上移)

int m_iStep ;//当前步数,0表示起点

int m_rowSet[1000] ;//存放每步的行

int m_colSet[1000] ;//存放每步的列

int m_iMoveType[1000];//每步的移动方式

CMazeMap m_map ;//地图数据

};

以下是源文件的内容

CMazeMap::CMazeMap()

{

SetRowNum(3);

SetColNum(3);

m_pMapData = CreateInitData();

}

CMazeMap::CMazeMap(const CMazeMap& other)

{

m_iRowNum = other.m_iRowNum ;

m_iColNum = other.m_iColNum ;

m_pMapData = CreateInitData();

//复制数据,以免数据丢掉

for(int i = 0 ; i < m_iRowNum ; i++ )

memcpy(m_pMapData[i],other.m_pMapData[i],sizeof(int)*m_iColNum);

}

CMazeMap::~CMazeMap()

{

ReleaseData();

}

int** CMazeMap::CreateInitData()

{

int ** pMapData = new int*[m_iRowNum];

if( NULL == pMapData )

return NULL ;

for(int i = 0 ; i < m_iRowNum ; i++ )

{

pMapData[i] = new int[m_iColNum];

memset(pMapData[i],0,sizeof(int)*m_iColNum);//置0

}

return pMapData ;

}

void CMazeMap::ReleaseData()

{

if( NULL == m_pMapData )

return ;

for(int i = 0 ; i < m_iRowNum ; i++ )

delete[] m_pMapData[i] ;

delete[] m_pMapData ;

m_pMapData = NULL;

}

void CMazeMap::SetRowNum(int iRowNum)

{

if( iRowNum < 3 )

iRowNum = 3 ;//最少行数是3

if( iRowNum > 20 )

iRowNum = 20 ;//最大20

m_iRowNum = iRowNum ;

}

void CMazeMap::SetColNum(int iColNum)

{

if( iColNum < 3 )

iColNum = 3 ;//最少行数是3

if( iColNum > 20 )

iColNum = 20 ;//最大20

m_iColNum = iColNum ;

}

void CMazeMap::ChangeRowCol(int iRow, int iCol)

{

CMazeMap tmp(*this);//备份当前数据

ReleaseData();

if( 0 != iRow )

SetRowNum(iRow);

if( 0 != iCol )

SetColNum(iCol);

m_pMapData = CreateInitData();

CopyData(tmp);//复制数据

}

void CMazeMap::SetMapState(int iRow, int iCol,int iState)

{

if( iRow < 0 || iRow >= m_iRowNum || iCol < 0 || iCol >= m_iColNum )

return ;//行列号不合法

if(iState < 0 || iState > 2 )

return ;//状态不合法

m_pMapData[iRow][iCol] = iState ;

}

void CMazeMap::Draw(CDC *pDC, CRect r)

{

CBrush brush[3] ;//建立三个刷子,对应三种不同的状态

brush[0].CreateSolidBrush(RGB(255,0,0));

brush[1].CreateSolidBrush(RGB(0,255,0));

brush[2].CreateSolidBrush(RGB(0,0,255));

CSize size(r.Width()/m_iColNum,r.Height()/m_iRowNum);

for( int i = 0 ; i < m_iRowNum ; i++ )

for( int j = 0 ; j < m_iColNum ; j++ )

{

CPoint pt(r.left + size.cx * j, r.top + size.cy * i);

CRect rCell(pt,size);

rCell.DeflateRect(1,1,1,1);//留点空隙

int iState = m_pMapData[i][j];

pDC->FillRect(&rCell,&brush[iState]);

}

}

void CMazeMap::CopyData(const CMazeMap &other)

{

//取得源数据、目的数据中行列较小者,以免溢出

int iMinRow = min(m_iRowNum,other.m_iRowNum);

int iMinCol = min(m_iColNum,other.m_iColNum);

//复制数据,以免数据丢掉

for(int i = 0 ; i < iMinRow ; i++ )

memcpy(m_pMapData[i],other.m_pMapData[i],sizeof(int)*iMinCol);

}

//r整个地图的范围,point鼠标点击的位置

CRect CMazeMap::ChangeMapState(CRect r, CPoint point)

{

//取得一个单格的大小

CSize size(r.Width()/m_iColNum,r.Height()/m_iRowNum);

int iRow = point.y/size.cy ;//取得行号

if( iRow >= m_iRowNum )

return CRect(0,0,0,0);//超出下边界

int iCol = point.x/size.cx ;//取得列号

if( iCol >= m_iColNum )

return CRect(0,0,0,0);//超出右边界

int iState = GetMapState(iRow,iCol);

if( 0 == iState )

iState = 1 ;

else if( 1 == iState || 2 == iState )

iState = 0 ;

SetMapState(iRow,iCol,iState);

//只刷新一部分,以免闪烁

CPoint pt(r.left + size.cx * iCol, r.top + size.cy * iRow);

CRect rCell(pt,size);

return rCell ;

}

bool CMazeMap::IslegalRowCol(int iRow, int iCol)

{

return (iRow >= 0 && iRow < m_iRowNum && iCol >= 0 && iCol < m_iColNum);

}

bool CMazeMap::SearchPath()

{

//清空路径标志

for(int i = 0 ; i < m_iRowNum ; i++ )

for(int j = 0 ; j < m_iColNum ; j++ )

{

if( 2 == GetMapState(i,j))

SetMapState(i,j,1);

}

//查找路径

CSearchPath find(*this);

if(!find.Search())

return false ;

//设置路径标志

for( i = 0 ; i < find.GetStepNum(); i++ )

{

int iRow,iCol ;

find.GetAStepRowCol(i,iRow,iCol);

SetMapState(iRow,iCol,2);

}

return true ;

}

CSearchPath::CSearchPath(CMazeMap& map):m_map(map)

{

m_iStep = 1 ;

memset(m_rowSet,0,1000*sizeof(int));

memset(m_colSet,0,1000*sizeof(int));

memset(m_iMoveType,0,1000*sizeof(int));

}

bool CSearchPath::Move(int iType)

{

m_iMoveType[m_iStep] = iType ;//无论是否移动成功都要记下来

//取得上一步的位置

int iRow = m_rowSet[m_iStep - 1] ;

int iCol = m_colSet[m_iStep - 1] ;

switch(iType)

{

case 1://右移

iCol++;

break;

case 2://下移

iRow++;

break;

case 3://左移

iCol--;

break;

case 4://上移

iRow--;

break;

default:

ASSERT(false);

return false;

break;

}

if(!m_map.IslegalRowCol(iRow,iCol))

return false ;//行列号不是合法

if(0 == m_map.GetMapState(iRow,iCol))

return false;//此格子不是可以通过

for(int i = 0 ; i < m_iStep ; i++ )

if( iCol == m_colSet[i] && iRow == m_rowSet[i])

return false ;//进入死循环

m_colSet[m_iStep] = iCol ;

m_rowSet[m_iStep] = iRow ;

return true ;

}

bool CSearchPath::Search()

{

while(true)

{

int iType = m_iMoveType[m_iStep] + 1 ;

if( iType > 4 )

if(!Back())

return false ;

else

continue;

if(!Move(iType))

continue ; //移动失败

if(m_map.GetRowNum()-1 == m_rowSet[m_iStep] && m_map.GetColNum()-1 == m_colSet[m_iStep])

return true ;//到达终点

m_iStep++;

}

return false ;

}

bool CSearchPath::Back()

{

if( 1 == m_iStep )

return false ;//退到起点,无路可退

m_iMoveType[m_iStep] = 0 ;

m_iStep-- ;

return true ;

}

int CSearchPath::GetStepNum()

{

return m_iStep+1 ;//起点第0步也算在内

}

bool CSearchPath::GetAStepRowCol(int iStepNO,int& iRow,int& iCol)

{

if( iStepNO < 0 || iStepNO > m_iStep )

return false ;

iRow = m_rowSet[iStepNO];

iCol = m_colSet[iStepNO];

return true ;

}

三,在视图类的头文件#include "MazeMap.h",并为视图类定议一个对象CMazeMap m_findMap;

四,在视图类的构造函数中设置行列。

CEx0605View::CEx0605View()

{

m_findMap.ChangeRowCol(10,9);

}

五,修改视图类的OnDraw函数。

void CEx0605View::OnDraw(CDC* pDC)

{

CRect r ;

GetClientRect(&r);

m_findMap.Draw(pDC,r);

}

六,在视图类,响应鼠标左键单击消息,具体内容如下:

void CEx0605View::OnLButtonDown(UINT nFlags, CPoint point)

{

CView::OnLButtonDown(nFlags, point);

CRect r ;

GetClientRect(&r);

m_findMap.ChangeMapState(r,point);

m_findMap.SearchPath();

Invalidate();//重新排序后,全刷新一下 // TODO: Add your message handler code here and/or call default

CView::OnLButtonDown(nFlags, point);

}

七,操作方法,单击鼠标左键,会改变每个小块的状态,红色表示无法通过,绿色表示可以通过,如果有路径连通左上角和右下角,此路径将以蓝色显示,单击红块会变成绿块,绿(蓝)块会变成红块。注:此路径不一定是最优路径。

注意:

直接复制需要重新排版.

点击查看效果  

查看分析

下载源代码 

一,新建一个单文档程序Ex0605。

二,增加两个类,最好放在单独的文件中,放在视图类也行,就是不规范。

以上是头文件的内容

class CMazeMap//迷宫地图类

{

public:

bool SearchPath();//查找路径

bool IslegalRowCol(int iRow,int iCol);//行列是否合法

CRect ChangeMapState(CRect r,CPoint pt);//根据范围和鼠标点击的坐标改变状态

void CopyData(const CMazeMap& other);//复制数据,不改变行列号

CMazeMap();

CMazeMap(const CMazeMap& other);

~CMazeMap();

void Draw(CDC* pDC,CRect r);//绘出迷宫地图的信息

void SetMapState(int iRow,int iCol,int iState);//设置某一块的状态

void ChangeRowCol(int iRow ,int iCol);//改变行列数,行列数变小时,会丢部分数据

int GetMapState(int iRow,int iCol){return m_pMapData[iRow][iCol];};

int GetRowNum(){return m_iRowNum;};

int GetColNum(){return m_iColNum;};

private:

void SetColNum(int iColNum);//设置列数,数据不变

void SetRowNum(int iRowNum);//设置行数,数据不变

void ReleaseData();//释放数据

int** CreateInitData();//new数据,并初始化

int** m_pMapData ;//数据内容,0表示不可到达,1表示可到达,2表示处于当前路径

int m_iRowNum ;//行号

int m_iColNum ;//列号

};

class CSearchPath//寻找第一条路径算法类

{

public:

bool GetAStepRowCol(int iStepNO,int& iRow,int& iCol);//取得某一步的行列

int GetStepNum();//取得总步数

CSearchPath(CMazeMap& map);

bool Search();//查找每第一条路径

private:

bool Back();//退回

bool Move(int iType);//移动(右移下移左移上移)

int m_iStep ;//当前步数,0表示起点

int m_rowSet[1000] ;//存放每步的行

int m_colSet[1000] ;//存放每步的列

int m_iMoveType[1000];//每步的移动方式

CMazeMap m_map ;//地图数据

};

以下是源文件的内容

CMazeMap::CMazeMap()

{

SetRowNum(3);

SetColNum(3);

m_pMapData = CreateInitData();

}

CMazeMap::CMazeMap(const CMazeMap& other)

{

m_iRowNum = other.m_iRowNum ;

m_iColNum = other.m_iColNum ;

m_pMapData = CreateInitData();

//复制数据,以免数据丢掉

for(int i = 0 ; i < m_iRowNum ; i++ )

memcpy(m_pMapData[i],other.m_pMapData[i],sizeof(int)*m_iColNum);

}

CMazeMap::~CMazeMap()

{

ReleaseData();

}

int** CMazeMap::CreateInitData()

{

int ** pMapData = new int*[m_iRowNum];

if( NULL == pMapData )

return NULL ;

for(int i = 0 ; i < m_iRowNum ; i++ )

{

pMapData[i] = new int[m_iColNum];

memset(pMapData[i],0,sizeof(int)*m_iColNum);//置0

}

return pMapData ;

}

void CMazeMap::ReleaseData()

{

if( NULL == m_pMapData )

return ;

for(int i = 0 ; i < m_iRowNum ; i++ )

delete[] m_pMapData[i] ;

delete[] m_pMapData ;

m_pMapData = NULL;

}

void CMazeMap::SetRowNum(int iRowNum)

{

if( iRowNum < 3 )

iRowNum = 3 ;//最少行数是3

if( iRowNum > 20 )

iRowNum = 20 ;//最大20

m_iRowNum = iRowNum ;

}

void CMazeMap::SetColNum(int iColNum)

{

if( iColNum < 3 )

iColNum = 3 ;//最少行数是3

if( iColNum > 20 )

iColNum = 20 ;//最大20

m_iColNum = iColNum ;

}

void CMazeMap::ChangeRowCol(int iRow, int iCol)

{

CMazeMap tmp(*this);//备份当前数据

ReleaseData();

if( 0 != iRow )

SetRowNum(iRow);

if( 0 != iCol )

SetColNum(iCol);

m_pMapData = CreateInitData();

CopyData(tmp);//复制数据

}

void CMazeMap::SetMapState(int iRow, int iCol,int iState)

{

if( iRow < 0 || iRow >= m_iRowNum || iCol < 0 || iCol >= m_iColNum )

return ;//行列号不合法

if(iState < 0 || iState > 2 )

return ;//状态不合法

m_pMapData[iRow][iCol] = iState ;

}

void CMazeMap::Draw(CDC *pDC, CRect r)

{

CBrush brush[3] ;//建立三个刷子,对应三种不同的状态

brush[0].CreateSolidBrush(RGB(255,0,0));

brush[1].CreateSolidBrush(RGB(0,255,0));

brush[2].CreateSolidBrush(RGB(0,0,255));

CSize size(r.Width()/m_iColNum,r.Height()/m_iRowNum);

for( int i = 0 ; i < m_iRowNum ; i++ )

for( int j = 0 ; j < m_iColNum ; j++ )

{

CPoint pt(r.left + size.cx * j, r.top + size.cy * i);

CRect rCell(pt,size);

rCell.DeflateRect(1,1,1,1);//留点空隙

int iState = m_pMapData[i][j];

pDC->FillRect(&rCell,&brush[iState]);

}

}

void CMazeMap::CopyData(const CMazeMap &other)

{

//取得源数据、目的数据中行列较小者,以免溢出

int iMinRow = min(m_iRowNum,other.m_iRowNum);

int iMinCol = min(m_iColNum,other.m_iColNum);

//复制数据,以免数据丢掉

for(int i = 0 ; i < iMinRow ; i++ )

memcpy(m_pMapData[i],other.m_pMapData[i],sizeof(int)*iMinCol);

}

//r整个地图的范围,point鼠标点击的位置

CRect CMazeMap::ChangeMapState(CRect r, CPoint point)

{

//取得一个单格的大小

CSize size(r.Width()/m_iColNum,r.Height()/m_iRowNum);

int iRow = point.y/size.cy ;//取得行号

if( iRow >= m_iRowNum )

return CRect(0,0,0,0);//超出下边界

int iCol = point.x/size.cx ;//取得列号

if( iCol >= m_iColNum )

return CRect(0,0,0,0);//超出右边界

int iState = GetMapState(iRow,iCol);

if( 0 == iState )

iState = 1 ;

else if( 1 == iState || 2 == iState )

iState = 0 ;

SetMapState(iRow,iCol,iState);

//只刷新一部分,以免闪烁

CPoint pt(r.left + size.cx * iCol, r.top + size.cy * iRow);

CRect rCell(pt,size);

return rCell ;

}

bool CMazeMap::IslegalRowCol(int iRow, int iCol)

{

return (iRow >= 0 && iRow < m_iRowNum && iCol >= 0 && iCol < m_iColNum);

}

bool CMazeMap::SearchPath()

{

//清空路径标志

for(int i = 0 ; i < m_iRowNum ; i++ )

for(int j = 0 ; j < m_iColNum ; j++ )

{

if( 2 == GetMapState(i,j))

SetMapState(i,j,1);

}

//查找路径

CSearchPath find(*this);

if(!find.Search())

return false ;

//设置路径标志

for( i = 0 ; i < find.GetStepNum(); i++ )

{

int iRow,iCol ;

find.GetAStepRowCol(i,iRow,iCol);

SetMapState(iRow,iCol,2);

}

return true ;

}

CSearchPath::CSearchPath(CMazeMap& map):m_map(map)

{

m_iStep = 1 ;

memset(m_rowSet,0,1000*sizeof(int));

memset(m_colSet,0,1000*sizeof(int));

memset(m_iMoveType,0,1000*sizeof(int));

}

bool CSearchPath::Move(int iType)

{

m_iMoveType[m_iStep] = iType ;//无论是否移动成功都要记下来

//取得上一步的位置

int iRow = m_rowSet[m_iStep - 1] ;

int iCol = m_colSet[m_iStep - 1] ;

switch(iType)

{

case 1://右移

iCol++;

break;

case 2://下移

iRow++;

break;

case 3://左移

iCol--;

break;

case 4://上移

iRow--;

break;

default:

ASSERT(false);

return false;

break;

}

if(!m_map.IslegalRowCol(iRow,iCol))

return false ;//行列号不是合法

if(0 == m_map.GetMapState(iRow,iCol))

return false;//此格子不是可以通过

for(int i = 0 ; i < m_iStep ; i++ )

if( iCol == m_colSet[i] && iRow == m_rowSet[i])

return false ;//进入死循环

m_colSet[m_iStep] = iCol ;

m_rowSet[m_iStep] = iRow ;

return true ;

}

bool CSearchPath::Search()

{

while(true)

{

int iType = m_iMoveType[m_iStep] + 1 ;

if( iType > 4 )

if(!Back())

return false ;

else

continue;

if(!Move(iType))

continue ; //移动失败

if(m_map.GetRowNum()-1 == m_rowSet[m_iStep] && m_map.GetColNum()-1 == m_colSet[m_iStep])

return true ;//到达终点

m_iStep++;

}

return false ;

}

bool CSearchPath::Back()

{

if( 1 == m_iStep )

return false ;//退到起点,无路可退

m_iMoveType[m_iStep] = 0 ;

m_iStep-- ;

return true ;

}

int CSearchPath::GetStepNum()

{

return m_iStep+1 ;//起点第0步也算在内

}

bool CSearchPath::GetAStepRowCol(int iStepNO,int& iRow,int& iCol)

{

if( iStepNO < 0 || iStepNO > m_iStep )

return false ;

iRow = m_rowSet[iStepNO];

iCol = m_colSet[iStepNO];

return true ;

}

三,在视图类的头文件#include "MazeMap.h",并为视图类定议一个对象CMazeMap m_findMap;

四,在视图类的构造函数中设置行列。

CEx0605View::CEx0605View()

{

m_findMap.ChangeRowCol(10,9);

}

五,修改视图类的OnDraw函数。

void CEx0605View::OnDraw(CDC* pDC)

{

CRect r ;

GetClientRect(&r);

m_findMap.Draw(pDC,r);

}

六,在视图类,响应鼠标左键单击消息,具体内容如下:

void CEx0605View::OnLButtonDown(UINT nFlags, CPoint point)

{

CView::OnLButtonDown(nFlags, point);

CRect r ;

GetClientRect(&r);

m_findMap.ChangeMapState(r,point);

m_findMap.SearchPath();

Invalidate();//重新排序后,全刷新一下 // TODO: Add your message handler code here and/or call default

CView::OnLButtonDown(nFlags, point);

}

七,操作方法,单击鼠标左键,会改变每个小块的状态,红色表示无法通过,绿色表示可以通过,如果有路径连通左上角和右下角,此路径将以蓝色显示,单击红块会变成绿块,绿(蓝)块会变成红块。注:此路径不一定是最优路径。

注意:

直接复制需要重新排版.

相关文章
下一篇:如何自动选择打印机,不弹出对话框让用户选择