금일은 숫자야구 문제를 더 푸는 시간을 가졌다.
BaseballGame.Swift
// BaseballGame.Swift
import Foundation
class BaseballGame {
private var targetNumber: [Int]
private var attempts: Int
init() {
self.targetNumber = BaseballGame.generateRandomNumber()
self.attempts = 0
}
// 랜덤 3자리 숫자 생성
private static func generateRandomNumber() -> [Int] {
var numbers = Array(0...9)
var result: [Int] = []
// 첫 번째 숫자는 0이 아닌 숫자여야 함
let firstNum = Int.random(in: 1...9)
result.append(firstNum)
numbers.remove(at: firstNum)
// 나머지 두 숫자 선택
for _ in 0..<2 {
let index = Int.random(in: 0..<numbers.count)
result.append(numbers[index])
numbers.remove(at: index)
}
return result
}
// 사용자 입력값 검증
private func validateInput(_ input: String) -> [Int]? {
guard input.count == 3,
let number = Int(input),
number >= 100 && number <= 999 else {
return nil
}
let digits = input.map { Int(String($0))! }
// 중복된 숫자가 있는지 확인
guard Set(digits).count == 3 else {
return nil
}
return digits
}
// 스트라이크와 볼 계산
private func checkNumbers(guess: [Int]) -> (strikes: Int, balls: Int) {
var strikes = 0
var balls = 0
for i in 0..<3 {
if guess[i] == targetNumber[i] {
strikes += 1
} else if targetNumber.contains(guess[i]) {
balls += 1
}
}
return (strikes, balls)
}
// 게임 진행을 위한 메서드
func makeGuess(_ inputNumber: String) -> GameResult {
guard let guess = validateInput(inputNumber) else {
return .invalidInput
}
attempts += 1
let result = checkNumbers(guess: guess)
if result.strikes == 3 {
return .gameWon(attempts: attempts)
}
return .ongoing(strikes: result.strikes, balls: result.balls)
}
// 게임 결과를 나타내는 열거형
enum GameResult {
case invalidInput
case ongoing(strikes: Int, balls: Int)
case gameWon(attempts: Int)
}
}
main.Swift
import Foundation
// 게임 실행
func playGame() {
print("숫자야구 게임을 시작합니다.")
let game = BaseballGame()
while true {
print("3자리 숫자를 입력하세요: ", terminator: "")
guard let input = readLine() else { continue }
let result = game.makeGuess(input)
switch result {
case .invalidInput:
print("올바른 3자리 숫자를 입력해주세요. (중복되지 않은 숫자)")
case .ongoing(let strikes, let balls):
print("\(strikes)스트라이크 \(balls)볼")
case .gameWon(let attempts):
print("축하합니다! \(attempts)번 만에 맞추셨습니다.")
return
}
}
}
// 게임 시작
playGame()
해당부분은 게임을 시작 및 프린트문으로 유저에게 보여주는 main.Swift파일과 게임로직을 실행하는 BaseballGame.Swift파일 두개로 나누어서 작성했다.
BaseballGame.Swift 수정본
import Foundation
class BaseballGame {
private var targetNumber: [Int]
private var attempts: Int
init() {
self.targetNumber = BaseballGame.generateRandomNumber()
self.attempts = 0
}
// 랜덤 3자리 숫자 생성 - 개선된 버전
private static func generateRandomNumber() -> [Int] {
// 1-9까지의 숫자로 배열 생성 (첫 자리는 0이 올 수 없으므로)
var availableNumbers = Array(1...9)
// 첫 번째 숫자 선택 및 제거
let firstIndex = Int.random(in: 0..<availableNumbers.count)
let firstNumber = availableNumbers.remove(at: firstIndex)
// 두 번째, 세 번째 숫자를 위해 0 추가
availableNumbers.append(0)
// 두 번째 숫자 선택 및 제거
let secondIndex = Int.random(in: 0..<availableNumbers.count)
let secondNumber = availableNumbers.remove(at: secondIndex)
// 세 번째 숫자 선택
let thirdIndex = Int.random(in: 0..<availableNumbers.count)
let thirdNumber = availableNumbers[thirdIndex]
return [firstNumber, secondNumber, thirdNumber]
}
// 사용자 입력값 검증
private func validateInput(_ input: String) -> [Int]? {
guard input.count == 3,
let number = Int(input),
number >= 100 && number <= 999 else {
return nil
}
let digits = input.map { Int(String($0))! }
// 중복된 숫자가 있는지 확인
guard Set(digits).count == 3 else {
return nil
}
return digits
}
// 스트라이크와 볼 계산
private func checkNumbers(guess: [Int]) -> (strikes: Int, balls: Int) {
var strikes = 0
var balls = 0
for i in 0..<3 {
if guess[i] == targetNumber[i] {
strikes += 1
} else if targetNumber.contains(guess[i]) {
balls += 1
}
}
return (strikes, balls)
}
// 게임 진행을 위한 메서드
func makeGuess(_ inputNumber: String) -> GameResult {
guard let guess = validateInput(inputNumber) else {
return .invalidInput
}
attempts += 1
let result = checkNumbers(guess: guess)
if result.strikes == 3 {
return .gameWon(attempts: attempts)
}
return .ongoing(strikes: result.strikes, balls: result.balls)
}
// 디버깅을 위한 정답 확인 메서드 (필요시 사용)
func getTargetNumber() -> String {
return targetNumber.map(String.init).joined()
}
// 게임 결과를 나타내는 열거형
enum GameResult {
case invalidInput
case ongoing(strikes: Int, balls: Int)
case gameWon(attempts: Int)
}
}
generateRandomNumber이라는 함수명을 통해서 첫자리에 0이 안오게 로직을 짰다.
// 예시
환영합니다! 원하시는 번호를 입력해주세요
1. 게임 시작하기 2. 게임 기록 보기 3. 종료하기
게임 메뉴 시스템 추가
import Foundation
/// 게임 기록을 저장하는 구조체
struct GameRecord {
let date: Date
let attempts: Int
}
/// 게임의 전체 기록을 관리하는 클래스
class GameHistory {
private var records: [GameRecord] = []
/// 새로운 게임 기록 추가
func addRecord(attempts: Int) {
records.append(GameRecord(date: Date(), attempts: attempts))
}
/// 모든 게임 기록 조회
func showRecords() {
if records.isEmpty {
print("아직 게임 기록이 없습니다.")
return
}
print("\n[ 게임 기록 ]")
print("날짜\t\t\t시도 횟수")
print("----------------------------------------")
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
for record in records {
print("\(dateFormatter.string(from: record.date))\t\(record.attempts)회")
}
print("----------------------------------------")
}
}
/// 메뉴 옵션을 나타내는 열거형
enum MenuOption: Int {
case startGame = 1
case showRecords = 2
case exit = 3
}
/// 게임 메뉴를 표시하고 사용자 입력을 받는 함수
func showMenu() -> MenuOption? {
print("\n[ 숫자 야구 게임 ]")
print("1. 게임 시작하기")
print("2. 게임 기록 보기")
print("3. 종료하기")
print("선택해주세요: ", terminator: "")
guard let input = readLine(),
let number = Int(input),
let option = MenuOption(rawValue: number) else {
return nil
}
return option
}
/// 숫자야구 게임을 실행하는 메인 함수
func playGame() -> Int? {
print("\n게임을 시작합니다!")
print("서로 다른 3자리 숫자를 맞혀보세요.")
print("각 숫자는 0과 9 사이이며, 첫 번째 자리는 0이 될 수 없습니다.")
let game = BaseballGame()
// 테스트/디버깅용 정답 출력
print("정답: \(game.getTargetNumber())")
while true {
print("\n3자리 숫자를 입력하세요: ", terminator: "")
guard let input = readLine() else { continue }
let result = game.makeGuess(input)
switch result {
case .invalidInput:
print("올바른 3자리 숫자를 입력해주세요. (중복되지 않은 숫자)")
case .ongoing(let strikes, let balls):
if strikes == 0 && balls == 0 {
print("아웃!")
} else {
print("\(strikes)스트라이크 \(balls)볼")
}
case .gameWon(let attempts):
print("축하합니다! \(attempts)번 만에 맞추셨습니다.")
return attempts
}
}
}
// 메인 프로그램 실행
let gameHistory = GameHistory()
while true {
// 메뉴 표시 및 사용자 입력 받기
guard let option = showMenu() else {
print("잘못된 입력입니다. 1-3 사이의 숫자를 입력해주세요.")
continue
}
// 선택된 메뉴 실행
switch option {
case .startGame:
// 게임 실행 및 결과 저장
if let attempts = playGame() {
gameHistory.addRecord(attempts: attempts)
}
case .showRecords:
gameHistory.showRecords()
case .exit:
print("\n게임을 종료합니다.")
exit(0)
}
}
맨처음 playGame함수안에 int값을 받는것을 기준으로 각각 1,2,3 값을 집어넣게 만들었으며
// 테스트/디버깅용 정답 출력
print("정답: (game.getTargetNumber())")
코드를 집어넣어서 각 문제간에 빠르게 확인을 할 수 있게 집어넣었다.
// 예시
환영합니다! 원하시는 번호를 입력해주세요
1. 게임 시작하기 2. 게임 기록 보기 3. 종료하기
2 // 2번 게임 기록 보기 입력
< 게임 기록 보기 >
1번째 게임 : 시도 횟수 - 14
2번째 게임 : 시도 횟수 - 9
3번째 게임 : 시도 횟수 - 12
게임메뉴 세분화
import Foundation
/// 게임 기록을 저장하는 구조체
struct GameRecord {
let attempts: Int
}
/// 게임의 전체 기록을 관리하는 클래스
class GameHistory {
private var records: [GameRecord] = []
/// 새로운 게임 기록 추가
func addRecord(attempts: Int) {
records.append(GameRecord(attempts: attempts))
}
/// 모든 게임 기록 조회
func showRecords() {
if records.isEmpty {
print("\n아직 게임 기록이 없습니다.")
return
}
print("\n< 게임 기록 보기 >")
for (index, record) in records.enumerated() {
print("\(index + 1)번째 게임 : 시도 횟수 - \(record.attempts)")
}
print()
}
}
/// 메뉴 옵션을 나타내는 열거형
enum MenuOption: Int {
case startGame = 1
case showRecords = 2
case exit = 3
}
/// 게임 메뉴를 표시하고 사용자 입력을 받는 함수
func showMenu() -> MenuOption? {
print("\n[ 숫자 야구 게임 ]")
print("1. 게임 시작하기")
print("2. 게임 기록 보기")
print("3. 종료하기")
print("선택해주세요: ", terminator: "")
guard let input = readLine(),
let number = Int(input),
let option = MenuOption(rawValue: number) else {
return nil
}
return option
}
/// 숫자야구 게임을 실행하는 메인 함수
func playGame() -> Int? {
print("\n게임을 시작합니다!")
print("서로 다른 3자리 숫자를 맞혀보세요.")
let game = BaseballGame()
// 정답 확인하기 (테스트용) 추후 삭제예정
print("정답: \(game.getTargetNumber())")
while true {
print("\n3자리 숫자를 입력하세요: ", terminator: "")
guard let input = readLine() else { continue }
let result = game.makeGuess(input)
switch result {
case .invalidInput:
print("올바른 3자리 숫자를 입력해주세요. (중복되지 않은 숫자)")
case .ongoing(let strikes, let balls):
if strikes == 0 && balls == 0 {
print("아웃!")
} else {
print("\(strikes)스트라이크 \(balls)볼")
}
case .gameWon(let attempts):
print("축하합니다! \(attempts)번 만에 맞추셨습니다.")
return attempts
}
}
}
// 메인 프로그램 실행
let gameHistory = GameHistory()
while true {
// 메뉴 표시 및 사용자 입력 받기
guard let option = showMenu() else {
print("잘못된 입력입니다. 1-3 사이의 숫자를 입력해주세요.")
continue
}
// 선택된 메뉴 실행
switch option {
case .startGame:
// 게임 실행 및 결과 저장
if let attempts = playGame() {
gameHistory.addRecord(attempts: attempts)
}
case .showRecords:
gameHistory.showRecords()
case .exit:
print("\n게임을 종료합니다.")
exit(0)
}
}