Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 59 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,71 +1,72 @@
# 숫자 야구 게임 과제 (Week 2)
숫자 야구 게임은 1에서 9까지의 서로 다른 3개의 숫자를 맞추는 게임입니다. <br>
각 레벨마다 기능이 확장되며, 팀원들이 협업하여 매주 주어진 과제를 해결해 나갑니다.
# ⚾️ 숫자 야구 게임
## 개요
- 숫자 야구 게임은 컴퓨터가 생성한 임의의 숫자 세 개를 맞추는 게임입니다. 사용자가 입력한 숫자와 자리 수를 비교하여 정답 여부를 판별합니다.
- 개발 도구 : Xcode 16
- 개발 기간 : 2024년 11월 4일 ~ 11월 8일
- 개발 인원 : Jeff

# 📝 협업 규칙
### 레포지토리 설정 및 브랜치 관리
**1** **Fork로 가져오기**: 각 팀원은 레포지토리를 Fork하여 자신의 개인 레포지토리로 가져옵니다.<br>
**2** **브랜치 생성**: Fork한 개인 레포지토리에서 각자의 이름을 딴 브랜치를 생성합니다.<br>
**3** **Pull Request**: 과제를 마친 후, 각자의 브랜치로 Pull Request를 생성하여 코드 리뷰를 요청합니다. 모든 팀원이 Pull Request에 코멘트를 달고 피드백을 제공합니다. <br>
**4** **수정 및 Merge**: 피드백을 반영하여 수정하고, 팀원들의 동의를 얻은 후 merge를 진행합니다. <br>
# 코드 파일 구조
* base.swift: 게임의 전반적인 흐름을 구현하는 클래스
* checkAnswer.swift: 유저의 값과 정답 값을 비교하는 클래스
* ErrorHandling.swift: 에러를 처리하를 정의한 enum
* GameRecord.swift: 게임 기록을 보여주기 위한 클래스
* GetAnswer.swift: 랜덤으로 정답 값을 생성하는 클래스
* GetUserValue.swift: 유저의 입력 값을 받아오고 에러를 정의하는 클래스
* StartGame.swift: 앱의 전반적인 흐름을 구현하는 클래스
* main.swift: 앱의 메인 진입점

이 과정을 통해 서로의 코드에 대해 이해를 높이고, “왜 이렇게 작성했는지”에 대한 질문과 답변을 주고받으며 과제를 진행합니다.
# 📂 코드 파일 구조
* main.swift: 게임의 메인 진입점으로, 레벨을 선택하고 시작할 수 있도록 구성되어 있습니다. startGame() 함수가 게임의 시작을 담당합니다.
* Lv_1.swift ~ Lv_6.swift: 각 레벨별 요구사항에 맞게 구현된 파일입니다. 각 파일에는 해당 레벨의 기능을 구현하는 함수가 포함되어 있습니다.
---

⠀📜 구현 가이드
## 게임 레벨별 구성
### Lv.1
**1 ~ 9 까지의 서로 다른 임의의 수를 3개 생성**
- **Point & 개발 과정**
- `random` 메서드를 이용하여 범위를 설정해서 임의의 수 생성
- **Set**을 이용해 중복값이 없는 3자리 수를 만든 뒤 배열에 저장하여 관리

### main.swift
Command Line Tool 프로젝트에서는 하나의 `main.swift` 파일에서만 프로그램을 시작할 수 있습니다. 따라서 각 레벨별 기능을 별도의 파일로 구현한 후, `main.swift` 파일에서 해당 레벨의 함수를 호출하여 실행하도록 구성합니다.
### Lv.2
**유저 입력을 받아 정답과 비교하여 스트라이크/볼 판별**
- **Point & 개발 과정**
- **유저의 입력 받기**: `readLine`으로 값을 받아 배열에 저장
- **에러 처리**: `do-try-catch`와 `enum`을 활용한 커스텀 에러 처리
- **정답과 비교**: 두 배열의 같은 자리 수는 **strike**, 위치만 다른 경우 **ball**로 판별
- **게임 종료 조건**: 3 스트라이크로 맞췄을 때 종료

