Python/프로그래머스

[프로그래머스 lv.1]다트 게임 (건너뛴 문제 다시풀기)

묘걍 2023. 9. 15. 21:08

문제

카카오톡에 뜬 네 번째 별! 심심할 땐? 카카오톡 게임별~

카카오톡 게임별의 하반기 신규 서비스로 다트 게임을 출시하기로 했다. 다트 게임은 다트판에 다트를 세 차례 던져 그 점수의 합계로 실력을 겨루는 게임으로, 모두가 간단히 즐길 수 있다.
갓 입사한 무지는 코딩 실력을 인정받아 게임의 핵심 부분인 점수 계산 로직을 맡게 되었다. 다트 게임의 점수 계산 로직은 아래와 같다.

  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, *, #로 구성된 문자열이 입력될 시 총점수를 반환하는 함수를 작성하라.

 

예전 풀이

생각

for문을 돌면서 (인덱스로 접근)

만약 dartResult[i]가 *이면dartResult[i] = *2, dartResult[i-2] += *2

일단 설명은 dartResult[ ] 생략

만약 i가 #이면 i = *(-1)

만약 i가 S면 i = **1

만약 i가 D면 i = **2

만약 i가 T면 i = **3

 

이 for문을 통해 새로운 수식을 만들어내 그 수식을 eval()함수를 통해 answer변수에 할당하고

answer을 return하면 원하는 결과를 얻을 수 있을 것이다.

 

코드

def solution(dartResult):
    answer = 0
    for i in range(len(dartResult)):
        if dartResult[i] == '*':
            dartResult[i] = *2
            dartResult[i-2] += *2
        elif dartResult[i] == '#':
            dartResult[i] = *(-1)
        elif dartResult[i] == 'S':
            dartResult[i] = **1
        elif dartResult[i] == 'D':
            dartResult[i] = **2
        elif dartResult[i] == 'T':
            dartResult[i] = **3
    answer = eval(dartResult)
        
    return answer

 

다시 생각해보기

생각

예전에는 수식을 만들고 그 결과를 내려고 했던 것 같다. 그래서 *의 경우 i보다 두 칸 앞에 *2를 '넣어주'려고 했다.

그런데 당연히 이 부분에서 에러가 나고 그걸 문자열로 바꿔도 안되는 일이다.

그냥 그 앞과 앞앞에 *2를 해주는 식으로 바꿔봐야겠다

그리고 각각의 결과를 더해주는 코드도 없다.

 

숫자인지 아닌지를 판별해서 만약 숫자라면

뒤에 있는 문자에 해당하는 값을 곱해준다(?) 그리고 answer에 더해준다.

그런데 *의 경우 앞 숫자에도 2배를 해줘야하는데..

리스트에 append하는 방식으로 바꾸면 되려나

 

코드

def dart(a):
    if a == 'S':
        return 1
    elif a == 'D':
        return 2
    elif a == 'T':
        return 3

def solution(dartResult):
    answer = 0
    points = []
    for i in range(len(dartResult)):
        if dartResult[i].isdigit() == True:
            point = int(dartResult[i]) ** dart(dartResult[i+1])
            points.append(point)
        elif dartResult[i] == '*':
            if len(points) >= 2:
                points[-1] *= 2
                points[-2] *= 2
            else:
                points[-1] *= 2
        elif dartResult[i] == '#':
            points[-1] *= (-1)
        else:
            continue
    answer = sum(points)
    return answer

- 10점을 다룰 수 없는 코드이다. TypeError: unsupported operand type(s) for ** or pow(): 'int' and 'NoneType'라는 에러가 나는데 그 이유도 어느정도 이것과 관련이 있다고 한다...

다른 사람 풀이

def solution(dartResult):
    n = ''
    score = []
    for i in dartResult:
        if i.isnumeric():
            n += i
        elif i == 'S':
            n = int(n)**1
            score.append(n)
            n = ''
        elif i == 'D':
            n = int(n)**2
            score.append(n)
            n = ''
        elif i == 'T':
            n = int(n)**3
            score.append(n)
            n = ''
        elif i == '*':
            if len(score) > 1:
                score[-2] = score[-2] * 2
                score[-1] = score[-1] * 2
            else:
                score[-1] = score[-1] * 2
        elif i == '#':
            score[-1] = score[-1] * -1
        
    return sum(score)

코드 스스로 해석하고 이해하기

- 주어진 문자열을 돌면서

- isnumeric()을 통해 만약 i가 숫자라면 n이라는 빈 문자열에 추가해준다

- 숫자가 아니고 S라면 n에 담긴 수를 정수로 만든 후 1제곱을 해준다. 그 결과를 score에 넣은 뒤 n은 초기화해준다

     - D와 T에 대해서도 같은 원리로

- *와 #에 대해서는 내가 푼 코드와 비슷하니 넘어가겠다

- 마지막에 score의 합을 반환하는 것도 내 코드와 같다

조금만 더 생각해봤으면 풀 수 있었을 것 같아서 너무 아쉽다..

 

def solution(dartResult):
    stack = []
    dartResult = dartResult.replace("10", "A")
    bonus = {'S': 1, 'D': 2, 'T': 3}
    
    for i in dartResult:
        if i.isdigit() or i=='A':
            stack.append(10 if i == 'A' else int(i))
        elif i in ('S', 'D', 'T'):
            num = stack.pop()
            stack.append(num ** bonus[i])
        elif i == '#':
            stack[-1] *= -1
        elif i == '*':
            num = stack.pop()
            if len(stack):
                stack[-1] *= 2
            stack.append(2 * num)
    return sum(stack)

코드 스스로 해석하고 이해하기

- 스택이라는 리스트를 만든다

- 주어진 문자열에서 10이 있다면 A로 바꾼다

- 보너스라는 딕셔너리를 만들어 각 문자열에 해당하는 제곱값 숫자를 value로 넣어준다

- 만약 i가 숫자이거나 A라면 그것을 stack에 넣어주는데,

     - 만약 i가 A라면 10으로 넣어주고 아니라면 정수로 만든 i를 넣어준다

** 조건 표현식 (삼항 연산자) **
- 기본 형식: value_if_true if condition else value_if_false
- if else문을 한 줄에 표현하게 해준다.

- i가 숫자가 아니고 S, D, T 중에 하나라면 (in과 튜플을 활용하는 방법은 생각을 못 해봤다. 앞으로 사용해봐야겠다)

     - 마지막으로 stack에 추가된 값을 num변수에 넣고

     - bonus 딕셔너리 내에서 i와 같은 key값의 value값을 제곱한 뒤 stack에 넣어준다.

- * 계산하는 코드가 흥미롭다

     - 만약 i가 *라면

     - stack에 마지막 추가된 값을 pop을 통해 가져오고 stack에서는 삭제시킨다

     - 만약 위 과정을 거치고 나서도 stack에 값이 남아있다면 그 맨 마지막 값을 2배 해준다.

     - 그리고 pop을 통해 가져온 num값을 두배로 만들어 stack에 넣어준다

- stack의 모든 값을 더해 반환한다.