논리적으로 차분하게 코딩하기

1. 문제

 

https://programmers.co.kr/learn/courses/30/lessons/17682

 

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

 

programmers.co.kr

 

 

카카오톡 게임별의 하반기 신규 서비스로 다트 게임을 출시하기로 했다.

 

다트 게임은 다트판에 다트를 세 차례 던져 그 점수의 합계로 실력을 겨루는 게임으로, 모두가 간단히 즐길 수 있다.

 

갓 입사한 무지는 코딩 실력을 인정받아 게임의 핵심부분인 점수 계산 로직을 맡게 되었다.

 

다트 게임의 점수 계산 로직은 아래와 같다

 

다트 게임은 총 3번의 기회로 구성된다

 

각 기회마다 얻을 수 있는 점수는 0점에서 10점까지이다.

 

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

 

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

 

아차상 당첨시 해당 점수는 마이너스된다.

 

스타상은 첫번째 기회에서도 나올 수 있다. 이 경우 첫번째 스타상의 점수만 2배가 된다.

 

스타상의 효과는 다른 스타상의 효과와 중첩될 수 있다.

 

이 경우 중첩된 스타상 점수는 4배가 된다.

 

스타상의 효과는 아차상의 효과와 중첩될 수 있다. 이 경우 중첩된 아차상의 점수는 -2배가 된다

 

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

 

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

 

0~10의 정수와 문자 S,D,T,*,#로 구성된 문자열이 입력될 시 총점수를 반환하는 함수를 작성하세요

 

 

2. 예시

 

그림1. 입출력 예시

 

3. 나의 풀이

 

기술은 필요하지 않고 규칙에 맞게 침착하게 코딩하면 된다

 

def solution(dartResult):
    
    answer = 0
    
    score_list = []
    
    for ind, result in enumerate(dartResult):
        
        if result.isdigit():
        
            if ind >= 1:
                
                if result == '0':
                    
                    if score_list[-1] == 1:
                        
                        score_list[-1] = 10
                        
                    else:
                        
                        score_list.append(int(result))
                    
                else:
                
                    score_list.append(int(result))
                    
            else:
                
                score_list.append(int(result))

 

 

숫자, 문자 이런식으로 구성되어 있으니까 dartResult에서 문자를 하나씩 빼서 숫자인지 문자인지 검사를 하는 isdigit()을 사용

 

숫자라면 이제 score_list에 넣으면 되는데 문자니까.. int로 바꿔서 넣어준다

 

근데 이제 10이 문제인데.. 10을 넣기 위해서 enumerate()로 ind까지 빼줄건데

 

ind가 1이상인경우는.. dartResult에서 뺀 문자 result가 ‘0’이면…

 

이제 score_list에 마지막으로 들어간 숫자가 1인지 아닌지 검사를 한다

 

1이라면 10이 들어가야하므로 마지막에 들어간 숫자를 10으로 수정하고

 

1이 아니면 그냥 0을 int로 바꿔서 넣어준다

 

  else:

      if result == 'S':

          score_list[-1] = score_list[-1] ** 1

      elif result == 'D':

          score_list[-1] = score_list[-1] ** 2

      elif result == 'T':

          score_list[-1] = score_list[-1] ** 3

      elif result == '*':

          if len(score_list) == 1:

              score_list[-1] = score_list[-1] * 2

          else:

              score_list[-2] = score_list[-2] * 2

              score_list[-1] = score_list[-1] * 2

      else:

          score_list[-1] = score_list[-1] * (-1)
 
 answer = sum(score_list)
 
 return answer

 

 

이제 문자에 따른 효과를 구성할건데

 

result가 S,D,T인 경우 바로 앞의 숫자에 대해 1제곱,2제곱,3제곱을 할건데

 

이제 만약 문자로 S,D,T가 나온다면 그 전 문자는 숫자이고 score_list에 들어갔을거임

 

마지막에 score_list로 들어간 score_list[-1]에 효과가 적용된다는 소리

 

근데 이제 *랑 # 이게 문제인데

 

*인 경우는 *앞에 붙은 score인 score_list[-1]에 적용이 되어야하는데

 

문제는 *앞에 붙은 것 뿐만 아니라 그 이전 score인 score_list[-2]에도 적용이 되어야한다

 

더 생각을 해서 *이 첫번째에 나오냐, 두번째에 나오냐 다를 수 있음

 

score_list의 길이가 1인지 아닌지 검사해서 1이면 *이 첫번째에 나온 것이므로

 

score_list[-1]에만 적용하고 1이 아니면 *이 두번째 이후에 나온거라서 [-2]와 [-1]모두에 2배를 적용

 

마지막으로 #이 나오면 그 앞에 나온 숫자에 -1배를 해야해서 score_list[-1] -1을 곱해준다

 

최종적으로 반복문을 끝내면 score_list의 합을 구한다

 

 

4. 다른 풀이

 

10을 어떻게 처리했을지..? 주목해볼 필요가 있다

 

def solution(dartResult):
    
    point = []
    
    answer = []
    
    dartResult = dartResult.replace('10','k')
    
    point = ['10' if i == 'k' else i for i in dartResult]

 

dartResult에서 ‘10’이 존재하면 ‘k’라는 문자로 바꿔주고

 

point라는 리스트를 만드는데 ‘k’이면 10으로 바꿔서 넣어줘

 

 

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)

 

다음 sdt를 구성한 다음에 i=-1로 초기화하고

 

point에는 숫자, 문자가 구성된 리스트일텐데 for문으로 돌아

 

처음 돌 때는 문자일리 없으니까 마지막 else문에서 answer.append(int(j))에 들어갈거고

 

이제 i를 +=1을 해주는데

 

그러면 answer에 마지막으로 들어간 수는 index 0에 저장이 되어 있을거

 

이제 문자가 나올텐데 만약 S,D,T이면 1제곱 2제곱 3제곱을 할건데

 

if문으로 S,D,T로 안나누고 sdt.index를 이용해서 한문장으로 처리한거 멋지고

 

만약 *가 나온다면 2배를 할건데

 

숫자가 들어갈 때마다 i에 값이 더해지니까

 

i가 0이 아니라면.. 그러니까 i가 1이나 2라면 answer에 숫자가 2개 이상 들어가있으니까

 

answer[i]와 answer[i-1] 모두에 2배를 하고 i가 0이면 answer에 숫자 하나가 들어가있으니까 answer[i]만 2배를함

 

#이면 마지막으로 들어간 answer[i]에 -1배를 함

 

한번의 for문을 다 돌면 answer에 들어간 점수의 합을 return

 

 

5. 되돌아보기

 

이런 문제는 알고리즘 기술이 안들어가서 쉽지만 문제 조건에 맞게 논리적으로 코딩을 잘 해야한다

 

10을 어떻게 처리했는지? 다른 풀이에서 replace를 이용해서 문자 하나로 바꿔서 처리한거 멋지고

 

물론 나도 복잡했지만 논리적으로 처리 잘 했다

 

마지막으로 들어간 수 score_list[-1]을 활용 잘 했다는 점

 

*의 효과를 처리할 때 첫번째로 들어가냐, 두번째로 들어가냐 경우를 잘 생각했고

 

S,D,T의 점수 처리할때 if문 3개로 나눠서 하느냐…

 

아니면 그냥 리스트에 넣어서 index를 활용해서 if 한문장으로 처리하느냐..?

 

TAGS.

Comments