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에게 작성한 코드를 해석해서 자세히 설명해달라고 요청
자세한 설명
- inputNum 배열: digits는 사용자가 입력한 3자리 숫자를 각 자리별로 분리한 배열입니다. 예를 들어, 사용자가 123을 입력했다면 digits는 [1, 2, 3]이 됩니다.
- Set(inputNum): Set은 Swift의 컬렉션 타입 중 하나로, 중복된 요소를 허용하지 않습니다. Set(inputNum)는 배열 digits의 중복 요소를 제거한 집합을 만듭니다.
- 예: inputNum가 [1, 2, 3]일 경우 Set(inputNum)는 {1, 2, 3}입니다.
- 예: inputNum가 [1, 1, 2]일 경우 Set(inputNum)는 {1, 2}입니다.
- Set(inputNum).count: 중복을 제거한 후 남은 고유 요소의 개수를 세는 것. 만약 사용자가 중복된 숫자를 입력했다면, Set(inputNum).count는 원래의 inputNum.count보다 작아집니다.
- 예: inputNum가 [1, 2, 3]일 경우 Set(inputNum).count는 3입니다.
- 예: inputNum가 [1, 1, 2]일 경우 Set(inputNum).count는 2입니다.
동작 방식 설명
- 입력받기: readLine()을 통해 사용자 입력을 받습니다.
- 숫자 변환: compactMap { $0.wholeNumberValue }를 사용하여 각 문자를 숫자로 변환합니다.
- 중복 확인: inputNum.count == 3와 Set(inputNum).count == 3를 사용하여 입력된 숫자가 정확히 3개이고, 중복되지 않는지 확인합니다.
이 조건을 통해 사용자가 중복되지 않는 3자리 숫자를 입력했는지 확인할 수 있습니다.
세부 동작 설명
1. 스트라이크 계산
- 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. 볼 계산
- 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 |