```swift
import Foundation
### Lv.3
**0 ~ 9 까지의 서로 다른 3자리 수, 맨 앞에 0 금지**
- **Point & 개발 과정**
- Lv.1에서 사용한 정답 생성 메서드 수정
- 랜덤 값이 첫 번째 자리일 때 0이 올 수 없도록 조건 추가

func startGame() {
print("레벨을 선택하세요 (1, 2, 3, 4, 5, 6):")

if let input = readLine(), let level = Int(input) {
switch level {
case 1:
levelOne()
case 2:
levelTwo()
case 3:
levelThree()
case 4:
levelFour()
case 5:
levelFive()
case 6:
levelSix()
default:
print("유효하지 않은 레벨입니다. 1~6까지를 선택해주세요.")
}
} else {
print("잘못된 입력입니다.")
}
}

// 게임 시작
startGame()
```
* startGame() 함수에서 게임의 레벨을 선택하여 시작할 수 있도록 구성합니다.
* 사용자가 입력한 레벨 번호에 따라 해당 레벨의 함수를 호출하여 게임을 진행합니다.
### Lv.4
**초기 안내문구와 메뉴 선택 기능 추가**
- **Point & 개발 과정**
- **초기 화면 구성**: 프로그램 시작 시 안내문구 출력하여 1, 2, 3번 기능 제공
- **게임 종료 후 초기화면 이동**: 정답을 맞췄을 때 초기화면으로 돌아가도록 수정
- `while` 문과 `switch` 문으로 옵션 선택 가능하게 구현


### 각 레벨 파일 (Lv_1.swift ~ Lv_6.swift) - 구현 파일
### Lv.5
**게임 기록 기능 추가**
- **Point & 개발 과정**
- **게임 횟수와 시도 횟수 기록**: 게임 횟수와 한 게임당 시도 횟수를 기록해 출력
- **게임 기록 배열**: 게임 종료 후 시도 횟수를 배열에 추가하여 기록 유지

**Lv_1.swift**
### Lv.6
**종료하기와 옵션 범위 외 입력 처리 추가**
- **Point & 개발 과정**
- **종료 기능 구현**: 3번 선택 시 앱 종료
- **입력 범위 검증**: `readLine`으로 받은 값을 옵셔널 바인딩해 1~3 사이 값이 아닐 경우 오류 메시지 출력

---

```swift
import Foundation
## 주요 기능

func levelOne() {
// 1. 정답을 생성하는 로직을 추가합니다.
// 2. 유저가 정답을 맞출 때까지 반복해서 입력을 받습니다.
// 3. 입력값이 유효한지 검사하고 힌트를 제공하는 기능을 구현합니다.
}
```
- **랜덤 숫자 생성**: 중복되지 않는 세 자리 수를 랜덤으로 생성
- **숫자 비교 및 판별**: 입력한 숫자와 정답을 비교하여 스트라이크와 볼의 개수를 판단
- **기록 관리**: 시도 횟수와 게임 횟수를 기록하여, 기록 보기 기능을 구현
- **에러 처리**: 입력한 갑이 올바르지 않은 경우 에러를 처리하여 사용자가 이해하도록 개선

