문제 설명
다트 게임
카카오톡에 뜬 네 번째 별! 심심할 땐? 카카오톡 게임별~
카카오톡 게임별의 하반기 신규 서비스로 다트 게임을 출시하기로 했다. 다트 게임은 다트판에 다트를 세 차례 던져 그 점수의 합계로 실력을 겨루는 게임으로, 모두가 간단히 즐길 수 있다.
갓 입사한 무지는 코딩 실력을 인정받아 게임의 핵심 부분인 점수 계산 로직을 맡게 되었다. 다트 게임의 점수 계산 로직은 아래와 같다.
- 다트 게임은 총 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 |
💛 나의 풀이
def solution(dartResult):
answer = 0
ans=""
dic={"S":1, "D":2, "T":3}
record=[] # 다트 점수 기록
idx=0 # record 인덱스
for dart in dartResult :
if dart.isdigit() :
ans+=dart # 점수(10을 고려하기 위해)
elif dart in dic :
ans=int(ans)**dic[dart]
answer+=ans
record.append(ans)
ans="" # 다음 판의 점수를 받기 위해 초기화
idx+=1
elif dart == "*" :
if idx != 1 :
answer+=record[idx-2]+record[idx-1]
record[idx-1]*=2
record[idx-2]*=2
else : # 스타상(*)이 첫 번째 기회에서 나올 경우
answer+=record[idx-1]
record[idx-1]*=2
elif dart == "#" :
record[idx-1]*=-1
answer+=record[idx-1]*2
return answer
입력 문자열에서 하나씩 읽고 실행하게 만들었다.
10점도 고려해야해서 ans+=dart로 덧붙인다.
ans는 S/D/T 이후로 초기화시켰다.
딕셔너리에서 지수를 가져온다. if문을 쓰기 싫어서 딕셔너리 씀!
리스트 record는 점수를 기록한다.
*/#을 적용하면 answer에 더하는 것 뿐만 아니라 해당 인덱스의 값도 갱신해야 한다.
5번 테케 1D#2S*3S를 예로 들어보겠다.
1D#까지 실행한 후 -1이다.
#을 적용한 후 갱신을 안했으면 record[0]=1이고, answer=-1이다.
*은 이전 점수도 2배 시키므로 record[0]이 -2가 아닌 2가 된다.
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.math.*;
class Solution {
public int solution(String dartResult) {
int[] answer = new int[3];
int idx=0;
int result=0;
HashMap<String, Integer> map=new HashMap<>();
map.put("S", 1);
map.put("D", 2);
map.put("T", 3);
// 정규표현식
Pattern pattern=Pattern.compile("([0-9]+)([SDT])([*#]?)");
Matcher matcher=pattern.matcher(dartResult);
while(matcher.find()){
int num=Integer.parseInt(matcher.group(1));
String n=matcher.group(2);
Integer nn=map.get(n); // 지수
answer[idx]=(int)Math.pow(num, nn);
if(matcher.group(3).equals("#")) {
answer[idx]*=-1;
}
else if(matcher.group(3).equals("*")){
answer[idx]*=2;
if(idx != 0){
answer[idx-1]*=2;
}
}
idx++;
}
for(int i=0; i<3; i++) result+=answer[i];
return result;
}
}
처음에 정규표현식을 "(\d+)([SDT])([*#]?)"로 했더니 에러가 .. 🥲
배열 answer에 값을 넣고, 마지막에 다 더해서 result에 저장했다.
# 실패
def solution(dartResult):
answer = 0
ans=""
dic={"S":1, "D":2, "T":3}
for dart in dartResult :
if dart.isdigit() :
ans+=dart # 점수
elif dart in dic :
ans=int(ans)**dic[dart]
answer+=ans
elif dart == "*" :
answer*=2
elif dart == "#" :
answer+=ans*2*-1 # 해당값*-1
return answer
풀다가 꼬였다...
문자 하나씩 확인하다보니 10을 처리할 때 문제가 생김
그래서 +로 이어붙이려고 했으나 ans를 언제 ""로 초기화를 할지가 문제다.
*또는 #이 있을 수도 없을 수도 있어서 S/D/T 처리 후 바로 ans를 ""로 초기화하면 또 dart=="#"에서 ans를 쓰니까 ㅠㅠ
🐱 다른사람 풀이
import re
def solution(dartResult) :
bonus={'S' : 1, 'D' : 2, 'T' : 3}
option={'':1, '*' : 2, '#' : -1}
p=re.compile('(\d+)([SDT])([*#]?)')
dart=p.findall(dartResult)
for i in range(len(dart)) :
if dart[i][2] == '*' and i > 0 :
dart[i-1]*=2
dart[i]=int(dart[i][0])**bonus[dart[i][1]]*option[dart[i][2]]
answer=sum(dart)
return answer
'(\d+)([SDT])([*#]?)'는 ()으로 그룹을 나눴다.
\d는 숫자
+는 한 번이상 반복
[]는 문자를 매치한다.
?는 있거나 없거나다.
정규 표현식을 이용해 한 차례씩 나누고 계산한다.
"1D2S#3T"의 경우 [('1', 'D', ''), ('2', 'S', '#'), ('3', 'T', '')]가 된다.
def solution(dartResult) :
dart={'S':1, 'D':2, 'T':3}
scores=[]
n=0 # n판의 시작점
for i, d in enumerate(dartResult) :
if d in dart : # S/D/T
scores.append(int(dartResult[n:i])**dart[d])
if d == "*" :
scores[-2:]=[x*2 for x in scores[-2:]]
if d == "#" :
scores[-1]=(-1)*scores[-1]
if not (d.isnumeric()) :
n=i+1
return sum(scores)
간결하고 좋은 로직인 듯
scores.append(int(dartResult[n:i])**dart[d])
n과 i로 숫자만 슬라이싱하고 거듭제곱한다.
scores[-2:]=[x*2 for x in scores[-2:]]
scores[-2:]를 하면 이전과 현재 값을 2배로 해줄 수 있다.
첫 판에 *이 있어도 조건문 없이 해결
scores[-1]=(-1)*scores[-1]
#이 나왔을 때 해당값에 -1을 곱해주는 부분이다.
인덱스가 -1인 이유는 최근에 거듭제곱해서 숫자를 scores에 넣었기 때문이다.
if not (d.isnumeric()) :
이걸 보고 isnumeric()과 isdigit()이 무슨 차이지??라는 생각이 들었다..
python doument에서 찾아봤다.
str.isnumeric()
Return True if all characters in the string are numeric characters, and there is at least one character, False otherwise.
str.isdigit()
Return True if all characters in the string are digits and there is at least one character, False otherwise.
numeric과 digit이 둘다 숫자를 의미하는 것 아닌가...🙄
isdigit()보다 isnumeric()이 범위가 더 크다.
예를 들어, isnumeric()은 '1/2'과 같은 분수를 True 반환하지만 isdigit()은 False
// https://girawhale.tistory.com/48
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Solution {
public int solution(String dartResult) {
// 정규표현식
Pattern pattern=Pattern.compile("([0-9]+)([SDT])([*#]?)");
Matcher matcher=pattern.matcher(dartResult);
Deque<Integer> score=new ArrayDeque<>();
while(matcher.find()){
int tmp=Integer.parseInt(matcher.group(1));
switch(matcher.group(2)){
case "D" :
tmp*=tmp;
break;
case "T" :
tmp*=tmp*tmp;
}
switch(matcher.group(3)){
case "*" :
if(!score.isEmpty()) // 첫판 x
score.push(score.pop()*2);
tmp*=2;
break;
case "#" :
tmp*=-1;
break;
}
score.push(tmp);
}
int ans=0;
while(!score.isEmpty())
ans+=score.pop();
return ans;
}
}
deque에 값을 저장한다.
*을 적용할 때 pop으로 마지막 값을 뽑고 2배해서 다시 push로 넣어 이전 값 2배를 해준다.
첫판에 *이 있는 경우 scores는 비어있으므로 현재 값만 2배 해준다.
문제 출처 👉 프로그래머스
'coding test' 카테고리의 다른 글
[Java] 9663. N-Queen (0) | 2021.08.29 |
---|---|
[Java] 15649. N과 M (1) (0) | 2021.08.29 |
[파이썬] [1차] 비밀지도 (0) | 2021.08.27 |
[파이썬, Java] [1차] 캐시 (0) | 2021.08.26 |
[파이썬] [1차] 프렌즈4블록 (0) | 2021.08.20 |