𝝅번째 알파카의 개발 낙서장

screen

[프로그래머스 / JAVA] Level 1 다트 게임 (17682)

posts

알고리즘

시리즈 톺아보기

프로그래머스

프로그래머스
count

다트 게임 🔗

랭크 사용 언어
Level 1 JAVA

🔗 다트 게임

문제 설명 🔗

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

image

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

  1. 다트 게임은 총 3번의 기회로 구성된다.
  2. 각 기회마다 얻을 수 있는 점수는 0점에서 10점까지이다.
  3. 점수와 함께 Single(S), Double(D), Triple(T) 영역이 존재하고 각 영역 당첨 시 점수에서 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, *, #로 구성된 문자열이 입력될 시 총점수를 반환하는 함수를 작성하라.

입력 형식 🔗

"점수|보너스|[옵션]"으로 이루어진 문자열 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

풀이 🔗

문제를 해결하는 방식이 생각보다는 좀 까다롭다.

  • 점수 - 보너스 - 옵션 순으로 배치되지만, 옵션은 있을 수도, 없을 수도 있다.
  • 스타상(*)의 경우 이전 점수에도 영향을 준다.
    • 스타상은 가장 첫 점수에도 나올 수 있으며, 이 경우 이전 점수가 없으므로 해당 점수만 영향을 준다.

때문에 각 점수 세트를 정확히 분리할 수 있어야하고, 이전 점수를 건드릴 필요가 있기 때문에 배열 형태로 점수를 저장할 필요가 있어보인다.


  1. 점수 세트 분리
  2. 점수 세트의 점수, 보너스, 옵션 분리
  3. 점수와 보너스를 곱해 기본 점수를 구한다
  4. 옵션 효과에 따라 점수에 반영한다

1번, 2번이 좀 까다로울 수 있겠지만, 정규식을 사용한다면 매우 간단하게 분리할 수 있다.

  • 점수 분리 정규식 - ([0-9]0?)([SDT])([*#]?)
  • [0-9] - 0 ~ 9 사이의 숫자 한 자리
  • 0? - 0이 있을 수도 있고, 없을 수도 있음
  • [SDT] - 보너스
  • [*#] - *, # 한 자리
  • [*#]? - *, #이 있을 수도 있고, 없을 수도 있음

()의 경우 정규식 자체에 영향을 주진 않지만, 코드 내에서 해당 정규식을 그룹별로 분리할 때 쓴다.

JAVA의 경우 group() 메서드를 통해 ()로 구분된 그룹별로 패턴을 따로 뽑아낼 수 있다. 예를 들어, ([0-9]0?)의 경우 2S*에서 2만 뺄 수 있다.

  • group(1) - 2
  • group(2) - S
  • group(3) - *

정규식으로 점수 세트 하나를 뽑아낸 뒤에, 굳이 이거 저거 빼고 *# 존재여부 판별없이 정규식 하나만으로 전부 해결할 수 있다.


점수 분리를 성공적으로 했다면 이후는 쉽다. 곱할거 곱해주고, 반영할거 반영해서 배열에 저장하면 된다. 만약, 스타상이 떴다? 이전 데이터의 점수를 호출해서 반영해주면 된다.

코드 🔗

JAVA

0import java.util.ArrayList;
1import java.util.regex.Matcher;
2import java.util.regex.Pattern;
3
4/**
5 * 다트 게임 클래스
6 *
7 * @author RWB
8 * @since 2021.12.12 Sun 17:55:08
9 */
10class Solution
11{
12 /**
13 * 해답 반환 메서드
14 *
15 * @param dartResult: [String] 점수|보너스|옵션 문자열 (옵션은 선택사항)
16 *
17 * @return [int] 해답
18 */
19 public int solution(String dartResult)
20 {
21 int answer = 0;
22 int index = 0;
23
24 Matcher matcher = Pattern.compile("([0-9]0?)([SDT])([*#]?)").matcher(dartResult);
25
26 ArrayList<Integer> scores = new ArrayList<>();
27
28 while (matcher.find())
29 {
30 int type = matcher.group(2).equals("T") ? 3 : matcher.group(2).equals("D") ? 2 : 1;
31 int option = matcher.group(3).equals("*") ? 2 : matcher.group(3).equals("#") ? -1 : 1;
32
33 int score = (int) Math.pow(Integer.parseInt(matcher.group(1)), type) * option;
34 scores.add(index, score);
35
36 // 인덱스가 0보다 크고, 스타상을 받았을 경우
37 if (index > 0 && option == 2)
38 {
39 // 이전 점수도 스타상의 영향으로 2배가 된다.
40 scores.set(index - 1, scores.get(index - 1) * option);
41 }
42
43 index++;
44 }
45
46 for (Integer score : scores)
47 {
48 answer += score;
49 }
50
51 return answer;
52 }
53}

정규식에 대한 약간의 이해가 있다면 매우 쉽게 풀 수 있는 문제.

정규식의 사용 부분이 궁금하다면 matcher.group()이 사용되는 구문을 유심히 보자.