STUDY/Algorithm

[프로그래머스_자바스크립트] Lv.2 당구 연습 / math, 좌표 이동, 대칭

ez1n 2023. 3. 21. 20:27

 

[Javascript_ 당구 연습]

 

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 


 

<STUDY>

 

📢 문제 📢

 

최근 취미로 알고리즘 문제를 풀기 시작한 당신은,

머쓱이가 친 공이 각각의 목표로한 공에 맞을 때까지 최소 얼마의 거리를 굴러가야 하는지가 궁금해졌습니다.

 

당구대의 가로 길이 m, 세로 길이 n과 머쓱이가 쳐야 하는 공이 놓인 위치 좌표를 나타내는 두 정수 startX, startY, 그리고 매 회마다 목표로 해야하는 공들의 위치 좌표를 나타내는 정수 쌍들이 들어있는 2차원 정수배열 balls가 주어집니다.

 

"원쿠션" (당구에서 공을 쳐서 벽에 맞히는 걸 쿠션이라고 부르고, 벽에 한 번 맞힌 후 공에 맞히면 원쿠션이라고 부릅니다) 연습을 위해 머쓱이가 공을 적어도 벽에 한 번은 맞춘 후 목표 공에 맞힌다고 할 때,

각 회마다 머쓱이가 친 공이 굴러간 거리의 최솟값의 제곱을 배열에 담아 return 하도록 solution 함수를 완성해 주세요.

 

단, 머쓱이가 친 공이 벽에 부딪힐 때 진행 방향은 항상 입사각과 반사각이 동일하며, 만약 꼭짓점에 부딪힐 경우 진입 방향의 반대방향으로 공이 진행됩니다.

공의 크기는 무시하며, 두 공의 좌표가 정확히 일치하는 경우에만 두 공이 서로 맞았다고 판단합니다.

공이 목표 공에 맞기 전에 멈추는 경우는 없으며, 목표 공에 맞으면 바로 멈춘다고 가정합니다.

 

제한사항

  • 3 ≤ m, n ≤ 1,000
  • 0 < startX < m
  • 0 < startY < n
  • 2 ≤ balls의 길이 ≤ 1,000
  • balls의 원소는 [a, b] 형태입니다.
    • a, b는 머쓱이가 맞춰야 할 공이 놓인 좌표를 의미합니다.
    • 0 < a < m, 0 < b < n
    • (a, b) = ( startX, startY )인 입력은 들어오지 않습니다.

 


 

<전체 코드>

 

function solution(m, n, startX, startY, balls) {
  let answer = [];
  
  balls.forEach(([endX, endY]) => {
    let distance = [];

    if (startX !== endX || startY > endY) {
      distance.push((startX - endX) ** 2 + (startY - 2 * n + endY) ** 2);
    }
    if (startX !== endX || startY < endY) {
      distance.push((startX - endX) ** 2 + (startY + endY) ** 2);
    }
    if (startY !== endY || startX < endX) {
      distance.push((startX + endX) ** 2 + (startY - endY) ** 2);
    }
    if (startY !== endY || startX > endX) {
      distance.push((startX - 2 * m + endX) ** 2 + (startY - endY) ** 2);
    }
    answer.push(Math.min(...distance));
  });

  return answer;
}

 


 

<풀이 방법>

 

처음에 문제를 봤을 때 좌표로 풀어야 한다는 감은 잡았지만 정확히 어떤 식으로 풀이를 해야하는지 잘 몰랐다.

 

그런데 입사각과 반사각이 같고 목표까지 갈 수 있는 최단거리를 구한다는 말에서

아래 그림과 같이 목표 좌표(공)를 대칭을 시키면 거리를 알 수 있다는 것을 깨달았다.

 

 

그러나 x좌표가 같거나 y좌표가 같은 경우 아래 그림처럼 쿠션에 부딪히기 전에 목표 좌표(공)과 먼저 부딪히기 때문에 불가능한 경우가 생긴다.

👻 부딪히는 경우

  • x1 === x2 이고 y1 < y2 : 위쪽 대칭 (y = n)
  • x1 === x2 이고 y1 > y2 : 아래쪽 대칭 (x축)
  • y1 === y2 이고 x1 < x2 : 오른쪽 대칭 (x = m)
  • y1 === y2 이고 x1 > x2 : 왼쪽 대칭 (y축)

 

이 경우를 고려하여 x축, y축, x = m, y = n을 기준으로 대칭시켜 그 중 가장 짧은 길이를 선택한다.

 

if (startX !== endX || startY > endY) {
    distance.push((startX - endX) ** 2 + (startY - 2 * n + endY) ** 2);
}
if (startX !== endX || startY < endY) {
    distance.push((startX - endX) ** 2 + (startY + endY) ** 2);
}
if (startY !== endY || startX < endX) {
    distance.push((startX + endX) ** 2 + (startY - endY) ** 2);
}
if (startY !== endY || startX > endX) {
    distance.push((startX - 2 * m + endX) ** 2 + (startY - endY) ** 2);
}

answer.push(Math.min(...distance));

 


 

처음에 대칭을 한다는 생각을 하지 못해서 생각보다 오래걸렸다.

 

어떤 방법으로 풀어야 하는지 큰 그림을 먼저 그리고 알고리즘을 생각하는 연습이 필요할 것 같다.

 

앞으로 더 열심히 해야겠다!

 


🔆프로그래머스 Lv2. 당구 연습🔆

 

👉ez1n github 구경하기👈

 

ez1n - Overview

Front-End Developer. ez1n has 18 repositories available. Follow their code on GitHub.

github.com