# 迷宫求解的过程演示

//头文件

#ifndef Labyrinth_StructH
#define Labyrinth_StructH

#include <vcl.h>
#pragma hdrstop
typedef void __fastcall (__closure *TMyEvent)(int ID);

const int EVENT_PAINT=0;
const int EVENT_BACKDATE=1;
const int EVENT_OK=3;

const int STATE_ERROR=-1;
const int STATE_PASS=0;//可以通过
const int STATE_PASSED=1; //标记已经通过
const int STATE_CANNOTPASS=2;//不能通过
const int STATE_ENTRY=3; //入口点
const int STATE_END=4; //出口点

class SPoint
{
public:

__fastcall ~SPoint()
{

}
__fastcall SPoint()
{
PriorityDirection=1;
Count=-1;
}
__fastcall SPoint(TPoint tPoint)
{
PriorityDirection=1;
Count=-1;
X=tPoint.x;
Y=tPoint.y;
}
__fastcall SPoint(int tX,int tY)
{
PriorityDirection=1;
Count=-1;
X=tX;
Y=tY;
}
int operator==(const SPoint& Source)
{
return(Source.X==X&&Source.Y==Y);
}
int operator!=(const SPoint& Source)
{
return(Source.X!=X||Source.Y!=Y);
}

int X;
int Y;
int Count;
int PriorityDirection;//一个优先方向另加四个方向
};

template<class T>class CShed //栈
{
public:
TList *List;
__fastcall CShed();
__fastcall ~CShed();
T *Pop();
void Push(T *point);

};

class CLabyrinth
{
TCanvas *LabyrinthCanvas;
int ImageHeight;
int ImageWidth;

int LabyrinthHeight;
int LabyrinthWidth;

int LabyrinthCol;
int LabyrinthRow;

int UnitHeight;
int UnitWidth;

int LeftSpace;
int TopSpace;

int *LabyrinthData;

Graphics::TBitmap *Bitmap_STATE_PASS;
Graphics::TBitmap *Bitmap_STATE_PASSED;
Graphics::TBitmap *Bitmap_STATE_CANNOTPASS;
Graphics::TBitmap *Bitmap_STATE_ENTRY;
Graphics::TBitmap *Bitmap_STATE_END;
void SetMemory();
void SetRowCol(int tRow,int tCol);
bool GetNewPoint(int Direction,int &tRow,int &tCol,int &tState);
void SetState(int tRow,int tCol,int tState);
public:
__fastcall CLabyrinth(AnsiString FileName);
__fastcall CLabyrinth(int tWidth,int tHeight,TCanvas *tCanvas=NULL);
__fastcall ~CLabyrinth();
void __fastcall Assin(const CLabyrinth& Source)
{
LabyrinthCol=Source.LabyrinthCol;
LabyrinthRow=Source.LabyrinthRow;
LabyrinthData=new int[LabyrinthRow*LabyrinthCol];
for(int k=0;k<LabyrinthRow*LabyrinthCol;k++)
LabyrinthData[k]=Source.LabyrinthData[k];
}

public:
void ChangRowCol(int tRow,int tCol);
void GetRowCol(int &tRow,int &tCol);
void Updata();

void SetSize(int tWidth,int tHeight);
void GetSize(int &tWidth,int &tHeight);
void GetSpace(int &tLeftSpace,int &tTopSpace);
void SetCanvas(TCanvas *tCanvas);
void Refresh();//整个画板进行刷新
void Refresh(TRect rect,int tState=-1);
void Refresh(TPoint point,int tState=-1);
void Refresh(int tRow,int tCol,int tState=-1);
void SaveToFile(AnsiString tFileName="");
int ConvertRC(int tRow,int tCol);
int GetState(int tRow,int tCol);
int GetState(TPoint tPoint);
void ChangeState(int OldState,int NewState,int Times=-1);
void FindResult(TPoint *StartPoint=NULL);
public:
bool PowerExit;
bool IsChange;
AnsiString FileName;

TMyEvent FMyEvent;

};

#endif

////////////////////////////////////////////////////////////////////////////////////////////////////////////

