[TIL] 숫자 야구 게임 lv.1 ~ lv.2

한철희·2024년 3월 14일
1

TIL

목록 보기
11/57
post-thumbnail

벌써 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도 최대한 시도 해보고 글로 남겨야겠다

profile
초보 개발자 살아남기

0개의 댓글