Development/자료구조 & 알고리즘

[알고리즘] 프로그래머스 - 리코쳇 로봇 (JS)

heondeam 2023. 9. 2. 15:33

 

✅ 문제

리코쳇 로봇이라는 보드게임이 있습니다.

이 보드게임은 격자모양 게임판 위에서 말을 움직이는 게임으로, 시작 위치에서 목표 위치까지 최소 몇 번만에 도달할 수 있는지 말하는 게임입니다.

이 게임에서 말의 움직임은 상, 하, 좌, 우 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...."]);