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

ziwon.k·2021년 5월 5일
0
post-thumbnail

[프로그래머스/C++] Level1.다트게임

1.문제



2.접근/체크포인트

  1. 총 3번 다트를 던지고, 보너스(S,D,T)나 옵션(*,#)에 따라서 이전 점수를 다시 조작해야 하기 때문에 각 점수를 따로 저장해야 함.
  2. 문자열을 하나씩 읽어서 점수, 보너스, 옵션을 구분하고 각 케이스에 맞게 점수를 반영.
  3. 점수는 0-10점으로, 문자열로 10이 주어지기 때문에, 점수가 1인지 10인지 구분해야 함.

3. 해결 방법

  1. 먼저 점수가 몇 점인지 확인 후 스택에 저장.
    1-1. 이때 점수가 1로 시작하는 경우와 그렇지 않은 경우로 나눠서 처리.
    1-2. 1로 시작하는 경우는 1점이거나 10점인 경우가 있고, 나머지는 0, 2-9점인 경우.
  2. 보너스에 따라 스택에 저장된 점수를 다시 꺼내서 계산 후 저장.
  3. 옵션에 따라 점수 다시 계산 후 스택에 저장.
    3-1. 옵션이 * 인 경우 : 첫 번째 기회인지, 아니면 두 번째, 세 번째 기회인지에 따라 다르게 처리해야 함. (두 번째, 세 번째 기회일 경우, 현재 점수와 바로 이전의 점수 모두 2배로 계산.)
    3-2. 옵션이 # 인 경우 : 현재 기회에서 얻은 점수만 -1 곱해서 스택에 저장.
  4. 1-3번이 각 기회마다 일어남.

4.전체 코드

#include<iostream>
#include <string>
#include <vector>
#include<cmath> //pow()
#include <stack>
using namespace std;

int answer = 0;

int solution(string dartResult) {

    int score1, score2 =0; 
    stack<int> sc;


    for(int i=0; i<dartResult.size(); i++){

        //1.다트의 점수가 1인지 10인지 확인하기
        if(dartResult[i] == '1'){

            sc.push(dartResult[i] - '0');  //1점인 경우
            
            if(dartResult[i+1] == '0'){  //다음 인덱스가 0이면 점수는 10

            sc.pop();      //넣어둔 1점 빼기
            sc.push(10);  //스택에 10점 넣기
            i++;          //점수가 10일경우 i를 증가 시켜줘야 다음 인덱스 (D T S)로 이동가능
            }

            //2.점수 값 계산하기
            if(dartResult[i+1] == 'D'){  //점수가 D일 경우 이전 점수의 2제곱
            score1 = sc.top();
            sc.pop();
            sc.push(pow(score1, 2));  //2제곱 한 값 스택에 넣기
            }else 
            if(dartResult[i+1] == 'T'){  //점수가 T일 경우 이전 점수의 3제곱
            score1 = sc.top();
            sc.pop();
            sc.push(pow(score1, 3));  //3제곱 한 값 스택에 넣기
            }

        }else{

            //0~9점인 경우
            sc.push(dartResult[i] - '0');  


            if(dartResult[i+1] == 'D'){  //점수가 D일 경우 이전 점수의 2제곱
            score1 = sc.top();
            sc.pop();
            sc.push(pow(score1, 2));  //2제곱 한 값 스택에 넣기
            }else if(dartResult[i+1] == 'T'){  //점수가 T일 경우 이전 점수의 3제곱
            score1 = sc.top();
            sc.pop();
            sc.push(pow(score1, 3));  //3제곱 한 값 스택에 넣기
            }

        }//여기까지는 옵션 빼고 점수 계산 된 상태

        i++;  //다음 인덱스(S,D,T)로 이동

        //3.옵션이 있다면 처리해야 함.
        if(dartResult[i+1] == '*' || dartResult[i+1] == '#'){

            //옵션이 스타상(*)이라면
            if(dartResult[i+1]=='*'){

                //스택에 점수가 하나만 있을때
                if(sc.size()==1){  
                    score1 = sc.top();
                    sc.pop();
                    sc.push(score1*2);
                }else{
                    //스택에 점수가 하나 이상인 경우는 현재 점수와 이전 점수 계산해야함
                    score1 = sc.top(); //현재 점수
                    sc.pop();
                    score1 *=2;

                    score2 = sc.top(); //바로 전 점수
                    score2 *=2;
                    sc.pop();

                    sc.push(score2);
                    sc.push(score1);
                }

            }else{
                //옵션이 #(아차상)인 경우 현재 점수 마이너스 처리
                score1 = sc.top();
                sc.pop();
                sc.push(-1*score1);
            }

            i++;  //다음 인덱스(옵션)으로 인덱스 이동
        }

    }

    while(!sc.empty()){
        answer += sc.top();
        sc.pop();
    }


    return answer;
}

5.참고사항

👉 제곱 계산용 함수
1. #include <cmath> 헤더 파일 포함 시키기
2. pow(숫자, 지수);
ex) 10의 세제곱 계산 : pow(10, 3);

👉C++에서의 문자열
C++에는 문자열을 나타내는 두 가지 방법이 있음.
1. char형 배열 : 마지막에 자동으로 null

  • 문자열의 크기에 항상 신경써야 함. 배열의 크기가 충분하지 않을 경우 error.
  1. string 클래스 사용.
  • 문자열 저장과 처리에 필요한 변수와 함수들의 정의되어 있음.
  • 문자열의 크기를 신경쓰지 않고 사용 가능.

6.다른 방법으로 풀어보기

#include <string>
#include <sstream>
#include <cmath>

using namespace std;

int solution(string dartResult) {
    stringstream ss(dartResult);

    int sum[3] = { 0, 0, 0 };
    int options[3] = { 1, 1, 1 };
    for (int i = 0; i < 3; i++) {
        int score;
        char bonus;
        char option;

        ss >> score;

        bonus = ss.get();
        option = ss.get();

        if (option != '*' && option != '#') {
            ss.unget();
        }

        switch (bonus) {
        case 'S':
            sum[i] += pow(score, 1);
            break;
        case 'D':
            sum[i] += pow(score, 2);
            break;
        case 'T':
            sum[i] += pow(score, 3);
            break;
        default:
            break;
        }

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

    return sum[0] * options[0] + sum[1] * options[1] + sum[2] * options[2];
}

코드 출처


7.후기

하나의 문자열로 주어진 3개의 케이스를 각각 어떻게 분리할지 생각하는 것이 오래 걸렸다.
특히 숫자를 기준으로 나누려 했더니 0-9점까지가 아니고 10점까지라 10점인 걸 어떻게 확인할지 고민함. 다른 풀이를 보면 보너스 (S,D,T)를 기준으로 앞, 뒤로 나눠서 계산하기도 하던데 그 방법으로도 풀어볼 예정. 문자열 처리는 계산이나 구분, 분리에서 까다로운 경우가 많아서 다양한 케이스, 함수를 익히는 것이 중요할 듯!

profile
Frontend-Devloper

0개의 댓글