//下面是实现部分

#include <stdio.h>
#pragma hdrstop
#include "Labyrinth_Struct.h"

__fastcall CLabyrinth::CLabyrinth(AnsiString FileName)
{
}
void CLabyrinth::Updata()
{
UnitHeight=ImageHeight/LabyrinthRow;
UnitWidth=ImageWidth/LabyrinthCol;

LabyrinthHeight=UnitHeight*LabyrinthRow;
LabyrinthWidth=UnitWidth*LabyrinthCol;

LeftSpace=(ImageWidth-LabyrinthWidth)/2;
TopSpace=(ImageHeight-LabyrinthHeight)/2;

}

__fastcall CLabyrinth::CLabyrinth(int tWidth,int tHeight,TCanvas *tCanvas)
{
LabyrinthData=NULL;
PowerExit=false;
Bitmap_STATE_PASS=new Graphics::TBitmap();
Bitmap_STATE_PASSED=new Graphics::TBitmap();
Bitmap_STATE_CANNOTPASS=new Graphics::TBitmap();
Bitmap_STATE_ENTRY=new Graphics::TBitmap();
Bitmap_STATE_END=new Graphics::TBitmap();
IsChange=false;
LabyrinthData=NULL;
LabyrinthCol=40;
LabyrinthRow=40;
LabyrinthCanvas=tCanvas;
ImageHeight=tHeight;
ImageWidth=tWidth;
SetRowCol(LabyrinthRow,LabyrinthCol);
}
__fastcall CLabyrinth::~CLabyrinth()
{
delete Bitmap_STATE_PASS;
delete Bitmap_STATE_PASSED;
delete Bitmap_STATE_CANNOTPASS;
delete Bitmap_STATE_ENTRY;
delete Bitmap_STATE_END;

if(LabyrinthData)
{
delete []LabyrinthData;
LabyrinthData=NULL;
}
}

