ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [programmers/Swift] 다트게임 (2018 Kakao Blind Recruitment 1차)
    Legacy/Be Refactoring.. 2020. 12. 2. 17:43

    2018 KAKAO BLIND RECRUITMENT

    programmers.co.kr/코딩테스트연습/Lv.1/2018 KAKAO BLIND RECRUITMENT/[1차]다트게임 

    다트게임 (2018 Kakao Blind Recruitment 1차)

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

     

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

     

    programmers.co.kr


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

    이미지출처 프로그래머스

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

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

     

    TODO

    점수|보너스|[옵션]으로 이루어진 문자열 3세트.  예)  1S2D*3T

    • 점수는 0에서 10 사이의 정수이다.
    • 보너스는 S, D, T 중 하나이다.
    • 옵선은 *이나 # 중 하나이며, 없을 수도 있다.

    Constraints :

    3번의 기회에서 얻은 점수 합계에 해당하는 정수값을 출력한다.
    예) 37

     

    Sample Input :

    예제	dartResult	설명
    1	1S2D*3T		11 * 2 + 22 * 2 + 33
    2	1D2S#10S	12 + 21 * (-1) + 101
    3	1D2S0T		12 + 21 + 03
    4	1S*2T*3S	11 * 2 * 2 + 23 * 2 + 31
    5	1D#2S*3S	12 * (-1) * 2 + 21 * 2 + 31
    6	1T2D3D#		13 + 22 + 32 * (-1)
    7	1D2S3T*		12 + 21 * 2 + 33 * 2

    Sample Output :

    answer
    37
    9
    3
    23
    5
    -4
    59

    Solution.swift :

    //
    //  Created by Yongwoo Marco on 2020/10/15.
    //  Copyright © 2020 Yongwoo Marco Kim. All rights reserved.
    //
    func solution(_ dartResult:String) -> Int {
        let numbers = dartResult.split(whereSeparator: {$0.isLetter||$0=="*"||$0=="#"})
        let letters = dartResult.split(whereSeparator: {$0.isNumber})
        
        var result = numbers.map({Int($0)!})
        
        for (index, element) in letters.enumerated() {
            for c in String(element) {
                let i = Int(index)
                switch c {
                case "S":
                    break
                case "D":
                    result[i] *= result[i]
                case "T":
                    result[i] *= result[i]*result[i]
                case "*":
                    if i != 0 {
                        result[i-1] *= 2
                    }
                    result[i] *= 2
                case "#":
                    result[i] *= -1
                default:
                    print("error")
                }
            }
        }
        
        return result.reduce(0, +)
    }

    How I tried this :

    문자열만 읽어내면 되는 문제이기 때문에 처음에 쉽게 접근했다.

    아래 코드는 내가 처음 떠올린 방법으로 구현한 코드이다.

    func solution(_ dartResult:String) -> Int {
        var num = 0
        var result = [Int]()
        for (index, element) in dartResult.enumerated() {
            switch element {
            case "1":
                if(Array(dartResult)[index+1]=="0") { // 만난 문자가 10인 경우 
                    result.append(num)
                    num = -1
                } else {
                    fallthrough
                }
            case "0":
                if num == -1 { 			// 만난 문자가 10인경우
                    num = 10
                } else {
                    fallthrough
                }
            default:
                if let intNum = Int(String(element)) {  // 만난 문자가 숫자인경우
                    result.append(num)
                    num = intNum
                } else {				// 만난 문자가 숫자가 아닌경우
                    switch element {
                    case "S":
                        break
                    case "D":
                        num *= num
                    case "T":
                        num *= num*num
                    case "*":
                        result[result.count-1] *= 2
                        num *= 2
                    case "#":
                        num *= -1
                    default:
                        print("error")
                    }
                }
            }
        }
        result.append(num)
        
        return result.reduce(0, +)
    }

    조금 C++ 다룰때 느낌이 났다. 먼가 더 이쁘게 할수 있을거 같은데... 

    라면서 떠올린건 문자열을 일단 숫자와 문자로 파싱하는 거였다.. 구현해보려고 했지만 차피 돌아가는데? 마인드로 자꾸 미루다가

    프로그래머스의 장점인 다른 사람의 답을 보았다..그래도 내 답변이 정답처리는 되었으니까..

     

    아래 코드는 다른 분들의 답을 보다가 알게된 강력한 함수를 이용해서 풀이한 답이다. 

    func solution(_ dartResult:String) -> Int {
        let numbers = dartResult.split(whereSeparator: {$0.isLetter||$0=="*"||$0=="#"})
        let letters = dartResult.split(whereSeparator: {$0.isNumber})
    
        var result = numbers.map({Int($0)!})
    
        for (index, element) in letters.enumerated() {
            for c in String(element) {
                let i = Int(index)
                switch c {
                case "S":
                    break
                case "D":
                    result[i] *= result[i]
                case "T":
                    result[i] *= result[i]*result[i]
                case "*":
                    if i != 0 {
                        result[i-1] *= 2
                    }
                    result[i] *= 2
                case "#":
                    result[i] *= -1
                default:
                    print("error")
                }
            }
        }
    
        return result.reduce(0, +)
    }

    이 얼마나 편리하고 아름다운가...

    .split(separator: String) 이용해서 단순히 나누기만 해보았지

    whereSeparator 라니.. 아주 강력한 기능이었다.

    메소드를 이용해서 문자와 특수기호는 하나씩 배열에 넣고

    숫자도 2자리 수여도 하나씩 배열에 넣을 수 있었다.

     

    이후 처리는 더 좋은 방법이 있을까 싶다. 

     

    한가지 조건을 실수로 놓친게 '*' 또는 "#" 기호가 나올때

    여태까지 쌓은 점수를 모두 2배로 만들거나 -1로 만드는게 아니라

    "당첨 시 해당 점수와 바로 전에 얻은 점수"

    를 변경해야되는데 그점을 실수로 전체로 두어서 몇번 고생하다가 

    문제를 다시 읽고 해결했다.

     

    What I got is : 

    .split(maxSplits:omittingEmptySubsequences:whereSeparator:)

    String 내부에 구현된 메소드로 

     

    I have to study :

    String 메소드

    문제 해설 : 카카오 해설
    문제에 관한 모든 저작권 : https://programmers.co.kr/
     

    프로그래머스

    코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

    programmers.co.kr

     

Designed by Tistory.