[백준] 20125 쿠키의 신체 측정 JavaScript

·2024년 5월 31일

문제

쿠키런은 데브시스터즈에서 제작한 모바일 러닝 액션 게임이다. 마녀의 오븐에서 탈출한 쿠키들과 함께 모험을 떠나는 게임으로, 점프와 슬라이드 2가지 버튼만으로 손쉽게 플레이할 수 있는 것이 특징이다.

연세대학교를 졸업한 김강산 선배님이 데브시스터즈에 취직하면서 주변 사람들에게 쿠키런을 전파시켰다. 하지만 게임을 전파하던 중에 쿠키들에게 신체적으로 이상이 생기는 것을 발견하였다. 팔, 다리 길이가 임의적으로 변한 것이다. 때문에 긴급하게 각 쿠키들의 신체들을 측정하려고 한다.

쿠키들은 신체를 측정하기 위해서 한 변의 길이가 N인 정사각형 판 위에 누워있으며, 어느 신체 부위도 판 밖으로 벗어나지 않는다. 판의 x번째 행, y번째 열에 위치한 곳을 (x, y)로 지칭한다. 판의 맨 왼쪽 위 칸을 (1, 1), 오른쪽 아래 칸을 (N, N)으로 나타낼 수 있다.

그림과 같이 쿠키의 신체는 머리, 심장, 허리, 그리고 좌우 팔, 다리로 구성되어 있다. 그림에서 빨간 곳으로 칠해진 부분이 심장이다. 머리는 심장 바로 윗 칸에 1칸 크기로 있다. 왼쪽 팔은 심장 바로 왼쪽에 붙어있고 왼쪽으로 뻗어 있으며, 오른쪽 팔은 심장 바로 오른쪽에 붙어있고 오른쪽으로 뻗어있다. 허리는 심장의 바로 아래 쪽에 붙어있고 아래 쪽으로 뻗어 있다. 왼쪽 다리는 허리의 왼쪽 아래에, 오른쪽 다리는 허리의 오른쪽 아래에 바로 붙어있고, 각 다리들은 전부 아래쪽으로 뻗어 있다. 각 신체 부위들은 절대로 끊겨있지 않으며 굽혀진 곳도 없다. 또한, 허리, 팔, 다리의 길이는 1 이상이며, 너비는 무조건 1이다.

쿠키의 신체가 주어졌을 때 심장의 위치와 팔, 다리, 허리의 길이를 구하여라.

입력

다음과 같이 입력이 주어진다.

N
a1,1 . . . a1,N
. . . . . .
aN,1 . . . aN,N

5 ≤ N ≤ 1,000. N은 판의 한 변의 길이를 의미하는 양의 정수다.
ai,j는 * 또는 _이다. *는 쿠키의 신체 부분이고, _는 쿠키의 신체가 올라가 있지 않은 칸을 의미한다. (1 ≤ i, j ≤ N)
쿠키의 신체 조건에 위배되는 입력은 주어지지 않는다.

출력

첫 번째 줄에는 심장이 위치한 행의 번호 x와 열의 번호 y를 공백으로 구분해서 출력한다.

두 번째 줄에는 각각 왼쪽 팔, 오른쪽 팔, 허리, 왼쪽 다리, 오른쪽 다리의 길이를 공백으로 구분해서 출력하여라.

예제 입력

10

__________
_____*____
__******__
_____*____
_____*____
_____*____
____*_*___
____*_____
____*_____
____*_____

예제 출력

3 6
3 2 3 4 1

