[js] 주사위 게임 3

sookyoung.k·2024년 7월 4일
1
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 함수를 작성해 주세요.

제한사항

  • a, b, c, d는 1 이상 6 이하의 정수입니다.

나의 풀이

const resort = (arr) => {
    let [a, b, c, d] = arr;
    
    if (a === b && b === c && c === d) {
        return 'case1'; // 네 개의 주사위가 모두 같은 경우
    } else if (a === b && b === c) {
        return 'case2-1'; // 세 개의 주사위가 같은 경우
    } else if (b === c && c === d) {
        return 'case2-2'; // 세 개의 주사위가 같은 경우
    } else if (a === b && c === d) {
        return 'case3'; // 두 개씩 같은 경우
    } else if (a === b || b === c || c === d) {
        return 'case4'; // 두 개만 같은 경우
    } else {
        return 'case5'; // 모두 다른 경우
    }

    // if (b === c && c === d) {
    //     if (b === a) return 'case1';
    //     return 'case2-2';
    // } else if (b === a) {
    //     if (c === a) return 'case2-1';
    //     else if (c === d) return 'case3';
    //     else return 'case4';
    // } else return 'case5';
}

function solution(a, b, c, d) {
    let answer = 0;
    let dice = [a, b, c, d];
    dice.sort((a, b) => a - b);
  
    switch(resort(dice)) {
        case 'case1':
            // 주사위 눈이 모두 같음 
            answer = 1111 * dice[0];
            break;
        case 'case2-1':
            // 주사위 눈이 하나 빼고 다 같음 (ex.1, 1, 1, 4)
            answer = (10 * dice[0] + dice[3]) ** 2;
            break;
        case 'case2-2':
            // 주사위 눈이 하나 빼고 다 같음 (ex. 1, 4, 4, 4)
            answer = (10 * dice[3] + dice[0]) ** 2;
            break;
        case 'case3':
            // 주사위 눈이 두 개씩 같음 
            answer = (dice[0] + dice[2]) * Math.abs(dice[0] - dice[2]);
            break;
        case 'case4':
            // 주사위 눈이 두 개만 같고 나머진 다 다름 (ex. 2, 2, 5, 6)
            if (dice[0] === dice[1]) {
                answer = dice[2] * dice[3];
            } else if (dice[1] === dice[2]) {
                answer = dice[0] * dice[3];
            } else {
                answer = dice[0] * dice[1];
            }
            break;
        case 'case5':
            // 주사위 눈이 모두 다름 
            answer = dice[0];
            break;
    }
    return answer;
}
  1. 먼저 주사위 눈 값을 통해서 어떠한 케이스인지 식별하는 과정이 필요하다 생각했다.
    • 배열의 요소를 a, b, c, d로 바인딩하고 조건에 따라 적절한 케이스를 반환한다.
    • 모두 같은 경우는 case1, 세 개가 같은 경우는 case2-1과 case2-2로 나누었다. (앞 쪽 세 개가 같은지, 뒤쪽 세 개가 같은지 구별)
    • 두 개씩 같은 경우는 case3, 두 개만 같은 경우는 case4, 모두 다른 경우는 case5를 반환한다.
  2. 주사위 네 개의 눈 값을 입력받아 resort 함수를 사용하여 특정 케이스를 식별하고, 그 케이스에 맞는 계산을 수행한다.
    • 먼저 주사위 눈 값을 정렬하여 dice 배열에 저장한다.
    • resort 함수에 dice 배열을 넣어 계산한 후 반환값에 따라 각각의 case로 넘어가 연산을 진행한다.
    • case1: 주사위 눈 값이 모두 같을 때, 1111 * dice[0]을 반환합니다.
    • case2-1: 세 개의 주사위 눈 값이 같은 경우, (10 * dice[0] + dice[3]) ** 2를 계산하여 반환한다.
    • case2-2: 세 개의 주사위 눈 값이 같은 경우, (10 * dice[3] + dice[0]) ** 2를 계산하여 반환한다.
    • case3: 두 개씩 같은 경우, (dice[0] + dice[2]) * Math.abs(dice[0] - dice[2])를 계산하여 반환한다.
    • case4: 두 개만 같은 경우, 두 개가 같은 주사위 눈 값을 찾아 나머지 두 개를 곱하여 반환한다.
      case4의 경우 주사위 배열 dice의 요소가 서로 다른 값일 수 있기 때문에 특정 경우에 맞는 조건을 확인해야 한다.
      ➡️ dice[0] === dice[1] 인 경우: 첫 번째와 두 번째 주사위의 값이 같으면, 세 번째와 네 번째 주사위의 곱을 계산한다.
      ➡️ dice[1] === dice[2] 인 경우: 두 번째와 세 번째 주사위의 값이 같으면, 첫 번째와 네 번째 주사위의 곱을 계산한다.
      ➡️ 그 외의 경우: 첫 번째와 두 번째 주사위의 곱을 계산한다.
    • case5: 주사위 눈 값이 모두 다른 경우, 가장 작은 값을 반환합니다.

다른 풀이 1

function count(arr) {
  const counter = new Map();
  for (const num of arr) {
    counter.set(num, (counter.get(num) || 0) + 1);
  }
  const sortedByCnt = [...counter.keys()].sort((a, b) => counter.get(b) - counter.get(a));
  const maxCnt = Math.max(...counter.values());
  return [sortedByCnt, maxCnt];
}

