오른손 법칙(Right-Hand Rule)은 미로 탐색 알고리즘 중 하나로,
"항상 벽에 오른손을 대고 이동한다"는 규칙을 따릅니다.
시계 방향 회전이 아닌, 반시계 방향 기준 열거형이므로,
"오른쪽"은_dir - 1, "왼쪽"은_dir + 1로 계산됩니다.
Player::Init)void Player::Init(Board* board)
{
_pos = board->GetEnterPos(); // 시작 위치 설정
_board = board;
Pos pos = _pos;
_path.clear(); // 경로 초기화
_path.push_back(pos);
Pos dest = board->GetExitPos(); // 목적지 설정
Pos front[4] = {
{ -1, 0 }, // UP
{ 0, -1 }, // LEFT
{ 1, 0 }, // DOWN
{ 0, 1 } // RIGHT
};
while (pos != dest)
{
int32 newDir = (_dir - 1 + DIR_COUNT) % DIR_COUNT;
if (CanGo(pos + front[newDir]))
{
_dir = newDir; // 오른쪽으로 회전
pos += front[_dir]; // 한 보 전진
_path.push_back(pos); // 경로 저장
}
else if (CanGo(pos + front[_dir]))
{
pos += front[_dir]; // 전진
_path.push_back(pos);
}
else
{
_dir = (_dir + 1) % DIR_COUNT; // 왼쪽 회전
}
}
}
| 요소 | 설명 |
|---|---|
_dir | 현재 방향 (0~3) |
front[4] | 방향 벡터 (UP, LEFT, DOWN, RIGHT) |
_path | 계산된 경로를 저장하는 벡터 |
CanGo() | 해당 좌표가 EMPTY인지 검사 |
Player::Update)void Player::Update(uint64 deltaTick)
{
if (_pathIndex >= _path.size())
return;
_sumTick += deltaTick;
if (_sumTick >= MOVE_TICK)
{
_sumTick = 0;
_pos = _path[_pathIndex]; // 다음 위치 이동
_pathIndex++;
}
}
deltaTick: ::GetTickCount64()로 계산한 프레임 경과 시간MOVE_TICK: 100ms로 설정 → 0.1초마다 한 칸씩 이동_pos: 실제 현재 위치, _path[_pathIndex]에서 단계별 참조bool Player::CanGo(Pos pos)
{
TileType tileType = _board->GetTileType(pos);
return tileType == TileType::EMPTY;
}
빈 공간(EMPTY)일 경우에만 true 반환Board::Render)void Board::Render()
{
ConsoleHelper::SetCursorPosition(0, 0);
ConsoleHelper::ShowConsoleCursor(false);
for (int32 y = 0; y < 25; y++)
{
for (int32 x = 0; x < 25; x++)
{
ConsoleColor color = GetTileColor(Pos{ y, x });
ConsoleHelper::SetCursorColor(color);
cout << "■";
}
cout << endl;
}
}
| 타일 | 색상 |
|---|---|
| 벽 | 🔴 RED |
| 길 | 🟢 GREEN |
| 플레이어 | 🟡 YELLOW |
| 출구 | 🔵 BLUE |
void Board::GenerateMap()
{
for (int32 y = 0; y < _size; y++)
{
for (int32 x = 0; x < _size; x++)
{
_tile[y][x] = (x % 2 == 0 || y % 2 == 0) ? TileType::WALL : TileType::EMPTY;
}
}
for (int32 y = 0; y < _size; y++)
{
for (int32 x = 0; x < _size; x++)
{
if (x % 2 == 0 || y % 2 == 0)
continue;
if (y == _size - 2 && x == _size - 2)
continue;
if (y == _size - 2)
{
_tile[y][x + 1] = TileType::EMPTY;
continue;
}
if (x == _size - 2)
{
_tile[y + 1][x] = TileType::EMPTY;
continue;
}
const int32 randValue = rand() % 2;
if (randValue == 0)
_tile[y][x + 1] = TileType::EMPTY;
else
_tile[y + 1][x] = TileType::EMPTY;
}
}
}
int main()
{
::srand(static_cast<unsigned>(time(nullptr)));
board.Init(25, &player);
player.Init(&board);
uint64 lastTick = 0;
while (true)
{
const uint64 currentTick = ::GetTickCount64();
const uint64 deltaTick = currentTick - lastTick;
lastTick = currentTick;
player.Update(deltaTick);
board.Render();
}
}
_path에 저장deltaTick 단위로 일정 시간마다 플레이어 이동| 구분 | 설명 |
|---|---|
| ✅ 장점 | 구현이 간단하고 벽에 붙어 있으면 반드시 탈출 가능 |
| ⚠️ 단점 | 순환이 없는 미로에서만 보장됨, 최단 경로 아님 |
| ➕ 확장성 | DFS, BFS, A* 등 다른 알고리즘으로 대체 가능 |