공원 산책 문제

2023년 11월 19일

문제

공원내의 장애물과 산책이 가능한 길에 대한 정보가 담겨 있는 park와 상하좌우 방향 중 어디로 움직일 것인지에 대한 정보와 그 방향으로 몇번 움직일지에 대한 정보를 입력 값으로 제공받았을 경우 시작지점 S에서 모두 이동 했을 시 마지막에 위치한 곳에 대한 정보를 반환하는 문제이다.
const park = ["SOO", "OOO", "OOO"];
const routes = ["E 2", "S 2", "W 1"];
const result = [2, 1];
이에 문제를 해결한 나의 코드는 아래와 같다.
const DIR = {
  N: [-1, 0],
  E: [0, 1],
  S: [1, 0],
  W: [0, -1],
};

function solution(park, routes) {
  var answer = [];
  const width = park.length;
  const height = park[0].length;

  let start = [];
  for (let i = 0; i < park.length; i++) {
    for (let j = 0; j < park[i].length; j++) {
      if (park[i][j] === "S") {
        start = [i, j];
        routes.forEach((route) => {
          route = route.split(" ");
          start = search(start, route[0], route[1]);
        });
        return start;
      }
    }
  }

  return start;

  function search(start, dir, count) {
    const [x, y] = DIR[dir];
    let tmp = [...start];
    const maxX = count * x;
    const maxY = count * y;
    if (
      tmp[0] + maxX >= width ||
      tmp[1] + maxY >= height ||
      tmp[0] + maxX < 0 ||
      tmp[1] + maxY < 0
    ) {
      return start;
    }

    for (let i = 0; i < count; i += 1) {
      const nextX = tmp[0] + x;
      const nextY = tmp[1] + y;

      if (park[nextX][nextY] === "X") {
        return start;
      }
      tmp = [nextX, nextY];
    }
    return tmp;
  }
}
처음에는 시작 좌표를 park에서 시작지점을 찾고 park 값을 split('')을 이용하여 배열의 형태로 값을 수정하여 해결하려 했다. 하지만 이렇게 접근한 방법은 모든 배열을 순환하고 변환해야 한다는 단점으로 인해 시간을 초과해서 테스트를 통과하지 못했다.
그래서 모든 배열을 탐색할 것이 아닌 시작지점 S를 찾았을 경우 그 지점에서 멈춰서 값을 이동하고 판단하는 것이 더 효율적일 것이라 생각해서 위와 같이 코드를 작성했다.
코드의 효율성을 높이기 위해서는 최대한 탐색을 자제하고 루프 함수를 줄여야 한다.

내 코드의 단점

  1. 너무 장황하다.
  2. 중복되는 코드가 많다.
  3. 반복문과 조건문이 많다.
스스로 판단하였을 때 생각되는 나의 코드의 문제점이다. 위의 3가지는 코드의 품질을 저하 시키는 주된 요인이기 때문에 다시 리펙토링 해볼 필요가 있다.
const DIR = {
  N: [-1, 0],
  E: [0, 1],
  S: [1, 0],
  W: [0, -1],
};

function solution(park, routes) {
  const [width, height] = [park.length, park[0].length];
  let start = findStart(park);

  for (const route of routes) {
    const [dir, count] = route.split(" ");
    console.log(start);
    if (isNotValidPosition(start, dir, count)) {
      continue;
    }
    start = move(start, dir, parseInt(count));
  }

  return start;

  function move(position, dir, count) {
    const [x, y] = DIR[dir];
    let [curX, curY] = position;

    for (let i = 0; i < count; i++) {
      const [nextX, nextY] = [curX + x, curY + y];
      if (park[nextX][nextY] === "X") {
        return position;
      }
      [curX, curY] = [nextX, nextY];
    }

    return [curX, curY];
  }

  function isNotValidPosition(start, dir, count) {
    const [x, y] = DIR[dir];
    const [maxX, maxY] = [count * x, count * y];
    const [currX, currY] = start;
    if (
      currX + maxX >= width ||
      currY + maxY >= height ||
      currX + maxX < 0 ||
      currY + maxY < 0
    ) {
      return true;
    }
    return false;
  }
}

function findStart(park) {
  for (let i = 0; i < park.length; i++) {
    for (let j = 0; j < park[i].length; j++) {
      if (park[i][j] === "S") {
        return [i, j];
      }
    }
  }
}
방법은 유지하되 여러개의 함수를 추출하여 리펙토링 했다. 내가 사용한 방법이외의 해결책도 탐색해 보아야 겠다.