function solution(a, b, c, d) {
  const [arr, maxCnt] = count([a, b, c, d]);
  const [p, q, r, s] = arr;
  if (arr.length === 1) {
    return p * 1111;
  }
  if (arr.length === 2) {
    return maxCnt === 2 ? (p + q) * Math.abs(p - q) : (10 * p + q) ** 2;
  }
  if (arr.length === 3) {
    return q * r;
  }
  return Math.min(p, q, r, s);
}
  1. count 함수
    • counter는 각 숫자의 빈도를 계산하는 Map 객체이다.
    • 입력 배열 arr의 숫자에 대해 counter에 해당 숫자의 빈도를 증가시킨다.
    • sortedByCnt는 빈도에 따라 숫자들을 정렬한 배열이다.
    • maxCnt는 배열에서 가장 많이 등장한 숫자의 빈도이다.
    • count 함수는 [sortedByCnt, maxCnt]를 반환한다.
  2. solution 함수
    • 배열 [a, b, c, d]에 대해 count 함수를 호출하여 arr 값과 maxCnt 값을 얻는다.
    • 배열 길이에 대한 조건을 준다.
      ➡️ arr.length가 1이라면 모든 숫자가 동일하다는 의미이다.
      ➡️ 2라면 두 가지 숫자가 있다는 말이다. maxCnt === 2라면 두 숫자가 각각 두 번 등장한 경우이니 그에 맞는 연산을 해준다. 그렇지 않다면 하나의 숫자가 세 번, 다른 하나가 한 번 등장한 경우이다. 그에 맞는 연산을 해준다. 여기서 p가 더 자주 등장한 숫자, q가 덜 자주 등장한 숫자이다.
      ➡️ 3이라면 세 가지 숫자가 있다는 의미이다. q, r은 두 번째와 세 번째로 빈도가 높은 숫자이다.
      ➡️ 그 외는 모두 숫자가 다르다는 의미이다. 네 개의 숫자 중 가장 작은 숫자를 반환한다.

다른 풀이 2

function solution(a, b, c, d) {
    const dice = [a, b, c, d];
    const counter = new Array(7).fill(0);
    for (let i = 0; i < 4; i++) 
        counter[dice[i]]++;

    let result = 0;

    if (counter.includes(4)) { 
        result = 1111 * counter.indexOf(4);
    } else if (counter.includes(3)) {
        const p = counter.indexOf(3);
        const q = counter.indexOf(1);
        result = (10 * p + q) ** 2;
    } else if (counter.includes(2) && counter.filter(val => val === 2).length === 2) {
        const p = counter.indexOf(2);
        const q = counter.lastIndexOf(2);
        result = (p + q) * Math.abs(p - q);
    } else if (counter.includes(2)) {
        const p = counter.indexOf(2);
        const q = dice.filter(num => num !== p)[0];
        const r = dice.filter(num => num !== p)[1];
        result = q * r;
    } else { 
        result = Math.min(...dice);
    }

    return result;
}
  1. 입력값 배열화 및 카운터 초기화
    • 주사위 숫자 a, b, c, d를 배열 dice에 저장한다.
    • 주사위 숫자의 빈도를 저장할 counter 배열을 초기화한다. 길이 7, 각 인덱스는 주사위 숫자에 해당하고 모든 값을 0으로 설정한다.
  2. 주사위 숫자 카운팅
    • for문을 돌며 dice 배열의 숫자를 couter 배열에서 해당 숫자의 인덱스 위치에 카운트 한다.
  3. 결과 계산
    • 조건별로 결과를 계산한다.

다른 풀이 3

function solution(a, b, c, d) {
    let dice = [a, b, c, d];
    let freq = {};

    // 주사위 값의 빈도 계산
    for (let num of dice) {
        if (freq[num]) {
            freq[num]++;
        } else {
            freq[num] = 1;
        }
    }

    // 빈도에 따라 점수 계산
    let values = Object.keys(freq).map(Number);
    let counts = Object.values(freq);

    if (counts.length === 1) {
        // 네 주사위 모두 같은 경우
        return 1111 * values[0];
    } else if (counts.length === 2) {
        if (counts.includes(3)) {
            // 세 주사위가 같은 경우
            let p = values[counts.indexOf(3)];
            let q = values[counts.indexOf(1)];
            return (10 * p + q) ** 2;
        } else {
            // 두 주사위씩 같은 경우
            let p = values[0];
            let q = values[1];
            return (p + q) * Math.abs(p - q);
        }
    } else if (counts.length === 3) {
        // 두 주사위가 같은 경우
        let p = values[counts.indexOf(2)];
        let remaining = values.filter(v => v !== p);
        return remaining[0] * remaining[1];
    } else {
        // 네 주사위 값이 모두 다른 경우
        return Math.min(...values);
    }
}
  1. 주사위 값 배열과 빈도 객체를 초기화한다.

  2. 주사위 값 배열을 순회하며 각 값의 빈도를 freq 객체에 저장한다.

  3. 빈도에 따라 점수를 계산한다. 주사위 값의 빈도에 따라 다섯가지 경우로 나누어 점수를 계산한다.


소신발언...

노가다 코드가 가독성이 가장 좋았다.

profile
영차영차 😎

0개의 댓글