[프로그래머스] 주사위 게임 3

badassong·2023년 8월 14일
0

JS

목록 보기
28/31
post-thumbnail

문제

1부터 6까지 숫자가 적힌 주사위가 네 개 있습니다. 네 주사위를 굴렸을 때 나온 숫자에 따라 다음과 같은 점수를 얻습니다.

네 주사위에서 나온 숫자가 모두 p로 같다면 1111 × p점을 얻습니다.
세 주사위에서 나온 숫자가 p로 같고 나머지 다른 주사위에서 나온 숫자가 q(p ≠ q)라면 (10 × p + q)2 점을 얻습니다.
주사위가 두 개씩 같은 값이 나오고, 나온 숫자를 각각 p, q(p ≠ q)라고 한다면 (p + q) × |p - q|점을 얻습니다.
어느 두 주사위에서 나온 숫자가 p로 같고 나머지 두 주사위에서 나온 숫자가 각각 p와 다른 q, r(q ≠ r)이라면 q × r점을 얻습니다.
네 주사위에 적힌 숫자가 모두 다르다면 나온 숫자 중 가장 작은 숫자 만큼의 점수를 얻습니다.
네 주사위를 굴렸을 때 나온 숫자가 정수 매개변수 a, b, c, d로 주어질 때, 얻는 점수를 return 하는 solution 함수를 작성해 주세요.


내가 푼 방법

function solution(a, b, c, d) {
    if (a === b && a === c && a === d) return 1111 * a

    if (a === b && a === c) return (10 * a + d) ** 2
    if (a === b && a === d) return (10 * a + c) ** 2
    if (a === c && a === d) return (10 * a + b) ** 2
    if (b === c && b === d) return (10 * b + a) ** 2

    if (a === b && c === d) return (a + c) * Math.abs(a - c)  // 절댓값 구하기
    if (a === c && b === d) return (a + b) * Math.abs(a - b)
    if (a === d && b === c) return (a + b) * Math.abs(a - b)

    if (a === b) return c * d
    if (a === c) return b * d
    if (a === d) return b * c
    if (b === c) return a * d
    if (b === d) return a * c
    if (c === d) return a * b

    return Math.min(a, b, c, d)
}

어떻게 접근해야 할지 감이 잘 안와서 일단 노가다로 해결했다..🥲
하지만 이렇게 풀 순 없지..!!😎


Solution 😆

/*
 정확하게 이런 순서로 코드를 작성하자!
  1. 숫자를 정렬한다
  2. 각 주사위 숫자의 개수를 센다
  3. 주사위 규칙에 따라 점수를 계산한다
    3-1. 모두 같은 경우
    3-2. 모두 다른 경우
    3-3. 2개는 같지만, 나머지가 다른 경우
    
    위 3가지 케이스를 머리속에서 지워보자.
    남은 케이스는 주사위가 (2🎲🎲, 2🎲🎲)씩 나왔거나, (3🎲🎲🎲,1🎲)씩 나온 경우이다.
    나머지 케이스를 고려할 필요가 없다. 머리가 가벼워진다..

    3-4. 2개씩 같은 경우
    3-5. 3개만 같은 경우

 A. 주사위게임은 순서가 상관없다.
    그러나 숫자를 정렬해두면, 사람의 머리속으로 상상하는 내용이 단순해진다.
 B. 주의! object의 keys는 String이다. 나중에 key를 숫자로 쓰려면 Number로 변환해줘야 한다.
*/
function diceGame(a, b, c, d) {
  const numbers = [a, b, c, d];
  numbers.sort((x, y) => x - y);

  const diceReport = countDuplicates(numbers)
  const keys = Object.keys(diceReport); 

  // 쉬운 케이스를 먼저 처리하고 머리속에서 잊자.
  switch (keys.length){
    case 1: return sameAll(a);
    case 4: return differentAll(numbers);
    case 3: return same211(diceReport);
    case 2:
      if (diceReport[a] === 2 )     // diceReport[a] ===3 || diceReport[a] === 1 이렇게 비교할 수도 있는데, 2 한번만 비교하는게 더 간편하다.
        return same22(keys.map(Number))
      return same31(diceReport, keys.map(Number))
  }
}

function countDuplicates(arr) {
  const countMap = {};
  
  for (const num of arr) {
    if (countMap[num] === undefined) 
      countMap[num] = 0;
    
    countMap[num] += 1;
  }

  return countMap;
}

function sameAll(p){
  return p * 1111;
}

function same31(report, [p, q]){
  if (report[p] === 1) [p, q] = [q, p]; // p가 1개인 경우, swap(p ,q). 그럼 p가 3개짜리 숫자가 된다.

  return Math.pow(10*p + q, 2);
}


function same22([p, q]){
  return (p+q) * Math.abs(p-q);
}

function same211(report){
  const [q, r] = Object.keys(report).filter(key => report[key] === 1).map(Number);
  return q * r;
}


// 물론 differentAll 자리에 Math.min 함수를 바로 사용할 수도 있다.
// 그러나 이렇게 하면, 다른 함수들과 형식이 달라져서 diceGame 함수를 이해하는 것이 복잡해진다.
// 사람의 두뇌는 차이점을 인지하는데 특화되어 있어서 그렇다.
// 따라서 switch case의 경우 주변과 비슷하게 작성하는 것이 좋다.
// 누누히 강조하지만, 함수 호출 하나 더 하는 것은 속도에 아무 영향을 끼치지 않는다.
// 그러나 사람이 코드를 읽기 힘들면 개발이 느려지도 관리가 어려워진다.
function differentAll(arr){
  return Math.min(...arr);
}
profile
프론트엔드 대장이 되어보쟈

0개의 댓글