Swift 문법을 응용해서 숫자 야구 게임을 만들어봅니다!
숫자 야구 게임은 두 명이 즐길 수 있는 추리 게임으로, 상대방이 설정한 3자리의 숫자를 맞히는 것이 목표입니다. 각 자리의 숫자와 위치가 모두 맞으면 '스트라이크', 숫자만 맞고 위치가 다르면 '볼'로 판정됩니다. 예를 들어, 상대방의 숫자가 123일 때 132를 추리하면 1스트라이크 2볼이 됩니다. 이러한 힌트를 활용하여 상대방의 숫자를 추리해 나가는 게임입니다.
Lv1. 정답이 될 수 있는 숫자의 조건
- 정답은 랜덤으로 만듭니다.(1에서 9까지의 서로 다른 임의의 수 3자리)
// 정답 숫자 랜덤 생성
func createAnswer() -> [String] {
var numSet: Set<String> = [] // Set은 중복 허용 안 함, 순서 없음
while numSet.count < 3 { // Set의 개수가 3개가 될 때까지 랜덤 숫자 추가
numSet.insert(String(Int.random(in: 1...9))) // 1~9까지 랜덤 숫자를 생성하여 numSet에 추가 (Set은 중복 허용 안 하므로 중복 방지)
}
return Array(numSet)
}
- Set은 Array와 다르게 중복을 허용하지 않고 순서를 보장하지 않는다
- 1~9까지의 서로 다른 임의의 수를 생성하기 위해 Set을 사용하여 중복 값이 없도록 구현했다
Lv3. 정답이 될 수 있는 숫자의 조건
- 정답이 되는 숫자를 0에서 9까지의 서로 다른 3자리의 숫자로 바꿔주세요
- 맨 앞자리에 0이 오는 것은 불가능합니다
- 092 → 불가능
- 870 → 가능
- 300 → 불가능
- 맨 앞자리에 0이 오는 것은 불가능합니다
첫 번째 시도: Set의 첫 번째 인덱스의 값(백의 자리 수)이 0이라면 Continue
// 정답 숫자 랜덤 생성
func createAnswer() -> [String] {
var numSet: Set<String> = [] // Set은 중복 허용 안 함, 순서 없음
while numSet.count < 3 { // Set의 개수가 3개가 될 때까지 랜덤 숫자 추가
let num = Int.random(in: 0...9)
if numSet.isEmpty && num == 0 { continue } // 첫자리가 0이면 continue
numSet.insert(String(num)) // 0~9까지 랜덤 숫자를 생성하여 numSet에 추가 (Set은 중복 허용 안 하므로 중복 방지)
}
return Array(numSet)
}
→ 문제점 발생
Set은 순서가 없기 때문에 첫 번째 수가 0이 안 되도록 필터링을 해도 return 될 때 순서에는 0이 앞으로 올 수 있었다
예를 들어,
numSet이 비어있을 때 첫 번째 자리 수에 0이 오면 필터링을 한다
하지만, 비어있지 않다면 0을 삽입할 수 있다
Set은 순서를 보장하지 않기 때문에 return 될 때는 첫 번째 인덱스가 아니었던 0이 첫 번째 인덱스로 바뀌고 return 될 수 있다
- 초기 numSet: Set<String> = [] → 비어 있음
- 랜덤 수 생성: num = 0
- numSet이 비어있고, num == 0 이므로 continue
- 랜덤 수 생성: num = 3
- numSet이 비어있지만, num != 0 이므로 inset → numSet = [3]
- 랜덤 수 생성: num = 0
- numSet이 비어있지 않으므로 insert → numSet = [3, 0] or [0, 3] ⇒ Set은 순서가 보장되지 않음
- 랜덤 수 생성: num = 6
- numSet이 비어있지 않으므로 insert → numSet = [3, 0, 6] or [6, 0, 3] or … ⇒ Set은 순서가 보장되지 않음
- return 되는 Array(numSet)이 첫 번째 인덱스의 값이 0이 될 수 있는 가능성이 존재한다
두 번째 시도: 배열로 변경
// 정답 숫자 랜덤 생성
func createAnswer() -> [String] {
var numArr: [String] = [] // 자릿수를 저장할 배열
while numArr.count < 3 { // 배열의 크기가 3개가 될 때까지 랜덤 숫자 추가
let num = String(Int.random(in: 0...9)) // 0~9까지의 랜덤 숫자 생성
if (numArr.isEmpty && num == "0") || numArr.contains(num) { continue } // 첫자리가 0이거나 이미 배열에 포함된 수(중복)이면 continue
numArr.append(num) // 첫자리가 0이 아니고 중복된 수도 아니면 배열에 삽입
}
return numArr
}
- 0~9까지의 숫자를 랜덤 생성하고
- 첫자리가 0이거나 이미 배열에 포함된 수(중복)이면 continue
- numArr의 크기가 3개라면 return
세 번째 시도: Set으로 중복 검사 후, Array 배열에 삽입
- 코드 리뷰를 통해 팀원 분에게 조언을 듣고 수정했다
- Set을 통해 중복 검사를 한 후, 따로 Array 배열을 만들어 Set 과 동일하게 만들어주면 따로 contains 메서드를 통해 중복 검사를 진행하지 않게 되어 시간 복잡도를 줄일 수 있을 거 같다
//MARK: 코드리뷰 후 변경 -> 순서가 있는 배열을 따로 생성
func createAnswer() -> [String] {
var numArr = [String]() // 실제 정답을 저장할 배열
var numSet: Set<String> = [] // Set은 중복 허용 안 함, 순서 없음 -> 중복검사로만 사용
while numSet.count < 3 { // Set의 개수가 3개가 될 때까지 랜덤 숫자 추가
let num = Int.random(in: 0...9)
if numSet.isEmpty && num == 0 { continue } // 첫자리가 0이면 continue
numSet.insert(String(num)) // 0~9까지 랜덤 숫자를 생성하여 numSet에 추가 (Set은 중복 허용 안 하므로 중복 방지)
numArr.append(String(num)) // 실제 정답을 저장할 배열에 숫자 추가
}
return Array(numSet)
}
- 팀원 분의 조언으로 최근 시간 복잡도에 대한 고민을 항상 생각해보게 되었다
'Today I Learn' 카테고리의 다른 글
Today I Learn: Swift에서의 Copy On Write (COW) (0) | 2025.03.12 |
---|---|
Today I Learn: Swift에서의 연결 리스트 (0) | 2025.03.11 |
Today I Learn: UIAlertController에 TextField 추가 및 데이터 사용 (0) | 2025.03.07 |
Today I Learn: UILabel 내부 Padding 설정하기 (0) | 2025.03.06 |
Today I Learn (4) : UIButton.AddTarget 데이터 전달 문제 리팩토링 (0) | 2025.03.05 |