void CLabyrinth::SetMemory()
{
if(LabyrinthData)
{
delete []LabyrinthData;
LabyrinthData=NULL;
}

LabyrinthData=new int[LabyrinthRow*LabyrinthCol];
for(int k=1;k<LabyrinthRow*LabyrinthCol;k++)
LabyrinthData[k]=STATE_PASS;
LabyrinthData[0]=STATE_ENTRY;
LabyrinthData[LabyrinthRow*LabyrinthCol-1]=STATE_END;
}
void CLabyrinth::SetRowCol(int tRow,int tCol)
{
LabyrinthCol=tCol;
LabyrinthRow=tRow;
Updata();
SetMemory();
}
void CLabyrinth::SetCanvas(TCanvas *tCanvas)
{
LabyrinthCanvas=tCanvas;
}
void CLabyrinth::Refresh()
{
if(LabyrinthCanvas!=NULL)
{
LabyrinthCanvas->Brush->Color=clBlack;
LabyrinthCanvas->FillRect(Rect(0,0,ImageWidth,ImageHeight));
}
for(int k=0;k<LabyrinthRow;k++)
for(int l=0;l<LabyrinthCol;l++)
Refresh(k+1,l+1);
}
void CLabyrinth::Refresh(TRect rect,int tState)
{
int tLeft,tTop,tRight,tBottom;
tLeft=rect.Left-LeftSpace;
tTop=rect.Top-TopSpace;
tBottom=rect.Bottom-TopSpace;
tRight=rect.Right-LeftSpace;

int tLeftCol=tLeft/UnitWidth+1;
int tLeftRow=tTop/UnitHeight+1;
int tRightCol=tRight/UnitWidth;
int tRightRow=tBottom/UnitHeight;
tRightCol+=tRight%UnitWidth>0?1:0;
tRightRow+=tBottom%UnitHeight>0?1:0;
for(int k=tLeftRow;k<=tRightRow;k++)
for(int l=tLeftCol;l<=tRightCol;l++)
Refresh(k,l,tState);

}
void CLabyrinth::Refresh(TPoint point,int tState)
{
int tCol=(point.x-LeftSpace)/UnitWidth;
int tRow=(point.y-TopSpace)/UnitHeight;
tCol+=point.x%UnitWidth>0?1:0;
tRow+=point.y%UnitHeight>0?1:0;
Refresh(tRow,tCol,tState);

}
void CLabyrinth::Refresh(int tRow,int tCol,int tState)
{
if(LabyrinthCanvas==NULL)
return;
if(tRow<0||tCol<0||tRow>LabyrinthRow||tCol>LabyrinthCol)
return;
int OldState=LabyrinthData[ConvertRC(tRow,tCol)];
if(tState!=-1)
{
if(OldState==STATE_ENTRY||OldState==STATE_END)
return;
LabyrinthData[ConvertRC(tRow,tCol)]=tState;
IsChange=true;
}
else
tState=OldState;

switch(tState)
{
case STATE_PASS: LabyrinthCanvas->StretchDraw(Rect(UnitWidth*(tCol-1)+LeftSpace,UnitHeight*(tRow-1)+TopSpace,UnitWidth*tCol+LeftSpace,UnitHeight*tRow+TopSpace),Bitmap_STATE_PASS);break;
case STATE_PASSED:LabyrinthCanvas->StretchDraw(Rect(UnitWidth*(tCol-1)+LeftSpace,UnitHeight*(tRow-1)+TopSpace,UnitWidth*tCol+LeftSpace,UnitHeight*tRow+TopSpace),Bitmap_STATE_PASSED); break;
case STATE_CANNOTPASS:LabyrinthCanvas->StretchDraw(Rect(UnitWidth*(tCol-1)+LeftSpace,UnitHeight*(tRow-1)+TopSpace,UnitWidth*tCol+LeftSpace,UnitHeight*tRow+TopSpace),Bitmap_STATE_CANNOTPASS); break;
case STATE_ENTRY:LabyrinthCanvas->StretchDraw(Rect(UnitWidth*(tCol-1)+LeftSpace,UnitHeight*(tRow-1)+TopSpace,UnitWidth*tCol+LeftSpace,UnitHeight*tRow+TopSpace),Bitmap_STATE_ENTRY); break;
case STATE_END:LabyrinthCanvas->StretchDraw(Rect(UnitWidth*(tCol-1)+LeftSpace,UnitHeight*(tRow-1)+TopSpace,UnitWidth*tCol+LeftSpace,UnitHeight*tRow+TopSpace),Bitmap_STATE_END); break;
default: break;
}

}
int CLabyrinth::ConvertRC(int tRow,int tCol)
{
return((tRow-1)*LabyrinthCol+tCol-1);

}

void CLabyrinth::SetSize(int tWidth,int tHeight)
{
LabyrinthHeight=tHeight;
LabyrinthWidth=tWidth;
UnitHeight=LabyrinthHeight/LabyrinthRow;
UnitWidth=LabyrinthWidth/LabyrinthCol;
LabyrinthHeight=UnitHeight*LabyrinthRow;
LabyrinthWidth=UnitWidth*LabyrinthCol;
Refresh();

}
void CLabyrinth::GetSpace(int &tLeftSpace,int &tTopSpace)
{
tLeftSpace=LeftSpace;
tTopSpace=TopSpace;

}

void CLabyrinth::GetSize(int &tWidth,int &tHeight)
{
tHeight=LabyrinthHeight;
tWidth=LabyrinthWidth;

}
int CLabyrinth::GetState(int tRow,int tCol)
{
if(tRow>0&&tCol>00&&tRow<=LabyrinthRow&&tCol<=LabyrinthCol)
return(LabyrinthData[ConvertRC(tRow,tCol)]);
return STATE_ERROR;
}

