[알고리즘] 프로그래머스 - 리코쳇 로봇 (JS)
✅ 문제
리코쳇 로봇이라는 보드게임이 있습니다.
이 보드게임은 격자모양 게임판 위에서 말을 움직이는 게임으로, 시작 위치에서 목표 위치까지 최소 몇 번만에 도달할 수 있는지 말하는 게임입니다.
이 게임에서 말의 움직임은 상, 하, 좌, 우 4방향 중 하나를 선택해서 게임판 위의 장애물이나 맨 끝에 부딪힐 때까지 미끄러져 이동하는 것을 한 번의 이동으로 칩니다.
다음은 보드게임판을 나타낸 예시입니다.
...D..R
.D.G...
....D.D
D....D.
..D....
여기서 "."은 빈 공간을, "R"은 로봇의 처음 위치를, "D"는 장애물의 위치를, "G"는 목표지점을 나타냅니다.
위 예시에서는 "R" 위치에서 아래, 왼쪽, 위, 왼쪽, 아래, 오른쪽, 위 순서로 움직이면 7번 만에 "G" 위치에 멈춰 설 수 있으며, 이것이 최소 움직임 중 하나입니다.
게임판의 상태를 나타내는 문자열 배열 board가 주어졌을 때, 말이 목표위치에 도달하는데 최소 몇 번 이동해야 하는지 return 하는 solution함수를 완성하세요. 만약 목표위치에 도달할 수 없다면 -1을 return 해주세요.
✅ 풀이
일단 BFS 알고리즘을 사용해서, 시작점을 기준으로 4방향으로 탐색해나간다.
기존 BFS 알고리즘과 다른 점은 탐색 방향으로 반복해서 나아가다가 벽이나 장애물을 만났을 때 그 위치가 큐에 들어갈 다음 위치가 된다. 이 부분을 코드로 구현하는 것이 핵심이다.
또한 최솟값을 찾아나가야 하기 때문에 visited 배열의 모든 원소를 10000으로 설정해두고, 종착점에 도달하기 까지의 가장 적은 cnt를 누적해나가며 풀이했다.
function solution (board) {
const maps = [];
const visited = [];
let [sx, sy] = [0, 0];
let [end_x, end_y] = [0, 0];
for (let i = 0; i < board.length; i ++) {
maps.push([]);
visited.push([]);
const splitedStr = board[i].split("");
for (let j = 0; j < splitedStr.length; j ++) {
maps[i].push(splitedStr[j]);
visited[i].push(10000);
if(splitedStr[j] === "R") {
sx = i;
sy = j;
}
if(splitedStr[j] === "G") {
end_x = i;
end_y = j;
}
}
}
// 벽
const [w, h] = [board[0].length, board.length];
// 탐색을 위한 방향 설정 (상, 우, 하, 좌)
const [dx, dy] = [[-1, 0, 1, 0], [0, 1, 0, -1]];
const bfs = (x, y) => {
const queue = [[x, y, 0]];
while(queue.length) {
if (visited[end_x][end_y] !== 10000) {
return visited[end_x][end_y];
}
const [ex, ey, ec] = queue.shift();
for (let i = 0; i < 4; i++) {
let [nx, ny, nc] = [ex, ey, ec + 1];
// 현재 방향으로 끝 OR 장애물 만날 때까지 이동.
while ((ny + dy[i] < w && nx + dx[i] < h) && (ny + dy[i] >= 0 && nx + dx[i] >= 0) && maps[nx + dx[i]][ny + dy[i]] !== "D") {
ny += dy[i];
nx += dx[i];
}
// 현재 좌표가 유효하다면?
if ((ny < w && nx < h) && (ny >= 0 && nx >= 0)) {
if (nc < visited[nx][ny]) {
visited[nx][ny] = nc;
queue.push([nx, ny, nc]);
}
}
}
}
return -1;
}
return bfs(sx, sy);
}
solution(["...D..R", ".D.G...", "....D.D", "D....D.", "..D...."]);