각 레벨별로 구현하시면 됩니다.
## 🎯 트러블슈팅
[트러블 슈팅과 자세한 과정](https://velog.io/@jeffapd_/swiftproject%EC%95%BC%EA%B5%AC%EA%B2%8C%EC%9E%84#-lv1)
52 changes: 52 additions & 0 deletions Week2-BaseballGame/Week2-BaseballGame/Base.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@


class BaseBallGame {
let answer = GetAnswer()
let userValue = GetUserValue()
lazy var checkAnswer = CheckAnswer(getAnswer: answer, getUserValue: userValue)
static var endPoint = 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 변수를 static으로 선언하신 이유가 궁금합니다!



// 게임 초기화
func settingGame() {
// 정답 배열 초기화
answer.answerArray.removeAll()
checkAnswer.strike = 0
// 정답 생성
answer.getAnswser()
print("< ⚾️ 게임을 시작합니다. >")
}


// 게임 시작
func startGame() {
// 게임 횟수를 카운트, 도전 횟수 초기화
GameRecord.gameCount += 1
GameRecord.tryCount = 0

// User입력값 초기화, 값 입력 받기(정답이 맞을때 까지 반복)
while checkAnswer.strike != answer.answerArray.count {
userValue.initUserValue()
// do catch를 이용한 에러처리
do {
try userValue.inputUserValue()
checkAnswer.checkAnswer()
checkAnswer.printResult()
GameRecord.tryCount += 1 // try 횟수 카운트
} catch ErrorHandling.emptyInput {
print(" 🚫 값을 입력해주세요.")
} catch ErrorHandling.wrongInput {
print(" 🚫 숫자 이외의 값을 입력하셨습니다.")
} catch ErrorHandling.duplicateNumber {
print(" 🚫 중복된 값을 입력하셨습니다.")
} catch ErrorHandling.outOfRange {
print(" 🚫 3자릿수를 입력해주세요")
} catch {
print(" 🚫 알 수 없는 오류")
}
}
GameRecord.tryRecordArray.append(GameRecord.tryCount) // 게임 종료 후 try횟수 배열에 추가
BaseBallGame.endPoint = 0 // 게임이 종료를 표시
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class CheckAnswer {

func checkAnswer() {
// 유저와 정답 배열을 셋으로 다시 생성(같은 수(ball)가 몇개인지 체크하기 위해)
let userArrayToSet:Set<Int> = Set(getUserValue.userArray)
let answerArrayToSet:Set<Int> = Set(getAnswer.answerArray)
let userArrayToSet:Set<Int> = Set(getUserValue.userArray)
let answerArrayToSet:Set<Int> = Set(getAnswer.answerArray)


// 입력한 유저 값이 정답에 몇개가 중복되는지를 체크 후 set의 갯수를 ball의 수로 지정, strike수 초기화(중복되는걸 방지)
Expand All @@ -34,10 +34,10 @@ class CheckAnswer {
func printResult() {
if ball == 0 && strike == 0 {
// ball과 strike 수가 없는 경우 아웃
print("OUT")
print("[ OUT ]")
} else if strike == getAnswer.answerArray.count {
// strike 수가 정답의 갯수와 같은 경우
print("정답입니다.")
print(" 🏆 정답입니다. ")
} else {
print("[ \(strike) S, \(ball) B ]")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
enum ErrorHandling: Error {
case wrongInput
case duplicateNumber
case inputZero
case outOfRange
case emptyInput
}
15 changes: 15 additions & 0 deletions Week2-BaseballGame/Week2-BaseballGame/GameRecord.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

// 게임 기록을 위한 클래스
class GameRecord {
static var gameCount = 0
static var tryCount = 0
static var tryRecordArray:[Int] = []

// 기록한 값을 출력
func showRecord () {
for i in 0..<GameRecord.gameCount {
print("\(i + 1)번째 게임 : 시도 횟수 - \(GameRecord.tryRecordArray[i])")
}
}

}
25 changes: 25 additions & 0 deletions Week2-BaseballGame/Week2-BaseballGame/GetAnswer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

// 정답 값을 생성하기 위한 클래스
class GetAnswer {
// 정답 값을 넣을 배열 생성
var answerArray:[Int] = []

// 랜덤값 생성 메서드
func getRandomValue() -> Int {
return Int.random(in: 0...9)
}

// 정답 생성 메서드
func getAnswser() {
// 중복 값을 제거해주고 3개의 임의의 수를 저장(첫번째 자리에 "0"이 오면 제거)
while answerArray.count < 3 {
let randomValue = getRandomValue()
if !answerArray.contains(randomValue) {
answerArray.append(randomValue)
}
if answerArray[0] == 0 {
answerArray.removeFirst()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,14 @@ class GetUserValue {
guard (Int(input) != nil) else {
throw ErrorHandling.wrongInput
}
guard !input.contains("0") else {
throw ErrorHandling.inputZero
}
guard let intValue = Int(input), (100...999).contains(intValue) else {
throw ErrorHandling.outOfRange
}
guard Set(input).count == 3 else {
throw ErrorHandling.duplicateNumber
}
// 유저 입력 값을 배열에 추가
let result = input.map { Int(String($0))! }
userArray.append(contentsOf: result)

print(userArray)
}
}

This file was deleted.

This file was deleted.

This file was deleted.

Loading