int CLabyrinth::GetState(TPoint tPoint)
{
int tCol=tPoint.x/UnitWidth;
int tRow=tPoint.y/UnitHeight;
tCol+=tPoint.x%UnitWidth>0?1:0;
tRow+=tPoint.y%UnitHeight>0?1:0;
if(tRow>0&&tCol>0&&tRow<=LabyrinthRow&&tCol<=LabyrinthCol)
return(LabyrinthData[ConvertRC(tRow,tCol)]);
return STATE_ERROR;

}
void CLabyrinth::SaveToFile(AnsiString tFileName)
{
if(tFileName.IsEmpty())
tFileName=FileName;
if(tFileName.IsEmpty())
return;
FILE *in;
try
{
try
{
if ((in = fopen(tFileName.c_str(), "w+"))== NULL)
{
ShowMessage("不能打开文件！！！");
throw(0);
}
char SMark[5]="Labyr";
int tEdition=100;
fprintf(in, " %s ", SMark);
fprintf(in, " %d ", tEdition);
fprintf(in, " %d %d ", LabyrinthRow,LabyrinthCol);
for(int k=0;k<LabyrinthRow*LabyrinthCol;k++)
fprintf(in, " %d ", LabyrinthData[k]);
FileName=tFileName;
IsChange=false;
}
__finally
{
fclose(in);
}
}
catch(...)
{
return;
}
}
void CLabyrinth::GetRowCol(int &tRow,int &tCol)
{
tRow=LabyrinthRow;
tCol=LabyrinthCol;
}
void CLabyrinth::ChangRowCol(int tRow,int tCol)
{
if(tRow>60||tRow<10||tCol>60||tRow<10)
{
ShowMessage("列和行超出边界(60>x>10)");
return;
}
LabyrinthData=NULL;
LabyrinthCol=tCol;
LabyrinthRow=tRow;
SetRowCol(LabyrinthRow,LabyrinthCol);
IsChange=true;
Refresh();
}
void CLabyrinth::SetState(int tRow,int tCol,int tState)
{
if(tRow>0&&tCol>0&&tRow<=LabyrinthRow&&tCol<=LabyrinthCol)
{
if(GetState(tRow,tCol)!=STATE_ENTRY&&GetState(tRow,tCol)!=STATE_END)
LabyrinthData[ConvertRC(tRow,tCol)]=tState;
}
}

void CLabyrinth::ChangeState(int OldState,int NewState,int Times)
{
int tCount=0;
for(int k=0;k<LabyrinthRow*LabyrinthCol;k++)
{
if(LabyrinthData[k]==OldState)
{
IsChange=true;
LabyrinthData[k]=NewState;
tCount++;
int tCol,tRow;
tRow=k/LabyrinthCol;
tCol=k%LabyrinthCol;
Refresh(tRow+1,tCol+1);
if(tCount==Times)
return ;
}
}

}

{
FILE *in;
try
{
try
{
if ((in = fopen(tFileName.c_str(), "r"))== NULL)
{
ShowMessage("不能打开文件！！！");
throw(0);
}
rewind(in);
char  Mark[5];
AnsiString SMark="Labyr";
fscanf(in, " %s ", Mark);
AnsiString tempStr=Mark;
tempStr=tempStr.SubString(1,5);
if(tempStr!=SMark)
{
ShowMessage("该文件不是迷宫数据文件");
throw(0);
}
int tRow,tCol;
int tEdition;
fscanf(in, " %d ", &tEdition);
fscanf(in, " %d %d ", &tRow,&tCol);
LabyrinthCol=tCol;
LabyrinthRow=tRow;

SetMemory();
int tState;
for(int k=0;k<LabyrinthRow*LabyrinthCol;k++)
{
if(feof(in))
{
ShowMessage("文件被破坏！！！");
throw(0);
}
fscanf(in, " %d ", &tState);
LabyrinthData[k]=tState;
}
FileName=tFileName;
IsChange=false;

}
__finally
{
fclose(in);
}
}
catch(...)
{
return false;
}
}