내가 했던 풀이 방법

  1. heart와 arm을 [null, null]로 초기화해준다. 이때 heart는 [y, x]를 의미하고 arm은 [left, right]를 의미한다. (즉, heart는 좌표를 담을 것이고, arm은 길이를 담을 것이다. 헷갈리지 않게 주의한다.)
  2. 쿠키의 신체를 위에서부터 아래 방향으로 진행하며 검사를 한다. 이때, 해당 line에서 "*"가 첫 등장하는 index와 마지막 등장하는 index가 다를 경우부터가 arm이다. 그러므로, indexOf와 lastIndexOf를 사용해 "*"가 같을 때는, 해당 index를 heart의 x로 저장하고, "*"의 위치가 달라질 때 해당 line을 heart의 y에 저장한다. heart가 있는 곳 양 옆에 팔이 있으므로, 처음으로 *이 등장했을 때가 왼쪽 팔의 시작지점이고, *이 마지막으로 등장했을 때가 오른쪽 팔의 시작지점이다. 해당 index를 heart의 x좌표를 이용해서 길이를 구해준 뒤, for문을 중단한다.
  3. heart의 좌표를 +1해서 출력해준다. (좌표는 1부터 시작하지만, 배열은 0부터 시작하기 때문에 +1을 해주어야 한다. 심장의 좌표를 제외한 다른 신체는 길이를 출력하므로 heart의 직접 +1을 해주면 계산이 불편해지므로, 출력 시에만 +1을 해준다.)
  4. leg를 [null, null]로 waist를 0으로 초기화해준다. 이때 leg는 [left, right]를 의미하고, waist는 허리가 끝나는 지점이다. (즉, leg는 길이를 담고, waist는 y좌표를 담을 것이다.)
  5. 쿠키의 신체를 심장 다음부터 아래 방향으로 진행하며 검사를 한다. 이때 해당 line에서 해당 line에서 "*"가 첫 등장하는 index와 마지막 등장하는 index가 다를 경우부터가 leg이다. 그러므로 2번과 같은 방법을 사용해준다. 둘의 index가 같을 때는 허리일수도 있지만, 한쪽 다리는 끝났지만, 다른쪽 다리가 아직 끝나지 않았을 때일 수도 있다. 그러므로, indexOf와 lastIndexOf가 같지만, 해당 index가 heart의 x좌표와 같을 경우에는 허리이고, x좌표보다 작을 때 왼쪽 다리, 클 때 오른쪽 다리임을 이용한다.
  6. index가 같고, x좌표가 heart와 같을 경우 waist를 현재 검사 line으로 바꿔준다. 이렇게 될 경우, 허리가 끝날 때까지 waist가 바뀌게 되고, 마지막으로 저장된 waist가 허리의 최종 y좌표이다. 이후 index가 서로 달라지게 되고, 허리의 y도 알고있기 때문에 leg를 waist를 이용해 길이를 저장해줄 수 있다. 하지만 두 다리 길이가 동일하지 않기 때문에 이후에 index가 같아질 경우 심장의 x좌표를 이용해 왼쪽/오른쪽 다리를 판별하고 해당 다리의 길이를 갱신해준다. 이렇게 모든 신체를 다 검사했을 때 최종적으로 저장된 leg가 다리의 길이이다.
  7. body 배열에 출력 순서대로 값을 넣어준다. 이때 waist는 허리의 y좌표일 뿐 허리의 길이가 아니므로, heart의 y좌표를 이용해 길이를 계산 후 넣어준다.
  8. body 배열을 문자열로 변환 후 출력해준다.

코드

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

N = Number(N);

let heart = [null, null];
let arm = [null, null];
for (let i = 0; i < input.length; i++) {
  input[i] = input[i].trim();
  if (input[i].indexOf('*') !== input[i].lastIndexOf('*')) {
    heart[0] = i;
    arm = [heart[1] - input[i].indexOf('*'), input[i].lastIndexOf('*') - heart[1]];
    break;
  } else {
    heart[1] = input[i].indexOf('*');
  }
}
console.log(`${heart[0] + 1} ${heart[1] + 1}`);

let leg = [null, null];
let waist = 0;
for (let i = heart[0] + 1; i < input.length; i++) {
  input[i] = input[i].trim();
  if (input[i].indexOf('*') !== input[i].lastIndexOf('*')) {
    leg = [i - waist, i - waist];
  } else {
    if (input[i].indexOf('*') === heart[1]) waist = i;
    else if (input[i].indexOf('*') === heart[1] - 1) leg[0] = i - waist;
    else if (input[i].indexOf('*') === heart[1] + 1) leg[1] = i - waist;
  }
}

let body = [arm[0], arm[1], waist - heart[0], leg[0], leg[1]];
console.log(body.join(' '));

회고

구현은 엄청 쉽지만, 아무래도 구현이라는 특성상 방법을 설명하려면 장문이 되어버려서.... 문제 풀이가 굉장히 복잡한 것 같지만 실제로는 좌표 놀이. 어렵지 않아서 기록 안 하려고 하긴 했는데 문제가 재미있어서 기록했다.

profile
Frontend🍓

0개의 댓글