will come true

[프로그래머스 / Level1] 다트 게임 (Java) 본문

Algorithm

[프로그래머스 / Level1] 다트 게임 (Java)

haehyun 2021. 10. 31. 16:08
728x90

문제

https://programmers.co.kr/learn/courses/30/lessons/17682?language=java 

 

코딩테스트 연습 - [1차] 다트 게임

 

programmers.co.kr

#문자열 처리(String Manipulation) #토큰화(Tokenizing) #의미 분석(Semantic Analysis)

🎯 다트게임 규칙

  • 다트판에 다트를 세 차례 던져 그 점수의 합계로 실력을 겨룬다.
  • 총 3번의 기회 제공
  • 점수 : 0점~10점
  • 보너스 : Single(S), Double(D), Triple(T) 영역에 따라 점수^제곱(1, 2, 3)
            점수마다 하나씩 존재
  • 옵션 : 스타상(*) - 해당 점수와 바로 전에 얻은 점수를 각 2배 (1번째에 나오면 해당 점수만 2배 / 중첩 = 4배),
            아차상(#) - 해당 점수 마이너스 (스타상+아차상 중첩 = -2배)
            점수마다 둘 중 하나만 존재, 또는 존재하지 않음.
  • 0~10의정수, 문자 S, T, D, *, # 로 구성된 문자열 3세트에서 총점수 산출

 

기존 코드 (성공)

class Solution {
    public int solution(String dartResult) {
        int totalScore = 0;
        int[] scores = new int[3];
        int turn = 0;
        
        for(int i = 0; i < dartResult.length(); i++){
            char ch = dartResult.charAt(i);
            if(Character.isDigit(ch)){
                if(scores[turn] != 0) { 
                    scores[turn] = 10; 
                }else{
                    scores[turn] = ch - '0';
                }
            }else if(Character.isAlphabetic(ch)){
                switch(ch){
                    case 'D':
                        scores[turn] = (int)(Math.pow(scores[turn], 2));
                        break;
                    case 'T':
                        scores[turn] = (int)(Math.pow(scores[turn], 3));
                        break;
                }
                if(i == dartResult.length() -1){
                    break;
                } else if(Character.isDigit(dartResult.charAt(i+1))){
                    turn++;
                }
            }else{
                switch(ch){
                    case '*':
                        scores[turn] *= 2;
                        if(turn != 0){ scores[turn-1] *= 2; }
                        break;
                    case '#':
                        scores[turn] *= -1;
                        break;
                }
                turn++;
            }
        }
        
        for(int score : scores){
            totalScore += score;
        }
        
        return totalScore;
    }
}

 

[점수]
i) 점수가 1자리일 경우(0~9) scores[turn]의 값은 한번 저장된다.
ii) 점수가 2자리일 경우(10) scores[turn]에 값이 저장된 뒤 다음 반복에서도 if(Character.isDigit(ch))에 걸려서 값이 두번 저장되게 된다. (.charAt(int index)로 접근 시 점수가 두자리면 1, 0을 따로 가져오기 때문) 이때 값이 0으로 덮어씌워지는 걸 방지하기 위해 해당 요소에 이미 값이 저장되어 있을 경우 10을 저장한다.

[보너스]
점수|보너스는 필수이나, 옵션은 필수가 아니다. 그렇기 때문에 한 기회의 문자열이
i) S, T로 끝나는 경우, ii) *, #로 끝나는 경우 두 가지로 나뉜다. 각각의 경우에서 다음 기회로 넘어가는 turn++ 처리

[옵션]
스타상일 경우, 기본적으로 현재 점수를 2배로 하고, 지금이 첫번째 시도가 아닐 경우(turn != 0)에만 이전것까지 2배로

 

개선 코드 (성공)

class Solution {
    public int solution(String dartResult) {
        int totalScore = 0;
        int[] scores = new int[3];              //3번의 기회 각 점수를 저장
        int turn = 0;
        
        for(int i = 0; i < dartResult.length(); i++){
            char ch = dartResult.charAt(i);
            if(Character.isDigit(ch)){
                if(scores[turn] != 0) {         //해당 기회에 점수가 두번 저장되는 경우는 10뿐.
                    scores[turn] = 10; 
                }else{
                    scores[turn] = ch - '0';
                }
            }else{
                switch(ch){
                    case 'D':
                        scores[turn] = (int)(Math.pow(scores[turn], 2));
                        break;
                    case 'T':
                        scores[turn] = (int)(Math.pow(scores[turn], 3));
                        break;
                    case '*':
                        scores[turn] *= 2;
                        if(turn != 0) { scores[turn-1] *= 2; }  //1번째 기회에서는 현재 점수만 2배
                        break;
                    case '#':
                         scores[turn] *= -1;
                        break;
                }
                if(i == dartResult.length() -1){                //마지막 문자일 경우 .charAt(i+1) 하면 index넘어감
                    break;
                } else if(Character.isDigit(dartResult.charAt(i+1))){   //다음 문자가 숫자면 이번 기회는 끝인 것
                    turn++;
                }
            }
        }
        
        for(int score : scores){
            totalScore += score;
        }
        
        return totalScore;
    }
}

기존 코드에서는 1) 숫자일 경우, 2) 알파벳일 경우, 3)숫자도 알파벳도 아닌 경우 세 가지로 분류했었는데, 한 기회의 끝 문자가 보너스(S, T)이거나 옵션(*, #)일 수 있기 때문에 (2), (3) 부분에 모두 다음 기회로 넘어가는 turn++ 코드가 들어갔는데, 두 부분의 처리가 비슷하기 때문에 하나의 블록에서 처리하기로 함. = switch문에서 보너스/옵션 구분

i) 문자열의 마지막 요소일 경우 => 종료
ii) 다음 기회가 남아있을 경우 => 다음 턴으로

 

학습 내용

//뒤늦게 카카오 공식 문제 해설을 발견했고, 새로운 방법이 있다는 것을 알게되어 학습중

토큰화(Tokenizing)

StringTokenizer

의미 분석(Semantic Analysis)

정규식

 


 

728x90
Comments