bool CLabyrinth::GetNewPoint(int Direction,int &tRow,int &tCol,int &tState)
{
int OldCol=tCol;
int OldRow=tRow;
switch(Direction)
{
case 1: tCol=tCol;tRow=tRow-1;break;
case 2: tCol=tCol+1;tRow=tRow;break;
case 3: tCol=tCol;tRow=tRow+1;break;
case 4: tCol=tCol-1;tRow=tRow;break;
default :return false;
}
tState=GetState(tRow+1,tCol+1);
return true;
return false;
}
void CLabyrinth::FindResult(TPoint *tStartPoint)
{
SPoint *StartSPoint;
SPoint *CurrentSPoint;
SPoint *StopSPoint;//=new SPoint();
TPoint StartPoint;
TPoint StopPoint;
int tCount=0;
for(int l=0;l<LabyrinthRow;l++)
for(int k=0;k<LabyrinthCol;k++)
{
if(LabyrinthData[l*LabyrinthCol+k]==STATE_ENTRY)
{
StartPoint.x=k;
StartPoint.y=l;
tCount++;
break;
}
if(LabyrinthData[l*LabyrinthCol+k]==STATE_END)
{
StopPoint.x=k;
StopPoint.y=l;  tCount++;
break;

}
if(tCount==2)
break;
}

if(tStartPoint!=NULL)
CurrentSPoint=new SPoint(*tStartPoint);
else
CurrentSPoint=new SPoint(StartPoint);
StopSPoint=new SPoint(StopPoint);
StartSPoint=CurrentSPoint;
if(CurrentSPoint->X>StopSPoint->X)
CurrentSPoint->PriorityDirection=4;
else
CurrentSPoint->PriorityDirection=2;

CShed<SPoint>tShed;

int NowState;
int CX,CY;
while(1)
{
if(PowerExit)
break;
do{
if(PowerExit)
break;
CurrentSPoint->Count++;
bool tNeedPush;
CX=CurrentSPoint->X;
CY=CurrentSPoint->Y;
switch(CurrentSPoint->Count)
{
case 0: tNeedPush=GetNewPoint(CurrentSPoint->PriorityDirection,CY,CX,NowState); break;
case 1:
case 2:
case 3:
case 4: tNeedPush=GetNewPoint(CurrentSPoint->Count,CY,CX,NowState);break;
default: tNeedPush=false;
SetState(CurrentSPoint->Y+1,CurrentSPoint->X+1,STATE_PASS);
Refresh(CurrentSPoint->Y+1,CurrentSPoint->X+1);
CurrentSPoint=tShed.Pop();
if(FMyEvent)
FMyEvent(EVENT_BACKDATE);
break;
}
if(tNeedPush)
{
int OldPriorityDirection=CurrentSPoint->PriorityDirection;
int OldCount=CurrentSPoint->Count;
SetState(CurrentSPoint->Y+1,CurrentSPoint->X+1,STATE_PASSED);
Refresh(CurrentSPoint->Y+1,CurrentSPoint->X+1);
tShed.Push(CurrentSPoint);
if(FMyEvent)
FMyEvent(EVENT_PAINT);
CurrentSPoint=new SPoint(CX,CY);
if(OldCount==0)
CurrentSPoint->PriorityDirection=OldPriorityDirection;
else
CurrentSPoint->PriorityDirection=OldCount;
if(NowState==STATE_END)
{
MessageDlg("恭喜你!!!", mtInformation, TMsgDlgButtons()<<mbOK, 0);
ChangeState(STATE_PASSED,STATE_PASS);
Refresh();
if(FMyEvent)
FMyEvent(EVENT_OK);
return;
}
break;
}
}while(CurrentSPoint);
if(CurrentSPoint==NULL)//没有解
{
MessageDlg("本迷宫没有通路。", mtWarning, TMsgDlgButtons()<<mbOK, 0);
if(FMyEvent)
FMyEvent(EVENT_OK);
return;
}
}

PowerExit=false;
}

//下面是栈的成员函数
template<class T>
__fastcall CShed<T>::CShed()
{
List=new TList();
}
template<class T> __fastcall CShed<T>::~CShed()
{
while(List->Count)
{
T *temp=(T *)List->Items[0];
delete temp;
List->Delete(0);
}
}
template<class T> T *CShed<T>::Pop()
{
if(!List->Count)
return NULL;

T *temp=(SPoint *)List->Items[List->Count-1];
List->Delete(List->Count-1);
return temp;

}
template<class T> void  CShed<T>::Push(T *point)
{