본문 바로가기
App 개발/Xcode

숫자 Baseball 게임 : 주요 기능 정리

by TomAdmin 2024. 6. 17.

   class BaseballGame {

    func start() {

        let answer = makeAnswer()!   // 정답값 만드는 함수 호출

        

        print("숫자 야구 게임 Start!!")

        

        while true {                // ABS 판독기

            let input = getInput()

            

            if let guess = input {

                let score = calculateABS(target: answer, user: guess) // calculateABS 값 호출

                print("\(score.strikes) 스트라이크, \(score.balls) 볼")

                

                if score.strikes == 3 {

                    print("3 Strike!!!! OUT!!!")

                    break

                }

            }

        }

    }

    

    func makeAnswer() -> [Int]? {  // 정답 함수 만들기

        var number = Array(1...9)

        number = number.shuffled()

        return Array(number.prefix(3)) // ArraySlice -> Array 타입 변환

    }

 

    

    func getInput() -> [Int]? {

        print("서로 다른 숫자 3개를 입력하세요 => ", terminator: "")

        if let getValue = readLine() {

            let inputNum = getValue.compactMap { $0.wholeNumberValue } //  데이터 변형 후 캐릭터 타입을 인트로 변환

            if inputNum.count == 3 && Set(inputNum).count == 3

                return inputNum

            } else {

                print("숫자 3자리만 입력해주세요!")

                return getInput()

            }

        }

        return nil

    }

    

    // zip, filter, tuple을 사용해서 스트라이크, 볼 판정

    func calculateABS(target: [Int], user: [Int]) -> (strikes: Int, balls: Int) { // target, user는 숫자 배열임

        let strikes = zip(target, user).filter { $0 == $1 }.count // filter를 연속으로 사용가능하니 이후 단계에서 적용해볼것

        let balls = user.filter { target.contains($0) }.count - strikes // 예시 [1, 3, 2] -> 3 이런 방식사용

        return (strikes, balls)

    }

}

 

chatGPT에게 작성한 코드를 해석해서 자세히 설명해달라고 요청

자세한 설명

  1. inputNum 배열: digits는 사용자가 입력한 3자리 숫자를 각 자리별로 분리한 배열입니다. 예를 들어, 사용자가 123을 입력했다면 digits는 [1, 2, 3]이 됩니다.
  2. Set(inputNum): Set은 Swift의 컬렉션 타입 중 하나로, 중복된 요소를 허용하지 않습니다. Set(inputNum)는 배열 digits의 중복 요소를 제거한 집합을 만듭니다.
    • 예: inputNum [1, 2, 3]일 경우 Set(inputNum)는 {1, 2, 3}입니다.
    • 예: inputNum [1, 1, 2]일 경우 Set(inputNum)는 {1, 2}입니다.
  3. Set(inputNum).count: 중복을 제거한 후 남은 고유 요소의 개수를 세는 것. 만약 사용자가 중복된 숫자를 입력했다면, Set(inputNum).count는 원래의 inputNum.count보다 작아집니다.
    • 예: inputNum [1, 2, 3]일 경우 Set(inputNum).count는 3입니다.
    • 예: inputNum [1, 1, 2]일 경우 Set(inputNum).count는 2입니다.

동작 방식 설명

  1. 입력받기: readLine()을 통해 사용자 입력을 받습니다.
  2. 숫자 변환: compactMap { $0.wholeNumberValue }를 사용하여 각 문자를 숫자로 변환합니다.
  3. 중복 확인: inputNum.count == 3와 Set(inputNum).count == 3를 사용하여 입력된 숫자가 정확히 3개이고, 중복되지 않는지 확인합니다.

이 조건을 통해 사용자가 중복되지 않는 3자리 숫자를 입력했는지 확인할 수 있습니다.

 

세부 동작 설명

1. 스트라이크 계산

let strikes = zip(target, guess).filter { $0 == $1 }.count
  • zip(target, guess): 두 배열의 각 요소를 병렬로 묶어 새로운 시퀀스를 만듭니다. 예를 들어, target이 [1, 2, 3]이고 guess가 [1, 3, 2]일 때, zip(target, guess)는 [(1, 1), (2, 3), (3, 2)]가 됩니다.
  • .filter { $0 == $1 }: 각 튜플의 요소가 같은지 비교합니다. 여기서 $(0,1)은 튜플의 첫 번째 요소, $(1,3)은 두 번째 요소를 나타냅니다. [(1, 1), (2, 3), (3, 2)]에서 첫 번째 튜플 (1, 1)만 동일합니다.
  • .count: 필터링된 튜플의 개수를 셉니다. 이 경우 스트라이크의 수는 1입니다.

2. 볼 계산

let balls = guess.filter { target.contains($0) }.count - strikes
  • guess.filter { target.contains($0) }: guess 배열의 각 요소가 target 배열에 포함되어 있는지 확인합니다. 예를 들어, guess가 [1, 3, 2]이고 target이 [1, 2, 3]일 때, target에 포함된 요소는 [1, 3, 2]입니다.
  • .count: guess 배열에서 target에 포함된 요소의 개수를 셉니다. 이 경우, target에 포함된 요소의 수는 3입니다.
  • - strikes: 스트라이크 개수를 뺍니다. 볼의 수는 3 - 1 = 2가 됩니다.

예제

target = [1, 2, 3]과 guess = [1, 3, 2]일 경우:

  • zip(target, guess): [(1, 1), (2, 3), (3, 2)]
  • 스트라이크: [(1, 1)] -> 1 스트라이크
  • guess.filter { target.contains($0) }: [1, 3, 2] -> 3
  • 볼: 3 - 1 = 2 -> 2 볼

따라서, 결과는 (strikes: 1, balls: 2)가 됩니다.


사용한 고차함수 및 메서드

let inputNum = getValue.compactMap { $0.wholeNumberValue }

  • Map : map은 기존 데이터 변형 시 사용. 그러나 기존 데이터는 변형되지 않고 새로운 컬렉션 생성함. 
  • compactMap : map과 비슷한 메서드지만 Map은 옵셔널 그대로 반환하고 compactmap은 옵셔널 값을 강제로 벗겨줌
  • wholeNumberValue : Character를 Int로 변환시킬 때 사용하는 메서드(단, 0이상의 자연수만 변환 가능. 음수 값 사용 X)

let strikes = zip(target, user).filter { $0 == $1 }.count

  • filter : 기존 컨테이너 요소 중 조건에 만족하는 새로운 컨테이너를 만들어 반환(내부에서 if를 사용하는 것과 같으며 이중 filter 사용 가능)

'App 개발 > Xcode' 카테고리의 다른 글

[UIKit] 데이터 값 다른 뷰로 전달하기  (0) 2024.06.03
[Xcode] Navigator Area 이해하기  (0) 2024.05.28
Xcode 단축어 모음  (0) 2024.05.27