###### tags: `README`, `1주차-EeE조`
# iOS 커리어 스타터 캠프
### 숫자야구 프로젝트 저장소
## 목차
1. [제목](#1.)
2. [소개](#2.)
3. [팀원](#3.)
4. [타임라인](#4.)
5. [순서도(Flow Chart)](#5.)
6. [실행 화면(기능 설명)](#6.)
7. [트러블 슈팅](#7.)
8. [참고 링크](#8.)
9. [팀 회고](#9.)
<a id="1."></a>
## 1. 제목
#### 🛎️ EeE-e's 숫자야구게임 ⚾️
<a id="2."></a>
## 2. 소개
플레이어에게 1부터 9까지의 한 자리 숫자 중복없이 3개를 입력받아 지정된 숫자 3개와
자리와 숫자가 같으면 스트라이크, 동일 숫자가 포함되어 있으면 볼로 나타났을 때,
9번 시도 중에 3 스트라이크면 사용자가 승리하고, 아니면 컴퓨터가 승리하는 게임
<a id="3."></a>
## 3. 팀원
| [Karen 🐕](https://github.com/karenyang835) | [Serena 🐷](https://github.com/serena0720) | [Whales 🐋](https://github.com/WhalesJin) |
| :--------: | :--------: | :--------: |
| <Img src = "https://i.imgur.com/gwxTotR.png" width="150"/>| <Img src = "https://i.imgur.com/q0XdY1F.jpg" width="150"/>| <Img src = "https://i.imgur.com/wnhhCv9.jpg" width="150"/>|
<a id="4."></a>
## 4. 타임라인
**2023.04.24**
- 순서도 작성
**2023.04.25**
- 랜덤 숫자 및 사용자 숫자 생성 함수 정의
- Ball, Strike 개수 체크 함수 정의
- 게임 진행 함수 정의
**2023.04.26**
- 랜덤 숫자 및 사용자 숫자 생성 함수 중복 수정
**2023.04.27**
- 리뷰어의 피드백에 따른 코드 리팩토링 및 네이밍 수정
- 메뉴 선택 함수 정의
- 사용자 숫자 입력 함수 정의
- 게임 시작 함수 정의
- 지역변수를 전역변수로 리팩토링
- 게임 메뉴 출력 함수 및 게임 출력 반복 함수 리팩토링
**2023.04.28**
- 옵셔널 언래핑 방법 수정
- 사용자 입력 숫자 중복 제거 조건 추가
- 승패출력 오류 수정
- 기능별 파일 분류
**2023.04.29**
- 리뷰어 피드백에 따른 승패 출력 후 메뉴 출력하도록 수정
- README 최종 수정
<a id="5."></a>
## 5. 순서도(Flow Chart)
<Img src = "https://i.imgur.com/cn5Swjz.png" width="450"/>
<a id="6."></a>
## 6. 실행 화면(기능 설명)
- 메뉴 번호를 입력받아서 1이면 게임 시작, 2면 게임종료가 됩니다.
| 1 입력 시 |
| :--------: |
| <Img src = "https://i.imgur.com/OYgiTEI.png" width="350"/> |
| **2 입력 시** |
| <Img src = "https://i.imgur.com/4ouC2Y2.png" width="350"/>|
- 게임이 시작되었을 때, 제한조건을 보여주며 사용자에게 숫자 입력을 받아 승패를 결정합니다.
| 컴퓨터 승리 시 |
| :--------: |
| <Img src = "https://i.imgur.com/q3d4hnR.png" width="350"/> |
| **사용자 승리 시** |
| <Img src = "https://i.imgur.com/DF1sB5u.png" width="350"/>|
<a id="7."></a>
## 7. 트러블 슈팅
### 🔥 중복함수 삭제
`createUserNumbers` 함수와 `createRandomNumbers` 함수의 기능이 동일하여 `createRandomNumbers` 함수로 통일시켰습니다.
<details>
<summary>세부 사항</summary>
#### 수정 전
```swift
func createUserNumbers() -> Array<Int> {
var userNumbers: [Int] = []
while userNumbers.count < 3 {
let userNumber = Int.random(in: 1...9)
if !userNumbers.contains(userNumber) {
userNumbers.append(userNumber)
}
}
print("userNumber : \(userNumbers)")
return userNumbers
}
func createRandomNumbers() -> [Int] {
var randomNumbers: [Int] = []
while randomNumbers.count < 3 {
let randomNumber = Int.random(in: 1...9)
if !randomNumbers.contains(randomNumber) {
randomNumbers.append(randomNumber)
}
}
return randomNumbers
}
```
#### 수정 후
```swift
func createRandomNumbers() -> [Int] {
var randomNumbers: [Int] = []
while randomNumbers.count < 3 {
let randomNumber = Int.random(in: 1...9)
if !randomNumbers.contains(randomNumber) {
randomNumbers.append(randomNumber)
}
}
return randomNumbers
}
```
</details>
### 🔥 전역변수 vs 지역변수
함수 별로 기능 구현 완료 후 `class`나 `struct`로 전체 코드를 감싸서 사용자 정의타입을 적용할 목적으로 전역변수로 선언을 했습니다. 그러던 중 *사용자 정의 타입을 구현하지 않고 함수를 이용* 하라는 제약사항을 재상기하여 지역변수로 수정하였습니다.
이후 프로젝트를 진행하던 중 `readLine()`을 이용하여 사용자 입력을 받는 반복문에서 지역변수에 비해 전역변수의 활용도가 높다고 생각하여 기존의 지역변수를 전역변수로 전환하게되었습니다.
<details>
<summary>세부 사항</summary>
#### 변수 생성 - 전역변수로 설정
```swift
var randomNumbers: [Int] = []
var userNumbers: [Int] = []
var strike = 0
var ball = 0
```
#### 1차 수정 - playBall() 함수의 지역변수로 수정
```swift
func playBall() {
let randomNumbers = createRandomNumbers()
var userNumbers = createUserNumbers()
var attemptCount = 9
var ballCount = 0
var strikeCount = 0
```
#### 최종 수정 - 전역변수로 꺼내고 playBall 함수의 파라미터를 수정하여 반복문 설정
```swift
let randomNumbers = createRandomNumbers()
var attemptCount = 9
var ballCount = 0
var strikeCount = 0
func executeGame(of selectedMenu: String) {
if selectedMenu == "1" {
playBall()
while attemptCount > 0 && strikeCount < 3 {
playBall(of: getNumbers())
}
} else if selectedMenu == "2" {
return
}
}
```
</details>
### 🔥 ! (강제추출) 사용 금지
중간에 `commit` 파일에는 `map`함수를 쓰면서 `nil` 값이 있을 수 있어서 임시로 `map{Int($0)!}` 이렇게 강제추출을 넣었다가 마지막 리팩토링 때 수정했습니다. `nil`을 걸러주는 `compactMap` 함수로 수정했습니다.
<details>
<summary>세부 사항</summary>
#### 수정 전
```swift
if let input = readLine()?.split(separator: " "),
input.count == 3,
input.allSatisfy({str in str.count == 1 && str >= "1" && str <= "9"}),
Set(input).count == 3
{
inputNumbers = input.map({Int($0)!})
playBall(of: inputNumbers)
} else {
print("입력이 잘못되었습니다.")
getNumbers()
}
```
#### 수정 후
```swift
if let input = readLine()?.split(separator: " "),
input.count == 3,
input.allSatisfy({str in str.count == 1 && str >= "1" && str <= "9"}),
Set(input).count == 3
{
inputNumbers = input.compactMap({Int($0)})
playBall(of: inputNumbers)
} else {
print("입력이 잘못되었습니다.")
getNumbers()
}
```
</details>
### 🔥 `map{Int($0)!}` 수정 대안 고민
저희는 `compactMap`함수를 이용해 수정했는데 다른 어떤 방법이 더 있을지 궁금하여 리뷰어분에게 문의 드린 결과 또다른 고차함수`reduce`나 `forEach`문 등을 사용하여 구현할 수 있을 것 같지만 지금 단계에서는 **`compactMap`이 훨씬 깔끔해 보인다**는 답변을 받았습니다.
<a id="8."></a>
## 8. 참고 링크
1. [Apple Developer - zip 함수](https://developer.apple.com/documentation/swift/zip(_:_:))
2. [블로그 - compactMap 함수](https://jeonyeohun.tistory.com/265)
<a id="9."></a>
## 9. 팀 회고
### 👏🏻 우리팀이 잘한 점
- 대화, 소통이 원활했습니다.
- 열정이 가득했습니다.
- 생각할 시간을 가지고 서로 기다려주는 시간을 가졌습니다.
- 시간 약속 잘 지켰습니다.
- 서로 배려를 원칙으로 했습니다. (미리 사전에 일정 조율 및 컨디션 고려, 건강을 서로 챙겨주었습니다.)
- 코드를 작성할 때 처음 접한 고차함수를 많이 활용했습니다.(`compactMap`, `zip`, `allSatisfy`)
- 세 명이었기 때문에 리뷰어분의 조언을 토대로 옵저버를 따로 두어 짝코딩을 진행하였습니다.
### 👊🏻 우리팀 개선할 점
- 짝프로그래밍 시에 최대시간을 정하지 않고 진행한 부분이 미흡했던 점 같습니다.
- 텐션 낮추려고 노력했으나 잘 안되었습니다.
- 개인 공부시간이 너무 부족했습니다. 팀 목표가 미션완료였기 때문에 발생되어진 것 같습니다.
- 서로 컨디션 조절을 위해 잠을 충분히 자는 것도 중요한 것 같습니다.
### 💜 서로에게 좋았던 점 피드백
- Dear. Karen 🐕
- 중재를 잘해주셨습니다.
- 상황정리를 잘해주셨습니다.(코드적인 상황정리)
- 철저한 준비로 첫 네비게이터 시작을 잘 끊어주셨습니다.
- 꼼꼼하게 놓치는 부분을 잘 챙겨주셔서 좋았습니다.
- Dear. Serena 🐷
- 아이디어를 많이 주셨습니다.
- 대화나 업무에 협조를 잘해주셨습니다.
- 모르는 함수들에 대하여 많이 알아와 주셨습니다.
- 양보를 잘해주시고 수용을 잘해주셨던것 같습니다.
- Dear. Whales 🐋
- 문서 정리를 잘해주셨습니다.
- 프로젝트 방향성을 많이 잡아주셨습니다.
- 소통을 중재해주고 대화를 잘 이끌어 주셨습니다.
- 통찰력이 좋습니다. (임기응변이 좋습니다.)