벌써 2주차 개인과제를 할 시간이다
이번에는 숫자 야구 게임을 구현해보는 과제를 받았다
이름부터 벌써 저번 과제보다 난이도가 상승했음이 느껴진다
일단 시작해보자!
// main.swift 파일
// 프로젝트 생성시 자동 생성됨
let game = BaseballGame()
game.start() // BaseballGame 인스턴스를 만들고 start 함수를 구현하기
// BaseballGame.swift 파일 생성
class 혹은 struct {
func start() {
let answer = makeAnswer() // 정답을 만드는 함수
}
func makeAnswer() -> Int {
// 함수 내부를 구현하기
}
}
일단 이건 처음에 제공받은 뼈대 코드다.
음 얼추 보아하니 이번엔 같은 파일내 다른 클래스가 아니라
아예 다른 파일에 생성된 클래스를 호출하는 방식으로 진행하는 것 같다.
그리고 사용자 입력도 readLine()
을 이용해서 키보드 입력을 받는 방식으로 진행한다.
이제 lv.1의 요구사항을 살펴보자
- 1에서 9까지의 서로 다른 임의의 수 3개를 정하고 맞추는 게임입니다
- 정답은 랜덤으로 만듭니다.(1에서 9까지의 서로 다른 임의의 수 3자리)
음 일단
1. 랜덤한 수 생성하기
2. 사용자로부터 입력받기
3. 정답여부 판별하기
정도로 과정이 생각된다.
랜덤한 수는 swift의 Int.random(in: 0...10)
을 사용해서 생성했다
arc4random_uniform( )
함수도 있긴한데 범위 설정 면에서 전자가 나은거같아서 사용했다.
func makeAnswer() -> Int {
let randomNumber = Int.random(in: 000..<999) // 0부터 99까지의 랜덤 정수 생성
print(randomNumber)
return randomNumber
}
처음에는 이런식으로 작성했다가
3자리수가 서로 다른 수여야 된다는 생각이 들어서
급하게 수정했다 ex) 123, 586, 436
func makeAnswer() -> Int {
// 함수 내부를 구현하기
var randomNumber: Int
repeat {
let hundreds = Int.random(in: 1..<10) * 100
let tens = Int.random(in: 0..<10) * 10
let units = Int.random(in: 0..<10)
randomNumber = hundreds + tens + units
} while Set(String(randomNumber)).count < 3 // 중복된 숫자가 있는 경우 다시 생성
// print(randomNumber) // 값 확인용 출력
return randomNumber
}
각 자리수를 따로 구한다음 합치는 방식으로 했다
그리고 중복된 숫자를 없애도록 Set
을 이용했다
그리고 입력값의 정답 여부를 판단하는 함수
func start() {
let answer = makeAnswer() // 정답을 만드는 함수
while true {
let input = Int(readLine()!) // 사용자 입력받기
if input == answer {
print("정답입니다")
break
} else {
print("오답입니다. 다시 해보세요")
}
}
}
이렇게 lv.1은 마무리했다
이제 lv.2를 해보자
전에는 lv.1~4 중에 3까지 필수였던 것과 달리
이번에는 lv.1~6중에서 2까지만 필수 구현이다
lv.2 요구 사항을 보자
- 정답을 맞추기 위해 3자리수를 입력하고 힌트를 받습니다
- 힌트는 야구용어인 볼과 스트라이크입니다.
- 같은 자리에 같은 숫자가 있는 경우 스트라이크, 다른 자리에 숫자가 있는 경우 볼입니다
- ex) 정답 : 456 인 경우
- 435를 입력한 경우 → 1스트라이크 1볼
- 357를 입력한 경우 → 1스트라이크
- 678를 입력한 경우 → 1볼
- 123를 입력한 경우 → Nothing
- 만약 올바르지 않은 입력값에 대해서는 오류 문구를 보여주세요
어우 뭔가 엄청 많다.
일단.. 정리해보자
1. 올바르지 않은 입력값에 대한 처리
2. 부분 정답에 대한 스트라이크, 볼 출력
이 정도로 추가 기능 구현이 예상된다.
일단 makeanswer
함수부터 보자
private func makeAnswer() -> [Int] {
var randomNumber: [Int]
repeat {
let hundreds = Int.random(in: 1..<10) // 범위 설정으로 0이 오는것을 방지
var tens = Int.random(in: 0..<10)
var units = Int.random(in: 0..<10)
while tens == hundreds {
tens = Int.random(in: 0..<10)
}
while units == hundreds || units == tens {
units = Int.random(in: 0..<10)
}
randomNumber = [hundreds, tens, units]
} while Set(randomNumber).count < 3
// print(randomNumber) // 값 확인용
return randomNumber
}
한번에 3자리수를 생성하던 것에서 각 자리수를 따로 생성하는 것을 변경했다
그리고 부분정답 처리를 위해 배열로 바꿨다
다음은 부분 정답 처리를 위한 함수
private func checkGuess(_ guess: [Int]) -> (Int, Int) {
var strikes = 0
var balls = 0
for (index, digit) in guess.enumerated() {
if digit == answer[index] {
strikes += 1
} else if answer.contains(digit) {
balls += 1
}
}
return (strikes, balls)
}
크게 특별한 것은 없고 자리수와 입력이 일치하는 경우는 strikes
를 그냥 포함만 하는경우는 balls
를 증가하도록 작성했다
사용자로부터 값을 입력받고 동작을 수행하는 start
함수
func start() {
answer = makeAnswer()
while true {
print("숫자를 입력하세요")
guard let input = readLine(), input.count == 3 else { // 입력값이 3자리가 아닐 경우
print("올바르지 않은 입력값입니다.")
continue
}
// 숫자외의 값이 입력되었을 경우
if !input.allSatisfy({ $0.isNumber }) {
print("세 자리 숫자를 입력하세요.")
continue
}
let guess = input.compactMap { Int(String($0)) }
// 입력값에 0이 포함된 경우
if guess.contains(0) {
print("0은 사용할 수 없습니다. 다시 입력하세요.")
continue
}
if guess == answer {
print("정답입니다.")
break
} else {
let (strikes, balls) = checkGuess(guess)
if strikes == 0 && balls == 0 {
print("Nothing")
} else {
print("\(strikes)스트라이크 \(balls)볼")
}
}
}
}
잘못된 값을 입력 받았을 때 처리를 하다보니 if
문을 많이 쓰게됐다
같은 문구로 하니까 뭐가 잘못되서 처리를 한건지 몰라서
예제와 다르게 각각 다른 문구를 작성했다
Lv.1은 그나마 랜덤 수 생성 느낌이라서 할만했는데
Lv.2가 처리할 것도 많고 이래저래 시간을 엄청 썼다.
남는 시간에 Lv.3~6도 최대한 시도 해보고 글로 남겨야겠다