프로그래머스 > [1차] 다트 게임
카카오톡 게임별 다트 게임의 점수 계산 로직을 구현하는 방법을 자세히 알아보고, JavaScript와 Java로 작성된 솔루션을 살펴보세요.
카카오톡에 뜬 네 번째 별! 심심할 땐? 카카오톡 게임별~
카카오톡 게임별의 하반기 신규 서비스로 다트 게임을 출시하기로 했다. 다트 게임은 다트판에 다트를 세 차례 던져 그 점수의 합계로 실력을 겨루는 게임으로, 모두가 간단히 즐길 수 있다. 갓 입사한 무지는 코딩 실력을 인정받아 게임의 핵심 부분인 점수 계산 로직을 맡게 되었다. 다트 게임의 점수 계산 로직은 아래와 같다.
1. 다트 게임은 총 3번의 기회로 구성된다.
2. 각 기회마다 얻을 수 있는 점수는 0점에서 10점까지이다.
3. 점수와 함께 Single(S), Double(D), Triple(T) 영역이 존재하고 각 영역 당첨 시 점수에서 1제곱, 2제곱, 3제곱 (점수1 , 점수2 , 점수3 )으로 계산된다.
4. 옵션으로 스타상(*) , 아차상(#)이 존재하며 스타상(*) 당첨 시 해당 점수와 바로 전에 얻은 점수를 각 2배로 만든다. 아차상(#) 당첨 시 해당 점수는 마이너스된다.
5. 스타상(*)은 첫 번째 기회에서도 나올 수 있다. 이 경우 첫 번째 스타상(*)의 점수만 2배가 된다. (예제 4번 참고)
6. 스타상(*)의 효과는 다른 스타상(*)의 효과와 중첩될 수 있다. 이 경우 중첩된 스타상(*) 점수는 4배가 된다. (예제 4번 참고)
7. 스타상(*)의 효과는 아차상(#)의 효과와 중첩될 수 있다. 이 경우 중첩된 아차상(#)의 점수는 -2배가 된다. (예제 5번 참고)
8. Single(S), Double(D), Triple(T)은 점수마다 하나씩 존재한다.
9. 스타상(*), 아차상(#)은 점수마다 둘 중 하나만 존재할 수 있으며, 존재하지 않을 수도 있다.
0~10의 정수와 문자 S, D, T, *, #로 구성된 문자열이 입력될 시 총점수를 반환하는 함수를 작성하라.
입력 형식
"점수|보너스|[옵션]"으로 이루어진 문자열 3세트. 예) 1S2D*3T
점수는 0에서 10 사이의 정수이다. 보너스는 S, D, T 중 하나이다. 옵선은 *이나 # 중 하나이며, 없을 수도 있다. 출력 형식 3번의 기회에서 얻은 점수 합계에 해당하는 정수값을 출력한다. 예) 37
입출력 예제
예제 dartResult answer 설명 1 1S2D*3T 37 11 * 2 + 22 * 2 + 33 2 1D2S#10S 9 12 + 21 * (-1) + 101 3 1D2S0T 3 12 + 21 + 03 4 1S2T3S 23 11 * 2 * 2 + 23 * 2 + 31 5 1D#2S*3S 5 12 * (-1) * 2 + 21 * 2 + 31 6 1T2D3D# -4 13 + 22 + 32 * (-1) 7 1D2S3T* 59 12 + 21 * 2 + 33 * 2
```javascript function solution(dartResult) { return flow( dartResult, parseDartResult, getScore, ) } function flow(initialValue, …functions) { return functions.reduce((ac, cv) => cv(ac), initialValue); } /** String 점수를 하나씩 배열 데이터로 쪼개준다. ex) "1D2S3T" -> [ { score: 1, bonus: 'D', option: undefined }, { score: 2, bonus: 'S', option: undefined }, { score: 3, bonus: 'T', option: '' }, ] */ function parseDartResult(dartResult) { let result = []; let score = ""; let bonus = undefined; let option = undefined; let scoreFlag = false; let bonusFlag = false; let optionFlag = false;
for(let i = 0 ; i < dartResult.length ; i++) {
    const currentString = dartResult[i];
    if(isNumberString(currentString)) {
        score = score + currentString;
        scoreFlag = true;
    }
    if(isBonus(currentString)) {
        bonus = currentString;
        bonusFlag = true;
    }
    if(isOption(currentString)) {
        option = currentString;
        optionFlag = true;
    }
    if(i === dartResult.length-1) {
        result.push({
            score: parseInt(score),
            bonus,
            option,
        });
        return result;
    }
    if(optionFlag === true) {
        result.push({
            score: parseInt(score),
            bonus,
            option,
        });
        _refresh();
    }
    if(bonusFlag === true && isNumberString(dartResult[i+1])) {
        result.push({
            score: parseInt(score),
            bonus,
            option,
        });
        _refresh();
    }
}
return result;
function _refresh() {
    score = "";
    bonus = undefined;
    option = undefined;
    scoreFlag = false;
    bonusFlag = false;
    optionFlag = false;
}
} /** 각각의 라운드들에 대해 점수를 계산함 */ function getScore(scoreArray) { for(let i = 0 ; i < scoreArray.length ; i++) { const current = scoreArray[i]; let score = current.score;
    if(current.bonus === "S") {
        current.totalScore = score;
    }
    if(current.bonus === "D") {
        current.totalScore = score * score;
    }
    if(current.bonus === "T") {
        current.totalScore = score * score * score;
    }
    if(current.option === "*") {
        current.totalScore = current.totalScore * 2;
        if(i>0) {
            scoreArray[i-1].totalScore = scoreArray[i-1].totalScore * 2;
        }
    }
    if(current.option === "#") {
        current.totalScore = -current.totalScore;
    }
}
return scoreArray.reduce((ac, cv) => cv.totalScore + ac, 0);
} // 옵션인지 체크해 줌 function isOption(str) { if(str.length !== 1) { throw new Error("invalid Option"); } return ["*", "#"].includes(str); } // 보너스인지 체크해 줌 function isBonus(str) { if(str.length !== 1) { throw new Error("invalid Bonus"); } return ["S", "D", "T"].includes(str); } // 숫자 형태의 문자인지 체크해 줌 (점수 계산 목적) function isNumberString(str) { const stringArray = Array(10).fill(undefined).map((_, idx) => idx.toString()); return Array.from(str).every(s => stringArray.includes(s)); }
###### [Solution in JAVA] 💡
java public static int solution(String dartResult) { int answer = 0; String last = "";
    int score = 0,preScore = 0;
    char[] charArray = dartResult.toCharArray();
    Stack<Integer> stack = new Stack<>();
    for (int i = 0 ; i<charArray.length ; i++) {
        char current = charArray[i];
        /* c가 보너스일 때 */
        if (Character.isLetter(current)) {
            if (current == 'S') score = (int) Math.pow(Integer.parseInt(last), 1);
            if (current == 'D') score = (int) Math.pow(Integer.parseInt(last), 2);
            if (current == 'T') score = (int) Math.pow(Integer.parseInt(last), 3);
            // 점수 초기화
            last = "";
            stack.push(score);
        /* c가 옵션일 때 (옵션 로직) */
        } else if (current == '*' || current == '#'){
            if (current == '*') { /* 스타상 */
                if (stack.size() >= 2) {
                    // 마지막 점수
                    score = stack.pop() * 2;
                    // 그 전 점수
                    preScore = stack.pop() * 2;
                    stack.push(preScore);
                    stack.push(score);
                } else { //하나 뿐일 때
                    score = stack.pop() * 2;
                    stack.push(score);
                }
            } else { /* 아차상 */
                score = stack.pop() * -1;
                stack.push(score);
            }
        /* c가 점수일 때, 두자리 정수일 때 대응 */
        } else {
            score = 0;
            last += String.valueOf(current);
        }
    }
    for (int a : stack) {
        answer += a;
    }
    return answer;
}
```
이것도 읽어보세요