# 묵찌빠게임 프로젝트 저장소 > 프로젝트 기간 2022/08/22 ~ > 팀원: @준호 @LJ / 리뷰어: @브래드 # 목차 - [프로젝트 소개](#프로젝트-소개) - [개발환경 및 라이브러리](#개발환경-및-라이브러리) - [타임라인](#타임라인) - [Flow chart](#Flowchart) - [실행 화면](#실행-화면) - [코딩 컨벤션](#코딩-컨벤션) - [트러블 슈팅](#트러블-슈팅) - [STEP 1](##STEP-1) - [고민한 점](###고민한-점) - [배운 개념](###배운개념) - [STEP 2](##STEP-2) - [고민한 점](###고민한-점) - [배운 개념](###배운개념) - [🔗 참고 링크](##🔗-참고-링크) --- # 프로젝트 소개 사용자로부터 값을 입력받아 컴퓨터와 가위바위보게임(STEP1), 묵찌빠게임(STEP2)을 구현함. # 개발환경 및 라이브러리 [![swift](https://img.shields.io/badge/swift-5.6-orange)]() [![xcode](https://img.shields.io/badge/Xcode-13.4-blue)]() # 타임라인 - 2022/08/23 - STEP 1 - 가위바위보 메뉴 출력 함수, 사용자 패 입력 함수 추가 - 사용자의 입력값 검증 함수 추가 - 함수 추가, 메서드 순서 수정, 반환타입 변경 - 가위바위보 열거형 추가, 반환타입과 메소드 리팩토링 - 승패 판단 함수 추가, 승무패 열거형 추가 - 기존 결과출력문을 열거형 `WinLoseDraw`에 메소드로 추가하여 대체, `startGame`메소드를 제외한 나머지 메소드를 은닉화 - 파일 분리(열거형타입, 구조체타입, 실행문) - README 파일 작성, flow chart 추가 - [STEP 1 PR ](https://github.com/yagom-academy/ios-rock-paper-scissors/pull/162) - git branch 정리 - 2022/08/24 - STEP 1 리뷰 수정내용 반영 - 열거형,메서드이름 수정, 반환타입 optional로 변경, 타입명시 통일 - STEP 1 PR Merge 완료 - STEP 2 - flow chart 작성 - 묵찌빠 열거형 추가 - 참가자 열거형 추가 - 묵찌빠 구조체 추가, 참가자 열거형 수정 - 가위바위보게임 종료시 승리자 반환하도록 기능 수정 - 2022/08/25 - STEP 2 - 입력값검증 후 잘못입력 시 에러메세지 출력, 정상입력 시 입력값 반환 메서드 `getSelectedUserMenu` 추가 - 승패를 결정하는 메서드 `compareComputerHand` 추가 - 메서드에서 사용하는 `turnOwner` 파라미터를 묵찌빠게임 구조체 `turnOwner`프로퍼티로 선언하여 사용 - 턴오너를 교체하는 메서드 `toggleTurnOwner`, 턴오너가 이겼는지 판단하는 메서드 `isTurnOwnerWin` 추가 - 묵찌빠 게임 실행하는 `startMukChiBaGameRoutine` 메서드 추가 - 메서드 배치 호출순으로 변경 - 가위바위보 게임 `startGame` 메서드에서 승자`Participant`를 직접 반환하지 않고 `winner`프로퍼티 값을 바꿔주도록 수정 - [STEP 2 PR 작성](https://github.com/yagom-academy/ios-rock-paper-scissors/pull/175) - flow chart 수정 - 2022/08/26 - STEP 2 리뷰 수정내용 반영 - 메서드명 변경, 개행방식 통일, 불필요한 else문 제거 - README 작성 --- # Flow chart | STEP 1 | STEP 2 | |:------------------------------------:|:------:| |![](https://i.imgur.com/JeAbkhs.png)| ![](https://i.imgur.com/tenhtAe.png)| --- # 실행 화면 | STEP 1 | STEP 2 | |:------------------------------------:|:------:| |![](https://i.imgur.com/8ptw9HI.gif)| ![](https://i.imgur.com/3xH0SuE.gif) | --- # 코딩 컨벤션 - 변수명 정할 때 단어 축약하지 않기 - 상수로 선언해줄 수 있는 부분은 최대한 상수로 구현 - 전역변수는 최대한 지양 - 타입 명시는 통일 - 메서드 내부는 메서드명과 메서드의 목적에 맞게 구현 - 타입(구조체, 열거형, 클래스)별로 파일 분리 - return문 윗줄 개행기준 : 코드블럭 내부 return문외에 다른실행문도 있으면 윗줄 개행하여 비워두기 --- # 트러블 슈팅 ## [STEP 1] ### 고민한 점 -용자 입력값과 컴퓨터 임의의 패를 비교할 때, 비교조건 내용을 고민하였습니다. > 예: 사용자 입력값이 가위일 경우 > 방법(1) 1. 컴퓨터의 패와 같은지?(True/False) -> 2. 컴퓨터의 패가 바위인가?(True/False) 방법(2) 1. 컴퓨터의 패가 바위인가?(True/False) -> 2. 컴퓨터의 패가 보인가?(True/False) ➡️ 방법(2)의 경우 사용자 입력값에 따라 비교조건이 전부 달라집니다. (가위일땐 바위,보, 바위일땐 가위,보, 보일땐 바위,가위 ) 방법(1)의 경우에는 첫번째 비교조건은 컴퓨터의 패와 같은것으로 통일 할 수 있습니다. (가위일땐 동일여부,바위, 바위일땐 동일여부,보, 보일땐 동일여부,가위) 그래서 방법(1)로 구현하였습니다. --- - RockPaperScissors, WinLoseDraw 열거형을 사용해서 선택지를 제한했습니다. - RockPaperScissors에는 Int 타입의 원시 값을 추가해서 원시 값으로 항목을 찾을 수 있도록 했습니다. - WinLoseDraw에는 결과 출력 메서드를 추가해서 승부 결과별로 다르게 출력해 줄 수 있게 했습니다. --- - RockPaperScissorsGame 구조체에서 startGame를 제외한 나머지 메서드에는 접근 제어 키워드 private를 추가해서 구조체 밖에서 접근할 수 없도록 했습니다. - 클래스의 상속 기능이 필요가 없고 연관된 기능의 집합을 단순히 캡슐화하는 것을 목적으로 하기 때문에 클래스 대신 구조체를 사용했습니다. - RockPaperScissors, WinLoseDraw, RockPaperScissorsGame 파일로 분리해서 main에는 실행 코드만 남겨두었습니다. --- - 코드의 가독성을 위해 Naming을 -Menu접미사와 -Hand접미사로 구분지었습니다. - 사용자에게 직접 입력받은 값과 입력 받는 메서드의 이름은 selectedUserMenu, getSelectedUserMenu 와 같이 Menu접미사를 붙였습니다. - RockPaperScissors 타입의 변수명은 computerHand, userHand 와 같이 Hand 접미사를 붙였습니다. - 처음에는 가위, 바위, 보를 1, 2, 3의 Int 타입으로 표현했는 데, 가독성을 위해 RockPaperScissors 열거형을 사용했습니다. --- ### 배운개념 - git branch 생성, merge 하는방법 - 열거형에서 랜덤 요소 가져오는 함수 ```swift /// A type that provides a collection of all of its values. /// /// Types that conform to the `CaseIterable` protocol are typically /// enumerations without associated values. When using a `CaseIterable` type, /// you can access a collection of all of the type's cases by using the type's /// `allCases` property. public protocol CaseIterable { 열거형: CaseIterable // CaseIterable 프로토콜 추가 열거형.allCases.randomElement() // 반환 타입은 옵셔널 ``` --- ## [STEP 2] ### 고민했던 점 - 가위바위보 게임의 startGame 메서드명은 게임을 시작한다는 의미인데 반환값이 있다는 것이 어색했습니다. - 해결방법 ➡️ winner 프로퍼티를 추가해서 가위바위보 게임이 끝나면 승자를 winner 프로퍼티에 설정하여 묵찌빠게임에서 쓸 수 있도록 했습니다. - 수정 전 ```swift struct RockPaperScissorsGame { func startGame() -> Participant? { ``` - 수정 후 ```swift struct RockPaperScissorsGame { var winner: Participant? mutating func startGame() { ``` --- - 묵찌빠 게임에서 먼저 가위바위보 게임이 끝나고 승리자가 결정된 후 묵찌빠 게임을 진행하는 부분은 startMukChiBaGameRoutine() 메서드로 분리했습니다. ```swift mutating func startGame() { var rockPaperScissorsGame: RockPaperScissorsGame = RockPaperScissorsGame() rockPaperScissorsGame.startGame() guard let turnOwner: Participant = rockPaperScissorsGame.winner else { return } self.turnOwner = turnOwner startMukChiBaGameRoutine() } mutating private func startMukChiBaGameRoutine() { var isTurnOwnerWin: Bool repeat { let selectedUserMenu: Int = getSelectedUserMenu() guard let userHand: MukChiBa = MukChiBa.init(rawValue: selectedUserMenu) else { return } guard let gameResult: GameResult = compareComputerHand(with: userHand) else { return } isTurnOwnerWin = isTurnOwnerMukChiBaGameWin(gameResult: gameResult) printMukChiBaGameResult(isTurnOwnerWin) } while isTurnOwnerWin == false } ``` ### 배운개념 - self property - private - 재귀함수 ## 🔗 참고 링크 - [Swift API Design Guidelines](https://www.swift.org/documentation/api-design-guidelines/) - [CaseIterable](https://developer.apple.com/documentation/swift/caseiterable) - [randomElement](https://developer.apple.com/documentation/swift/array/randomelement())