스택을 이용한 미로찾기 (Maze Problem ver. Stack)

Sample

maze.txt (maze map)

txt
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 0 0 1 1 1 0 0 0 1 1 1
1 0 0 0 0 1 1 0 0 0 1 0 0 0 1
1 1 0 1 0 1 0 0 1 1 1 0 1 0 1
1 1 1 1 0 0 0 1 1 0 0 0 1 0 1
1 0 1 1 1 1 1 0 0 0 1 1 1 0 1
1 0 0 0 1 0 1 0 1 0 1 1 1 0 1
1 0 1 1 1 1 1 0 1 1 1 1 1 0 1
1 0 1 0 0 0 0 0 0 1 1 1 1 1 1
1 0 1 0 1 1 1 1 1 1 0 0 0 1 1
1 0 0 0 1 0 0 0 1 1 0 1 0 1 1
1 1 0 1 1 0 1 0 1 0 0 1 0 1 1
1 1 0 1 1 0 1 0 0 0 1 1 0 0 1
1 0 0 0 0 0 0 1 1 0 0 1 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Source Code

Main.cpp

cpp
#include "Maze.h"
#include <iostream>

int main(void)
{

 try
 {
  Maze* test;
  test = new Maze("maze.txt"); // txt file open
  int t = test->Find(1,1,13,13); // 길찾기. 
  // Find함수는 올바른 경로를 스택에 저장한다.
  // 올바른 경로가 존재하면 1을 반환하고 나머지 경우는 0을 반환한다.

  if (t==0)
   throw "No escape route.";

  test->Sol();// 스택에 저장된 경로를 보여준다(출력부분)
 }
 catch(char* e)
 {
  std::cout << e << "\n";
 }

 
}

Stack.h

cpp
#ifndef STACK_H
#define STACK_H

#include "Location.h"

class Stack
{

private:

 Location* stack;
 int top;
 int capacity;

public:

 Stack(int stackCapacity = 10);
 bool IsEmpty();
 Location Top();
 void Push(Location item);
 Location Pop();

};

#endif

Stack.cpp

cpp
#include "Stack.h"
#include "Location.h"

Stack::Stack(int stackCapacity)
{
 capacity = stackCapacity;
 if(capacity < 1)
  throw "Stack capacity must be > 0";
 stack = new Location[capacity];
 top = -1;
}

bool Stack::IsEmpty()
{
 return top == -1;
}

Location Stack::Top()
{
 if(IsEmpty())
  throw "Stack is empty"; 
 return stack[top];
}

void Stack::Push(Location x)
{
 if(top < capacity-1)
 {
  stack[++top] = x;
 } else {
  throw "Stack is full";
 }
}

Location Stack::Pop()
{
 if(IsEmpty())
  throw "Stack is empty";
 return stack[top--];

}

Location.h

cpp
#ifndef LOCATION_H
#define LOCATION_H

class Location
{
private:
 int x;
 int y;
public:

 //클래스 동적배열을 사용하기 위해 기본 생성자를 사용한다.
 //Location();
 //Location(int xx, int yy);

 void Replace(int xx, int yy); // 객체에 x,y좌표를 재대입한다

 void Up(); // y->y-1
 void Down();// y->y+1
 void Left();// x->x-1
 void Right();// x->x+1

 int X();// 객체의 x를 출력
 int Y();// 객체의 y를 출력
 
 void Print(); // (x,y) 형식으로 출력
};

#endif

Location.cpp

cpp
#include <iostream>
#include "Location.h"


void Location::Replace(int xx, int yy) { x=xx; y=yy; }
void Location::Up() { y--; }
void Location::Down() { y++; }
void Location::Left() { x--; }
void Location::Right() { x++; }
int Location::X() { return x; }
int Location::Y() { return y; }
void Location::Print() { std::cout << "(" << x << ", " << y << ")\n"; }

Maze.h

cpp
#ifndef MAZE_H
#define MAZE_H

#include "Stack.h"
#include "Location.h"

class Maze
{
private:
 
 int Map[15][15]; // 미로 정보를 저장할 이차원 배열
 Stack* Path; // 스택
 Location* P; // 임의의 좌표

public:

 Maze(char* str); // 생성자
 int IsBlock(Location* p); // p가 벽인지 길인지 확인하는 함수

 int Find(int x1,int y1,int x2,int y2); // 통합 길찾기 함수

 void Sol(); // 정답 출력

};

