리코쳇 로봇

Lv. 2

Solution

import { range } from '@algorithm/lib';
 
export function ricochetRobot(board: string[]): number {
  const [m, n] = [board.length, board[0].length];
  const directions = [
    [0, 1],
    [0, -1],
    [1, 0],
    [-1, 0],
  ];
  const visited = Array.from({ length: m }).map(() => new Array(n).fill(false));
 
  const isMovable = (y: number, x: number) =>
    0 <= y && y < m && 0 <= x && x < n && board[y][x] !== 'D';
  const findRobot = () => {
    for (const y of range(m)) {
      for (const x of range(n)) {
        if (board[y][x] === 'R') {
          return [y, x];
        }
      }
    }
    throw "Can't find robot.";
  };
 
  const moveRobot = (y: number, x: number, direction: number) => {
    const [dy, dx] = directions[direction];
    let [cy, cx] = [y, x];
    let [ny, nx] = [cy + dy, cx + dx];
    while (isMovable(ny, nx)) {
      [cy, cx] = [ny, nx];
      [ny, nx] = [ny + dy, nx + dx];
    }
    return [cy, cx];
  };
 
  const [sy, sx] = findRobot();
  visited[sy][sx] = true;
 
  let queue = [[sy, sx, 0]];
  while (0 < queue.length) {
    const nextQueue: number[][] = [];
    for (const [cy, cx, cc] of queue) {
      for (const direction of range(4)) {
        const [ny, nx] = moveRobot(cy, cx, direction);
        if (board[ny][nx] === 'G') {
          return cc + 1;
        }
        if (!visited[ny][nx]) {
          visited[ny][nx] = true;
          nextQueue.push([ny, nx, cc + 1]);
        }
      }
    }
    queue = nextQueue;
  }
 
  return -1;
}