프로그래머스 2018 KAKAO BLIND RECRUITMENT
- Lv 1. 1차 다트 게임 (Python)
https://school.programmers.co.kr/learn/courses/30/lessons/17682
카카오톡 게임별의 하반기 신규 서비스로 다트 게임을 출시하기로 했다. 다트 게임은 다트판에 다트를 세 차례 던져 그 점수의 합계로 실력을 겨루는 게임으로, 모두가 간단히 즐길 수 있다.
갓 입사한 무지는 코딩 실력을 인정받아 게임의 핵심 부분인 점수 계산 로직을 맡게 되었다. 다트 게임의 점수 계산 로직은 아래와 같다.
S
), Double(D
), Triple(T
) 영역이 존재하고 각 영역 당첨 시 점수에서 1제곱, 2제곱, 3제곱 (점수^1 , 점수^2 , 점수^3 )으로 계산된다.*
) , 아차상(#
)이 존재하며 스타상(*
) 당첨 시 해당 점수와 바로 전에 얻은 점수를 각 2배로 만든다. 아차상(#
) 당첨 시 해당 점수는 마이너스된다.*
)은 첫 번째 기회에서도 나올 수 있다. 이 경우 첫 번째 스타상(*
)의 점수만 2배가 된다. (예제 4번 참고)*
)의 효과는 다른 스타상(*
)의 효과와 중첩될 수 있다. 이 경우 중첩된 스타상(*
) 점수는 4배가 된다. (예제 4번 참고)*
)의 효과는 아차상(#
)의 효과와 중첩될 수 있다. 이 경우 중첩된 아차상(#
)의 점수는 -2배가 된다. (예제 5번 참고)S
), Double(D
), Triple(T
)은 점수마다 하나씩 존재한다.*
), 아차상(#
)은 점수마다 둘 중 하나만 존재할 수 있으며, 존재하지 않을 수도 있다.0~10의 정수와 문자 S, D, T, *, #로 구성된 문자열이 입력될 시 총점수를 반환하는 함수를 작성하라.
"점수|보너스|[옵션]"으로 이루어진 문자열 3세트.
예) 1S2D*3T
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 |
import math
def solution(dartResult):
answer = 0
dart_split = [] # input으로 들어온 문자열 dartResult를 쪼개서 담을 리스트
score = [] # 아래 for문에서 각 점수를 쪼깨어 부분 리스트로 넣을 리스트
# 문자열 쪼개서 담기 작업
for d in dartResult:
if(d.isdigit()): # 만약 숫자면
score.append(int(d)) # int로 변형해서 부분 리스트 score에 넣어두기
else: # 숫자가 아니면 (ex. 'S', 'D', 'T', '*', '#')
score.append(d) # 그냥 string 형식 그대로 부분 리스트 score에 넣어두기
# 부분 리스트인 score 의 길이가 3 이상이라면 -> 점수가 10이라는 소리
# (10은 2자리라서 score에 이렇게 1과 0으로 쪼개어져 들어가있게됨 ex. [1, 0, 'S'])
if (len(score) >= 3):
update = str(score[0]) + str(score[1]) # 맨앞에 두 정수를 붙여서 새로운 정수로 만들어주기 (ex. '1' + '0' -> '10)
score[0] = int(update) # 0번째 자리에 새로 만든 2자리 정수를 넣고 (ex. [10, 0 'S'])
score.pop(1) # 1번 인덱스에 있는건 빼버리기 (ex. [10, 'S'])
# 만약 옵션인 *이나 #이 있다면 -> 따로 분리해서 넣어주기
if (d == '*' or d == '#'):
dart_split.append(score) # 부분 리스트 score를 dart_split 리스트에 넣기
score = [] # 초기화
# 보너스를 만나면 -> 끊어주기
if(d == 'S' or d == 'D' or d == 'T'): # 부분 리스트 score를 dart_split 리스트에 넣기
dart_split.append(score) # 초기화
score = []
print(dart_split)
# dart_split 출력 예시 (ex. [[1, 'S'], [2, 'D'], ['*'], [3, 'T']])
calculate_score = [] # 각 점수를 계산할 리스트
for element_index, element in enumerate(dart_split): # 위의 예시를 토대로 하면 element : [1, 'S'], element_index : 0
# S, D, T를 기반으로 제곱 계산하기
if(element[-1] == 'S'):
calculate_score.append(math.pow(element[0], 1))
if (element[-1] == 'D'):
calculate_score.append(math.pow(element[0], 2))
if (element[-1] == 'T'):
calculate_score.append(math.pow(element[0], 3))
# 만약 옵션 *이 있으면
if(element[-1] == '*'):
index = dart_split.index(element, element_index) # 옵션 *의 인덱스 파악
# 옵션 *이 첫번째 점수에서 나온게 아닐 때
if(index >= 2):
current_index = len(calculate_score) - 1 # 가장 최근 calculate_score에 계산되어 들어온 값의 인덱스
calculate_score[current_index] *= 2 # *을 가진 해당 점수 2배하기
calculate_score[current_index - 1] *= 2 # 해당 점수 바로 전에 얻은 점수 2배하기
# 옵션 *이 첫번째 점수에서 나온거일 때
else:
calculate_score[index - 1] *= 2 # 현재 첫번째 점수만 2배
# 만약 옵션 #이 있으면
if (element[-1] == '#'):
current_index = len(calculate_score) - 1 # 가장 최근 calculate_score에 계산되어 들어온 값의 인덱스
calculate_score[current_index] *= (-1) # #을 가진 해당 점수 마이너스화
print(calculate_score)
# calculate_score 출력 예시 (ex. [2.0, 8.0, 27.0])
# 총 합 계산하기
for score in calculate_score:
answer += score
return answer
→ 뭐가 틀렸는지 확인하고 싶어서 여러 테스트케이스를 혼자 돌려보다가 "1T*2T#3T*"
이 케이스에서 오류가 나는걸 발견했다!
# 만약 옵션 #이 있으면
if (element[-1] == '#'):
current_index = len(calculate_score) - 1 # 가장 최근 calculate_score에 계산되어 들어온 값의 인덱스
calculate_score[current_index] *= (-1) # #을 가진 해당 점수 마이너스화
이 코드 부분에서 원래는 current_index
를 사용하지 않고, index = dart_split.index(element, element_index)
이런식으로 dart_split
에 들어있는 인덱스로 추정하여 #
을 가진 점수 마이너스화를 진행하였다.
# 만약 옵션 #이 있으면
if (element[-1] == '#'):
**index** = dart_split.index(element, element_index)
calculate_score[**index - 1**] *= (-1)
이렇게하면 만약 #
이 인덱스 3
에 존재할 때, index = 3 이 되어 calculate_score[3 - 1] ⇒ calculate_score[2] 의 값을 마이너스화하게 되는데,
#
이 인덱스 3
인 경우는 위 테스트케이스로 예시를 들자면, 올바르게 마이너스화 되어야 하는건 인덱스 2
에 있는 2T 점수이다.
그러나 calculate_score[2] 의 값을 마이너스화 하려고 하면, 인덱스 오류가 난다.
왜냐하면 현재 calculate_score
에는 [1T 계산한값
, 2T 계산한값
] 까지밖에 안들어있기 때문이다.
즉, 인덱스 1
을 마이너스화 해야하기 때문에 #의 인덱스를 얻을 수 있는 dart_split
의 인덱스를 기준으로 생각하지 말고, 계산한 값들이 들어있는 calculate_score
의 인덱스를 기준으로 바꾸어줘야 한다.
▶️ isdigit()
: 문자열에 숫자가 들어있는지 판별하기
참고 : https://cotak.tistory.com/137
초반에 문자열을 자르는 부분에서 하나하나 비교하는 식으로 짰다가 너무 별로라서 위 메서드를 찾아 수정하였다.
if(d == '0' or d == '1' or ... d == '9'):
-> if(d.isdigit()):
▶️ index()
: 리스트 요소를 가지고 인덱스를 찾을 때 특정 요소가 맨 처음으로 위치하고 있는 인덱스만 찾아줌
참고 : https://ooyoung.tistory.com/78
예를 들어, “1S*2S*3S*"
와 같이 *
이 여러개가 껴있어서 중간 *
들의 인덱스를 찾아내지 못하고 계속 맨 처음으로 있는 *
의 인덱스만 찾아낼 때, 시작점을 지정해주어 해당 위치부터 처음 뜨는 *
을 찾아내게 할 수 있다.
# 문자열중 2번째 위치부터 처음 'x'가 위치한 자리
>>> 'oxoxoxoxox'.index('x', 2)
3
이걸 사용한게 아래의 이 코드 부분이다.
index = dart_split.index(element, element_index) # 옵션 *의 인덱스 파악
▶️ 2번을 위해서 현재 위치를 같이 전달해줘야하니까 enumerate()
를 써주었다. (쓸때마다 헷갈리는 놈)
참고 : https://www.daleseo.com/python-enumerate/
>>> for i, letter in enumerate(['A', 'B', 'C']):
... print(i, letter)
...
0 A
1 B
2 C
아무튼 이런 형식
for 요소의_인덱스, 요소 in enumerate(리스트):
replace()
를 사용한 점이 인상깊었다.
def solution(dartResult):
point = []
answer = []
dartResult = dartResult.replace('10','k')
point = ['10' if i == 'k' else i for i in dartResult]
print(point)
i = -1
sdt = ['S', 'D', 'T']
for j in point:
if j in sdt :
answer[i] = answer[i] ** (sdt.index(j)+1)
elif j == '*':
answer[i] = answer[i] * 2
if i != 0 :
answer[i - 1] = answer[i - 1] * 2
elif j == '#':
answer[i] = answer[i] * (-1)
else:
answer.append(int(j))
i += 1
return sum(answer)
애초에 이렇게 하나하나 다 쪼개서 하는게 나았을지도?!