[알고리즘] 2018 카카오 1차 _ 다트게임

DongGyu Jung·2022년 1월 16일
0
post-thumbnail

※ 본 사진과 해당 게시글 내용의 문제 모두 프로그래머스[Programmers]사이트에 발췌해왔습니다.

💬 들어가기 앞서..

프로그래머스를 사정이 있어 잠깐 쉬고
최근에는
알고리즘 스터디도 진행하고 있지만
문제를 백준에서 풀다보니
이 문제는 정말 오랜만에 프로그래머스를 방문해서 맞닥뜨린 문제였는데

아뿔사...
그래도 Lv.1 문제는 이제 풀기 쉽겠지 라는 생각하던 찰나
나의 근거없는 자신감을 다시 밟아 다져준(?) 문제인 것 같다..
(무슨 1시간을 넘게 머리 싸매서 풀어... )

아직 멀었다... 아직 내가 풀었던 건 아무것도 아니였다...
아직 부족하다는 현실을 깨닫고 앞으로 더 많이 풀어야 겠다는 다짐을 하며 시작해보겠다..


❓ 문제

다트 게임은 다트판에 다트를 세 차례 던져 그 점수의 합계로 실력을 겨루는 게임이다.
다트 게임의 점수 계산 로직은 아래와 같다.

다트 게임은 총 3번의 기회로 구성된다.
각 기회마다 얻을 수 있는 점수는 
0점에서 10점까지이다.

점수와 함께 Single(S), Double(D), Triple(T) 영역이 존재하고 
각 영역 당첨 시 
점수에서 1제곱, 2제곱, 3제곱 (점수1 , 점수2 , 점수3 )으로 계산된다.

옵션으로 스타상(*) , 아차상(#)이 존재하며 
스타상(*) 당첨 시 
해당 점수와 바로 전에 얻은 점수를 각 2배로 만든다. 
아차상(#) 당첨 시 
해당 점수는 마이너스된다.

스타상(*)은 첫 번째 기회에서도 나올 수 있다. 
이 경우 
첫 번째 스타상(*)의 점수만 2배가 된다. (예제 4번 참고)

스타상(*)의 효과는 다른 스타상(*)의 효과와 중첩될 수 있다. 
이 경우 
중첩된 스타상(*) 점수는 4배가 된다. (예제 4번 참고)

스타상(*)의 효과는 아차상(#)의 효과와 중첩될 수 있다. 
이 경우 
중첩된 아차상(#)의 점수는 -2배가 된다. (예제 5번 참고)

Single(S), Double(D), Triple(T)은 
점수마다 하나씩 존재한다.

스타상(*), 아차상(#)은 
점수마다 둘 중 하나만 존재할 수 있으며, 존재하지 않을 수도 있다.

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	1S*2T*3S	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

❗ 풀이

My Code

def solution(dartResult):
    answer = [] # 더할 각 단계 계산 점수값을 담을 리스트
    num = '' # 10이라는 두자릿수 값의 경우까지 가능한 " 문자열로의 누적합 " 활용 _ 초기화 또한 용이한 장점 
    for i in dartResult :
        if i.isdigit() : # 숫자일 경우
            num += i # 점수를 입력
        elif i in ['S', 'D', 'T'] : # S, D, T의 경우
            if i == 'S' :
                answer.append(int(num)) # 각 단계의 결과 점수
                num = '' # 초기화
            elif i == 'D' :
                answer.append(int(num)**2) # 각 단계의 결과 점수
                num = '' # 초기화
            else :
                answer.append(int(num)**3) # 각 단계의 결과 점수
                num = '' # 초기화
        elif i in ["*", "#"] : # 옵션의 경우
            if i == "*" :
                if len(answer) == 1 : 
                    answer[-1] = answer[-1]*2 # 수정
                    # answer에서 가장 최근에 들어갔던 값에 대해 수행되게끔
                else : # 스타상
                # 해당 점수와 바로 전에 얻은 점수를 각 2배
                    answer[-1] = answer[-1]*2
                    answer[-2] = answer[-2]*2  
            else : # 아차상
                answer[-1] = answer[-1]*-1    
    return sum(answer)

사실 들어가기 앞서 말했듯이
해당 문제를 푸는데 시간이 적지않게 소요되었는데
아무래도 다른 분들이 푼 방법들도 살펴보았다.

숫자와 문자가 번갈아 나오며
나올 때마다 초기화 되어야 하는 경우가 있어
이 두 가지를를 어떻게 유동적으로 붙였다 삭제를 할 수 있을까 골치 아팠었다.
(필자는 정규표현식 & Dict 자료구조 활용 이나 타입 상관없이 리스트를 활용해볼까 를 고민해보았지만 아직 성공하지 못해 더 시도해봐야 하긴 하다..)

그러던 중
삭제에도 용이할 뿐더러
누적합도 가능한 방법이 있었다.
바로 문자열 이였다.


❣ 다른 풀이

(1)

import re
def solution(dartResult):
	# { Key : Value } 딕셔너리 활용
    bonus = {'S' : 1, 'D' : 2, 'T' : 3} # SDT의 경우에 대해 할당되는 계산 값들을 짝지어줌.
    option = {'' : 1, '*' : 2, '#' : -1} # 아무 상도 없으면 값 그대로 유지 : 1로 연산에 활용
    
    # " (digit)([S나 D나 T가 나온 경우])([스타상이나 아차상의 경우 : 있어도그만 없어도 그만]) " <- 이 구성를 단위로
    # 전체 중에 위 구조의 덩어리들을 1차적으로 분리하고
    # 중괄호를 기준으로 각자 2차적으로 분리한다.
    # 스타상(*)이나 아차상(#)이 없더라도 ()로 분리되었기때문에 '' 비어있는 값도 하나의 값으로 분리됨.
    p = re.compile('(\d+)([SDT])([*#]?)') # 정규표현식을 통해 S, D, T가 쓰인 경우로 나누어줌
    
    dart = p.findall(dartResult) # 위 구조에 해당하는 부분을 찾아냄 (분리되는 과정)
    
    for i in range(len(dart)): # 찾아낸 것들을 하나씩 계산
        if dart[i][2] == '*' and i > 0: # 첫번째 덩어리의 끝 부분
            dart[i-1] *= 2
        # 처음에 설정한 dict에 value들을 가져와서 연산하기
        dart[i] = int(dart[i][0]) ** bonus[dart[i][1]] * option[dart[i][2]]

    answer = sum(dart)
    return answer

필자가 도전하던 정규 표현식Dict 형식의 " Key-Value " 성질을 사용한 경우이다.
아직 정규표현식을 정확하게 활용하기 위해선
더 공부가 필요한 것 같다.

조만간 정규표현식도 한 번 알아봐야겠다..


0개의 댓글