코드는 일단 이렇습니다.
#include "stdafx.h"
#define TileSize 2
#define NOFIND NULL
// 커서를 콘솔 x,y 좌표로 이동.
void gotoxy(int x, int y)
{
COORD pos = { x, y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
//
// Tile Class
//
class CTile
{
private:
bool m_bMarked; // 검색 여부 체크
bool m_bBlock; // 이동 불가 타일 체크
int G; // 시작-현재타일 사이 비용
int X; // 타일의 좌표
int Y;
int m_nLastX; // 검색된 이전 칸 인덱스
int m_nLastY;
public:
bool check;
CTile() :m_bBlock(0), m_bMarked(0), check(0), m_nLastX(NULL), m_nLastY(NULL), G(0){}
~CTile(){};
void SetG(int m_G) { G = m_G; }
void SetFrontTile(int px, int py) { m_nLastX = px; m_nLastY = py; }
void SetMarked(bool pM) { m_bMarked = pM; }
void SetBlock(bool pB) { m_bBlock = pB; }
void SetPos(int px, int py) { X = px; Y = py; }
bool GetMarked() { return m_bMarked; }
bool GetBlock() { return m_bBlock; }
int GetG() { return G; }
int GetFX() { return m_nLastX; }
int GetFY() { return m_nLastY; }
int GetX() { return X; }
int GetY() { return Y; }
};
// 길 찾은 후 저장할 STL
list<CTile*> g_Loop;
// 길찾기 g 값 비교 할 find 참조 구조체
struct sort_list_f_g
{
bool operator() (CTile* n1, CTile* n2) const
{
return n1->GetG() < n2->GetG();
}
};
//
// Tile Map Class
//
class CTilemap
{
private:
int m_nWidth, m_nHeight; // 맵 가로, 세로 사이즈
CTile* m_pMapdata; // 맵 배열
list<CTile*> Open_list; // 오픈리스트
public:
CTilemap() :m_nHeight(NULL), m_nWidth(NULL), m_pMapdata(NULL) {}
CTilemap(int pW, int pH) :m_nHeight(pH), m_nWidth(pW){ m_pMapdata = new CTile[m_nWidth*m_nHeight + m_nWidth]; }
~CTilemap() { if (m_pMapdata) delete[] m_pMapdata; m_pMapdata = NULL; }
// 텍스트 타일맵 파일 읽고 맵 배열에 저장
bool SetMapdata(const TCHAR* filename)
{
FILE* pf;
_tfopen_s(&pf, filename, _T("rt"));
TCHAR BlockIndex[128];
int x, y;
for (y = 0; y<m_nHeight; y++)
{
if (!(_fgetts(BlockIndex, 128, pf)))
{
fclose(pf);
return false;
}
for (x = 0; x<m_nWidth; x++)
{
(m_pMapdata + (y*m_nWidth + x))->SetBlock((BlockIndex[x] == '0' ? true : false));
(m_pMapdata + (y*m_nWidth + x))->SetPos(x, y);
}
}
fclose(pf);
return true;
}
// 콘솔에 타일 맵 데이터 그리기
void DrawMap()
{
int x, y;
for (y = 0; y<m_nHeight; y++)
{
for (x = 0; x<m_nWidth; x++)
{
// 이동 가능 타일 ▨, 이동 불가능 타일 ■
gotoxy(x * 2, y);
cout << ((m_pMapdata + (y*m_nWidth + x))->GetBlock() ? "▨" : "■");
}
}
}
// A* 길찾기 경로가 있으면 목표지점 리턴하고 없으면 Null 리턴
CTile* findpath(int& StartingX, int& StartingY, int& GoalX, int& GoalY)
{
list<CTile*>::iterator itor = Open_list.begin();
list<CTile*>::iterator End = Open_list.end();
int x = StartingX;
int y = StartingY;
int inX;
int inY;
bool Cell_is = true; // 검사해야될 타일인지 여부 체크 변수
int TempG; // 중간 비용 변수
CTile* Goal = (m_pMapdata + GoalY * m_nWidth + GoalX);
CTile* Son = NULL;
Open_list.push_back((m_pMapdata + StartingY * m_nWidth + StartingX));
itor = Open_list.begin();
(*itor)->SetFrontTile(x, y);
// 목적지와 시작점이 같거나 목적지가 이동불가 지역일 경우 실패 리턴
if (*itor == Goal || Goal->GetBlock() == false)
return NOFIND;
// 오픈리스트가 있을경우 길찾기 시작! or 계속
while (!(Open_list.empty()))
{
// 첫번째 타일 꺼내기
itor = Open_list.begin();
while ((*itor)->check == true)
{
if (itor == End)
return NOFIND;
itor++;
}
(*itor)->check = true;
x = (*itor)->GetX();
y = (*itor)->GetY();
// 현재 타일을 기준으로 상하좌우 타일에 대하여 검사
for (inY = y - 1; inY <= y + 1; inY++)
{
for (inX = x - 1; inX <= x + 1; inX++)
{
// 부모 타일인 경우 건너뜀;
if (inX == x
&& inY == y)
continue;
// 검사 타일이 배열 밖이면 건너뜀;
if (!(inY*m_nWidth + inX >= 0
&& inY*m_nWidth + inX < m_nWidth*m_nHeight + m_nWidth))
continue;
// 상하좌우 검색 시에 대각선 타일이 이동불가 타일이면 건너뜀;
if (abs(x - inX) + abs(y - inY) == 2)
{
// 이동불가 타일인 경우에 대한 조건 완성
if( )
continue;
//
}
// 경계에 있을시 다음 or 이전 줄로 이동하는 것 방지
if (inX == x - 1)
Cell_is = x != 0;
else if (inX == x + 1)
Cell_is = x != m_nWidth - 1;
//
// 중간 비용 계산을 위하여 대각선인 경우 14, 수평,수직인 경우 10
TempG =
//
// 오픈리스트에 저장할 자식타일이 있을 경우
if (Cell_is)
{
Son = (m_pMapdata + (inY*m_nWidth + inX));
// 자식타일이 이동불가 타일과 검색한 적이 없다면
if (Son->GetBlock())
{
if (Son->GetMarked() == false)
{
// 오픈 리스트에 저장할 정보
Son->SetFrontTile(x, y);
Son->SetG(TempG);
Son->SetMarked(true);
Son->SetPos(inX, inY);
//
// 오픈리스트에 자식타일 추가하기
//
// 목표지점일 경우 리턴
if (Son == Goal)
return Son;
}
else
{
// 검색한 적이 있는 타일의 경우
if (Son->GetG() > (*itor)->GetG() + TempG)
{
//
// 비용 검사하여 더 작은 비용으로 업데이트
//
// 부모타일로 업데이트
Son->SetFrontTile(x, y);
}
}
}
}
}
}
// 비용 g가 제일 작은 순으로 정렬.
Open_list.sort(sort_list_f_g());
}
// 길을 찾지 못했을 경우 NULL 리턴
return NOFIND;
}
// 길찾기 함수 실행후 리턴받은 값으로 STL 리스트 작성.
bool FindLoop(int& StartingX, int& StartingY, int& GoalX, int& GoalY)
{
CTile* Temp = findpath(StartingX, StartingY, GoalX, GoalY);
if (Temp != NOFIND)
{
while (Temp != (m_pMapdata + StartingY*m_nWidth + StartingX))
{
g_Loop.push_front(Temp);
Temp = (m_pMapdata + Temp->GetFY()*m_nWidth + Temp->GetFX());
}
return true;
}
return false;
}
};
void main()
{
list<CTile*>::iterator itor = g_Loop.begin();
list<CTile*>::iterator End = g_Loop.end();
char key;
bool loop = true;
// 타일맵 그리기
CTilemap* p_Map = new CTilemap(16, 16);
if (!(p_Map->SetMapdata("MapAstar.txt")))
return;
p_Map->DrawMap();
// 시작점, 끝점
int StartX, StartY, GoalX, GoalY;
StartX = 4; StartY = 7;
GoalX = 12; GoalY = 8;
gotoxy(StartX * 2, StartY);
cout << "S";
gotoxy(GoalX * 2, GoalY);
cout << "E";
gotoxy(2, 17);
cout << "Press AnyKey for 1 Step";
gotoxy(5, 18);
cout << "or SpaceBar for All Step";
// 루프 찾기
p_Map->FindLoop(StartX, StartY, GoalX, GoalY);
itor = g_Loop.begin();
// 찾은 루프를 시작점부터 끝점까지 그리기
while (itor != End)
{
if (loop)
key = getch();
if (key == ' ')
loop = false;
// 찾은 길 "○"표시
gotoxy((*itor)->GetX() * 2, (*itor)->GetY());
cout << "○";
itor++;
}
// 길찾기 후 콘솔의 커서위치 재설정
gotoxy(0, 20);
delete p_Map;
}
상당히 긴 편인데요.
궁금한 부분은 이렇습니다.
// 이동불가 타일인 경우에 대한 조건 완성
// 중간 비용 계산을 위하여 대각선인 경우 14, 수평,수직인 경우 10
// 오픈리스트에 자식타일 추가하기
// 비용 검사하여 더 작은 비용으로 업데이트
염치 불구하고 질문드립니다. 감사합니다 도와주세요~~
아직 댓글이 없습니다. 첫번째 댓글 작성자가 되어주세요 :)