[프로그래머스] [1차] 다트 게임

ppyororong_0_0·2022년 1월 19일
0

프로그래머스

목록 보기
18/19
post-custom-banner

[프로그래머스 - 1단계][1차] 다트 게임 문제

https://programmers.co.kr/learn/courses/30/lessons/17682

📝 문제 설명

다트 게임의 기회 : 총 3회
점수|보너스|[옵션]으로 이루어진 문자열 3세트가 주어진다.
0~10의 정수와 문자 S, D, T, *, #로 구성된 문자열이 입력될 시 총점수를 반환하는 함수를 작성하라.

  • 각 기회마다 얻을 수 있는 점수: 0점 ~ 10점

  • 보너스
    • S : 점수의 1제곱
    • D : 점수의 2제곱
    • T : 점수의 3제곱

  • 옵션
    • 옵션은 존재할 수도, 존재하지 않을 수도 있다.
    • 스타상(*) : 해당 점수와 바로 전에 얻은 점수를 각각 2배로 만든다.
      • 첫 번째 기회에서 스타상이 나올 경우 첫 번째 점수만 2배가 된다.
      • 다른 스타상 효과와 중첩 가능(4배)
    • 아차상(#) : 해당 점수는 마이너스된다.
      • 스타상과 아차상이 중첩돌 경우 중첩된 아차상의 점수는 -2배가 된다.

💡 풀이

1. 점수 vs 보너스/옵션으로 문자열 분리하기

  • numArr배열 : 숫자들만 모아둔 배열
  • strArr배열 : 보너스와 옵션을 모아둔 배열
  • split( ) 함수를 사용하여 문자열을 분리하여 각각 배열로 만들어주었다.
  • split( ) 함수의 파라미터로 정규표현식을 사용하였다.
    • separator(구분자) : 끊어주는 부분
    • /[^0-9]/ : 구분자로 '0에서 9까지의 숫자가 아닌 것'이라는 의미의 표현식을 주었다.
      숫자가 아닌 부분이 끊는 부분이기 때문에 숫자가 아닌 부분(구분자)은 사라지고 숫자만 남은 배열이 반환된다.
      ex) 1S2D*3T -> 1 | 2 | "" | 3 | ""
    • /[0-9]/ : 구분자로 '0에서 9까지의 숫자'라는 표현식을 주었다.
      숫자가 있는 부분에서 끊기 때문에 숫자가 아닌 문자만 남는다.
      ex) 1S2D*3T -> "" | S | D* | T
  • filter( ) 함수를 사용하여 split( ) 함수를 사용하고 반환된 배열에서 "" 값을 제거해주었다.

2. 보너스/옵션 적용하여 점수 계산하기

  • strArr에 있는 보너스와 옵션을 적용하기 위해 반복문을 사용하였다.
  • numArr의 길이와 strArr의 길이는 3이다.
  • 바깥 for문의 i 변수 : 따라서 strArr에 있는 보너스와 옵션은 차례대로 numArr 배열의 같은 인덱스에 있는 점수에 적용한다.
  • 내부 for문의 j 변수 : 옵션이 있는 경우 strArr[i]의 길이가 2가 되기 때문에 이중 for문을 통해 보너스와 옵션을 분리하여 각각 점수에 적용될 수 있도록 하였다.

3. 총 점수 return

  • 총 점수 : 보너스와 옵션이 적용된 numArr의 배열 안에 있는 점수들을 reduce( ) 함수를 통해 더하였다.
  • 더하는 과정에 있어 점수가 문자열인 경우가 있었다.
  • Number(cur) : 따라서 숫자 더하기가 제대로 적용되지 않는 경우가 있어서, numArr 배열 안에 있는 값들을 Number( ) 함수를 통해 숫자로 변환해주었다.

🖥️ 코드

(1) 처음 짠 코드

function solution(dartResult) {
    let num = [];
    for (let x of dartResult) {
        if (!isNaN(x)) num.push(Number(x));
        else if (x === 'D') {
           num[num.length - 1] = Math.pow(num[num.length - 1], 2);
        } else if (x === 'T') {
            num[num.length - 1] = Math.pow(num[num.length - 1], 3);
        } else if (x === '*') {
            if (num.length !== 1) num[num.length - 2] *= 2; 
            num[num.length - 1] *= 2;
        } else if (x === '#') {
            num[num.length - 1] *= (-1);
        }
        console.log(num)
    }
    return num.reduce((acc, cur) => acc + cur, 0);
}

이렇게 풀면 숫자로 10이 들어올 경우를 해결해주지 못함.


(2) 다시 짠 코드

function solution(dartResult) {
    let numArr = dartResult.split(/[^0-9]/).filter((v) => v !== "");
    let strArr = dartResult.split(/[0-9]/).filter((v) => v !== "");
    
    for (let i = 0; i < strArr.length; i++) {
        for (let j = 0; j < strArr[i].length; j++) {
          
            if (strArr[i][j] === 'D') {
               numArr[i] = Math.pow(numArr[i], 2);
            } else if (strArr[i][j] === 'T') {
                numArr[i] = Math.pow(numArr[i], 3);
            } else if (strArr[i][j] === '*') {
                if (i !== 0) numArr[i - 1] *= 2; 
                numArr[i] *= 2;
            } else if (strArr[i][j] === '#') {
                numArr[i] *= (-1);
            }
          
        }
    }
    return numArr.reduce((acc, cur) => acc + Number(cur), 0);
}

문제를 풀다보니 느낀 점...
정규 표현식과 문자열 나누는 부분에 대해 취약하다는 것을 깨달았다.
매번 저 split함수는 쓸 때마다 사용법을 찾아보게 된다...😂


❗ 다른 사람 풀이

function solution(dartResult) {
  const reg = /[\d]+[SDT][*#]*/g;
  const input = dartResult.match(reg);
  const result = [];

  for (let i = 0; i < input.length; i++) {
    let number = input[i].match(/[\d]+/g)[0];
    const bonus = input[i].match(/[SDT]/g)[0];
    const option = input[i].match(/[*#]/g);

    switch (bonus) {
      case 'S':
        number = Number(number);
        break;
      case 'D':
        number = Math.pow(number, 2);
        break;
      case 'T':
        number = Math.pow(number, 3);
        break;
    }

    result[i] = number;

    if (option) {
      switch (option[0]) {
        case '*':
          result[i - 1] *= 2;
          result[i] *= 2;
          break;
        case '#':
          result[i] *= -1;
          break;
      }
    }
  }

  return result.reduce((acc, cur) => {
    return acc + cur;
  });
}
profile
안녕하세요!
post-custom-banner

0개의 댓글