알고리즘-2021/05/04

sanghun Lee·2021년 5월 4일
0

알고리즘

목록 보기
40/52
post-thumbnail

다트 게임

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

다트 게임은 총 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

첫번째 풀이

function solution(dartResult) {
    let answer = 0;
    let splitArr = dartResult.split("");
    let doSDTArr = [];
    let doStarArr = [];
    if(dartResult.includes("10")){
      let tenIdx = dartResult.indexOf("10");
      splitArr = [...splitArr.slice(0,tenIdx),'10',...splitArr.slice(tenIdx+2,splitArr.length+1)]
    }
  
  
    //1. SDT처리
    // console.log(splitArr);
    splitArr.forEach((el,index)=>{
      if(el === "S"){
        return doSDTArr[index-1] = Number(splitArr[index-1])**1;
      }else if(el === "D"){
        return doSDTArr[index-1] = Number(splitArr[index-1])**2;
      }else if(el === "T"){
        return doSDTArr[index-1] = Number(splitArr[index-1])**3;
      }else{
        return doSDTArr[index] = el;
      }
    })
  
    doSDTArr = doSDTArr.filter((el)=> el);
    // console.log(doSDTArr);
    //2. # 처리
    let starArr = [];
    let NotStarIdxArr = [];
    doSDTArr.forEach((el,index)=>{
      if(el ==="#"){
        doStarArr[index] = 0;
        return doStarArr[index-1] =  Number(doSDTArr[index-1])*-1;
      }else if(el !== "*"){
        return doStarArr[index] = Number(el);
      }else{
        return  doStarArr[index] = el;
      } 
    })

    //3. * 인덱스를 활용하여 앞으로 숫자 두개만 2곱하기 진행
    console.log(doStarArr);
    for(let i = 0; i < doStarArr.length; i++){
        let count = 0;
        for(let j = i; j >= 0; j--){
          if(doStarArr[i] === "*"){
            if(doStarArr[j] !== "*" && doStarArr[j] !== 0){
              doStarArr[j] *= 2;
              count +=1;
            } 
          }
          if (count >=2) break;
        }    
    }
    
    //총합
    let filterStarArr = doStarArr.filter(el=>el!=="*");
    console.log(filterStarArr);
     answer = doStarArr.filter(el=>el!=="*").reduce((a,b)=>a+b);
      
    return answer;
}
console.log(solution('1S*2T*3S')); //23
// console.log(solution('1S2D*3T')); //37
console.log(solution("1D#2S*3S")); //5
console.log(solution("1D2S3T*"));  //59
// console.log(solution("1T2D3D#"));
console.log(solution("1D2S#10S")); //9

몇몇개의 테스트 케이스 통과가안된다
이 방식 자체가 잘못된듯 ㅎㅅㅎ...
배열을 계속 만들어 주며 그 안에서 필요한 조건에따라 숫자를 변경하는 방식으로 진행하려 하였다.
*의 조건이나 #의 조건에서 조금 엉킨것도 있을 것 같고
무엇보다 10에대한 처리가 제대로 되지않았었다 ㅎㅅㅎ...

두번째 풀이 (스택을 생각하자)

function solution(dartResult) {
    let answer = 0;
    let splitArr = [];
    let stack = [];
    //스택은 위에서쌓고 빼면 제일위에것임
    //따라서 concat(push는 배열순서바뀌니께)과 pop으로 조절할 수 가 있게된다.
    dartResult.split("").forEach((el,index)=>{
      if(!isNaN(dartResult[index-1]) && !isNaN(dartResult[index])){
        console.log("find 10!");
        splitArr.pop();
        splitArr = splitArr.concat(('10'));
      }else{
        splitArr = splitArr.concat((el));
      }
    })
  
    splitArr.forEach((el,index)=>{
      if(!isNaN(el)){
        stack = stack.concat(el);
      }else if(["S","D","T"].includes(el)){
        if(el === "S"){
            let newEl = Number(stack.pop()**1);
            stack = stack.concat(newEl);
        }else if(el ==="D"){
            let newEl = Number(stack.pop()**2);
            stack = stack.concat(newEl);
        }else if(el ==="T"){
            let newEl = Number(stack.pop()**3);
            stack = stack.concat(newEl);
        }
      }else if(["*"].includes(el)){
          //앞의 숫자 2개까지 곱하기 2 한다고 하였으니!
            // let newEl =  Number(stack.pop()*2)

            let newEl = stack.pop()*2;
            let secondEl = stack.pop()*2;
            if(secondEl){
                stack = stack.concat(secondEl,newEl);
            }else{
                stack = stack.concat(newEl);
            }
        
      }else if(["#"].includes(el)){
            let newEl =  Number(stack.pop()*-1);
            stack = stack.concat(newEl);
      }
    })
    console.log(stack);
  
    
    return stack.reduce((a,b)=>a+b);
}
console.log(solution('1S*2T*3S')); //23
console.log(solution("1D#2S*3S")); //5
console.log(solution("1D2S3T*"));  //59
console.log(solution("1D2S#10S")); //9

생각을 조금 바꿔서 스택을 기본 구조로하고 10과함께 구분되어 있는 배열에 각 조건들을 뺏다가 넣어주는 방식으로 변경하였다.

진작 이렇게 할 걸... 자료구조에 대한 공부가 더욱 중요하다는 것을 깨닫게 되었다.

메서드에 혼동이 조금 있어 정리하자면

  • push: 배열 길이 반환, 기존 배열 변환됨
  • concat: 변경된 배열 반환, 기존배열 변환 없음
  • pop: 제일 마지막 index의 값 반환, 기존배열 마지막 원소 제거

참고

*프로그래머스-[1차] 다트게임_

profile
알고리즘 풀이를 담은 블로그입니다.

0개의 댓글