#endif

Maze.cpp

cpp
#include <iostream>
#include <fstream>
#include "Maze.h"

using  std::ifstream;

Maze::Maze(char* str)
{

 // 파일을 읽어서 배열에 저장한다
 ifstream in_file;
 in_file.open(str);
 int i,j;
 for(i=0;i<15;i++)
 {
//  in_file.getline(temp,30);
  for(j=0;j<15;j++)
  {
//   t=temp[j];
//   Map[i][j]=atoi(&t);
   in_file>>Map[i][j]; // 자동 형변환.. "1 "또는 "0 " 을 1,0 으로 변환
  }
 } 
 in_file.close();
 // 끝

 Path = new Stack(1000);

}
int Maze::IsBlock(Location* p)
{
 return Map[p->Y()][p->X()]; // 벽이면 1, 길이면 0을 반환
}
int Maze::Find(int x1,int y1,int x2,int y2)
{



 int result;
 Location T;
 P = new Location();
 P->Replace(x1,y1);
 
 if(Path->IsEmpty()) T.Replace(-2,-2);  // 처음 실행했을때(스택이 비어있을때) 허위값을 넣는다
 else T = Path->Top(); // T에 가장 최근 지나온 길의 좌표를 넣는다

 Path->Push(*P); // 스택에 현재 좌표를 대입한다

 if((x1==x2)&&(y1==y2)) return 1; // 시작점과 도착점이 같으면 1을 반환 (경로찾기 성공)


 // 현재 좌표에서 4방향을 모두 검사한다
 // 북쪽
 P->Up(); // 임시로 점을 북쪽으로 한칸 옮긴다
 if((P->X()!=T.X())||(P->Y()!=T.Y())) // 스택에 저장된 최근 경로값과 현재 좌표가 같지 않다면 
 {          // 같게 된다면 이 방향으로는 경로가 존재하지 않으므로 skip한다
  if(!IsBlock(P)) // 벽이 아니면
  {
   result = Find(P->X(),P->Y(),x2,y2); // 이 지점부터 다시 경로를 찾는다 ex) (3,2)->(13,13) => (3,2)->(3,1)->(13,13)
   if(result == 0) // 경로가 없으면
    Path->Pop(); // 지나간 경로를 지운다
   else
    return result; // 경로가 존재한다면 1을 반환하고 종료
  }
 }
 P->Down(); // 점을 다시 제자리로

 // 남쪽 (알고리즘은 위와 동일)
 P->Down();
 if((P->X()!=T.X())||(P->Y()!=T.Y()))
 {
  if(!IsBlock(P))
  {
   result = Find(P->X(),P->Y(),x2,y2);
   if(result == 0)
    Path->Pop();
   else
    return result;
  }
 }
 P->Up();

 // 서쪽
 P->Left();
 if((P->X()!=T.X())||(P->Y()!=T.Y()))
 {
  if(!IsBlock(P))
  {
   result = Find(P->X(),P->Y(),x2,y2);
   if(result == 0)
    Path->Pop();
   else
    return result;
  }
 }
 P->Right();

 // 동쪽
 P->Right();
 if((P->X()!=T.X())||(P->Y()!=T.Y()))
 {
  if(!IsBlock(P))
  {
   result = Find(P->X(),P->Y(),x2,y2);
   if(result == 0)
    Path->Pop();
   else
    return result;
  }
 }
 P->Left();


  return 0; // 4방향 모두 경로가 없으므로 0을 반환
   
}


void Maze::Sol()
{

 if(Path->IsEmpty()) throw "Error"; // 스택이 비어있거나 Find함수가 먼저 실행되지 않았을때

 int i,j;
 
 std::cout << "Maze-\n";
 for(i=0;i<15;i++)
 {
  for(j=0;j<15;j++)
  {
   std::cout << Map[i][j] << " ";
  }
  std::cout << "\n";
 }

 std::cout << "\n" << "Solution-\n";
 
 int sol[15][15];
 Location temp;
 for(i=14;i>=0;i--)
  for(j=14;j>=0;j--)
   sol[i][j]=0;
 while(!Path->IsEmpty())
 {
  temp = Path->Pop();
  sol[temp.Y()][temp.X()] = 1;
 }

 for(i=0;i<15;i++)
 {
  for(j=0;j<15;j++)
  {
   std::cout << sol[i][j] << " ";
  }
  std::cout << "\n";
 }

}