[백준] 8911 거북이 JavaScript

·2024년 4월 23일

문제

상근이는 2차원 평면 위에서 움직일 수 있는 거북이 로봇을 하나 가지고 있다. 거북이 로봇에게 내릴 수 있는 명령은 다음과 같이 네가지가 있다.

F: 한 눈금 앞으로
B: 한 눈금 뒤로
L: 왼쪽으로 90도 회전
R: 오른쪽으로 90도 회전
L과 R명령을 내렸을 때, 로봇은 이동하지 않고, 방향만 바꾼다. 명령을 나열한 것을 거북이 로봇의 컨트롤 프로그램이라고 한다.

상근이는 자신의 컨트롤 프로그램으로 거북이가 이동한 영역을 계산해보려고 한다. 거북이는 항상 x축과 y축에 평행한 방향으로만 이동한다. 거북이가 지나간 영역을 모두 포함할 수 있는 가장 작은 직사각형의 넓이를 구하는 프로그램을 작성하시오. 단, 직사각형의 모든 변은 x축이나 y축에 평행이어야 한다.

아래 그림에서 거북이는 가장 처음에 (0, 0)에 있고, 북쪽을 쳐다보고 있다. 컨트롤 프로그램이 FLFRFLBRBLB인 경우에 거북이는 아래와 같이 움직인다. 회색으로 빗금친 부분이 거북이가 지나간 영역을 모두 포함할 수 있는 가장 작은 직사각형이다. 넓이는 4가 된다.

거북이가 지나간 영역이 직사각형을 만들지 않는 경우도 있다. 예를 들어, FFLLFF인 경우에 거북이는 y축의 위로만 지나다닌다. 이 경우에 거북이가 지나간 영역을 모두 포함하는 직사각형은 선분이고, 선분은 한 변이 0인 직사각형으로 생각할 수 있다. 따라서, 선분의 경우에 넓이는 0이 된다.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 컨트롤 프로그램이 주어진다. 프로그램은 항상 문제의 설명에 나와있는 네가지 명령으로만 이루어져 있고, 길이는 500을 넘지 않는다.

출력

각 테스트 케이스에 대해서, 거북이가 이동한 영역을 모두 포함하는 가장 작은 직사각형의 넓이를 출력한다.

예제 입력

3
FFLF
FFRRFF
FFFBBBRFFFBBB

예제 출력

2
0
9

내가 했던 풀이 방법

  1. 현재 위치를 current 배열에 저장한다. 초기값은 [0, 0]이다. 거북이가 바라보는 방향을 direction에 저장한다. 초기값은 N(북쪽)이다.
  2. min과 max 배열을 [0, 0](거북이의 시작 위치)으로 초기화해준다. 해당 코드에서 min과 max의 값은 min/max인 x좌표와 y좌표를 의미한다. 간단히 말해 min이 [3, 5]일 경우, 거북이가 [3, 5]를 지나가지 않았을 수 있다. 그저 거북이가 이동한 좌표 중 x좌표의 최솟값은 3, y좌표의 최댓값은 5를 의미한다.
  3. command(각 테스트케이스)의 길이만큼 반복하면서 명령어를 실행해준다. 명령어가 F 또는 B였을 때, 거북이가 바라보는 방향에 따라 current 값을 이전 current 값을 이용해서 +1하거나 -1해준다. 명령어가 L 또는 R이었을 때, 거북이의 현재 direction을 기준으로 오른쪽 또는 왼쪽으로 회전한 방향을 direction에 저장해준다.
  4. F 또는 B 명령어를 실행한 경우, current의 x와 y 좌표를 비교해 min/max값일 경우, min/max 배열에 해당 좌표를 저장해준다.
  5. 모든 command를 실행한 뒤, min과 max 배열의 값을 이용하여 width와 height를 계산해준다. max값보다 min값이 무조건 크므로, Math.abs를 하지 않아도 된다. width와 height를 곱한 값을 answer에 더해준다.

코드

const fs = require('fs');
let [T, ...cases] = fs.readFileSync(0, 'utf-8').toString().trim().split('\n');

let command = '';
let current = [];
let direction = 'N';
let answer = '';
for (let i = 0; i < parseInt(T); i++) {
  current = [0, 0];
  command = cases[i].trim();
  min = [0, 0];
  max = [0, 0];
  for (let j = 0; j < command.length; j++) {
    if (command.charAt(j) === 'F') {
      if (direction === 'N') {
        current = [current[0], current[1] + 1];
      } else if (direction === 'S') {
        current = [current[0], current[1] - 1];
      } else if (direction === 'W') {
        current = [current[0] - 1, current[1]];
      } else {
        current = [current[0] + 1, current[1]];
      }

      if (current[0] < min[0]) min[0] = current[0];
      if (current[1] < min[1]) min[1] = current[1];
      if (current[0] > max[0]) max[0] = current[0];
      if (current[1] > max[1]) max[1] = current[1];
    } else if (command.charAt(j) === 'B') {
      if (direction === 'N') {
        current = [current[0], current[1] - 1];
      } else if (direction === 'S') {
        current = [current[0], current[1] + 1];
      } else if (direction === 'W') {
        current = [current[0] + 1, current[1]];
      } else {
        current = [current[0] - 1, current[1]];
      }

      if (current[0] < min[0]) min[0] = current[0];
      if (current[1] < min[1]) min[1] = current[1];
      if (current[0] > max[0]) max[0] = current[0];
      if (current[1] > max[1]) max[1] = current[1];
    } else if (command.charAt(j) === 'L') {
      if (direction === 'N') {
        direction = 'W';
      } else if (direction === 'S') {
        direction = 'E';
      } else if (direction === 'W') {
        direction = 'S';
      } else {
        direction = 'N';
      }
    } else {
      if (direction === 'N') {
        direction = 'E';
      } else if (direction === 'S') {
        direction = 'W';
      } else if (direction === 'W') {
        direction = 'N';
      } else {
        direction = 'S';
      }
    }
  }

  let width = max[0] - min[0];
  let height = max[1] - min[1];
  answer += width * height + '\n';
}
console.log(answer.trim());

회고

코드가 약간 쓸데없이 길어졌다. min/max 같은 경우에는 F/B 상관없이 같은 코드라서 함수로 묶어줘도 될 것 같다. direction을 구하는 것도 [동, 서, 남, 북] 이런식으로 해서 directions 배열을 이용했다면, 좀 더 간결하게 표현됐을 것 같다. 제출하고 회고를 작성하다보면 좋은 코드가 생각이 자주 난다. 미리미리 떠올랐으면 좋았겠지만... 그래도 이게 사람들이 블로그를 쓰는 이유인 것 같다.

profile
Frontend🍓

0개의 댓글