[swift]project_야구게임

Jeff·2024년 11월 7일
1

이번 주는 야구 게임을 만들기를 해보았다. 이번 앱은 Command Line Tool을 이용한 값을 입력 받아 실행되게 하는 앱이다.

숫자 야구 게임 은 두 명이 즐길 수 있는 추리 게임으로, 상대방이 설정한 3자리의 숫자를 맞히는 것이 목표입니다. 각 자리의 숫자와 위치가 모두 맞으면 '스트라이크', 숫자만 맞고 위치가 다르면 '볼'로 판정됩니다. 예를 들어, 상대방의 숫자가 123일 때 132를 추리하면 1스트라이크 2볼이 됩니다. 이러한 힌트를 활용하여 상대방의 숫자를 추리해 나가는 게임입니다.

이번 과제로는 6단계를 나눔으로써 단계별로 기능을 추가하는 과정을 경험해 보는 느낌이였다.
기본적으로 게임에 있어 2명의 사람이 필요하지만 우리는 앱을 이용하기에 상대방의 정답을 우리가 모르게 생성해야한다.

# Lv.1

💡 1 ~ 9 까지의 서로 다른 임의의 수를 3개를 만드는게 목표이다.

📌 Point & 📝 개발 과정

  • 임의의 수 즉, 내가 알 수 없게 생성해야하기에 random값을 생성
    • 이 부분은 Int에서 제공해주는 random메서드를 이용하여 범위를 설정해서 생성
  • 서로 다른 3개의 수 즉, 3개의 숫자가 중복이 되면 안되게 생성
    이 부분에서 많은 고민을 했던거 같다.
    • 처음에는 배열을 이용해 첫번째 자리를 배열에 넣고 두번째 자리는 첫번째와 비교해서 동일한 값인지 아닌지 확인하고, 세번째 자리는 첫번째와 두번째 자리와 중복이 되는지.... 여러번 시도를 해봤지만 복잡하고 비효율적이다라고 생각해 다른 방법으로 생각했다.
    • 중복값을 제거해주는 Set를 이용해서 임의의 중복되지 않은 3자리 만들어서 다시 배열에 넣는 방식으로 생성

# Lv.2

💡 이번엔 정답 값을 생성했기에 유저가 값을 입력받고 그 값이 생성된 정답 값을 비교해서 정답을 찾는 기능을 구현하는게 목표다. 이 게임의 핵심 기능이라고 볼 수 있다.
-> 같은 자리에 같은 숫자가 있는 경우 strike, 다른 자리에 숫자가 있는 경우 ball 이라고 한다.

📌 Point & 📝 개발 과정

  • 유저의 값을 입력 받기
    • readline을 활용해 커맨드창에서 값을 받아서 유저의 입력 값을 배열에 저장(순서를 보장하기 위해)
  • 올바르지 않은 값을 입력 받은 경우 오류 문구
    • 에러처리 do try catchthrows를 활용하여 에러가 발생할 메서드에 에러 처리
    • Error타입을 미리 enum (커스텀 타입)에 채택해 에러 요소를 미리 정의
    • guard문을 활용해 에러를 throw 하도록 구성
  • 유저의 값과 이전의 생성한 정답 값을 비교
    • Lv.1에서 생성한 정답 값을 배열에 저장 해놓았고 Lv.2에서 생성한 유저 입력 값을 배열에 저장해 놓았는데 이 이유는 두 배열의 각 자리를 비교해 동일한 자리는 strike를 표현하기 위해서다.
    • 우선 유저의 입력 값이 정답 값에 몇개가 들어갔는지에 대해 알아보려고 했다. 그래서 저는 한번 더 배열을 Set으로 변경 후, 정답에 유저 입력 값이 몇개가 intersection하는지 그래서 그 수를 구해서 총 ball의 갯수가 몇개인지 알아냈다. 그리고 앞에서 언급했듯이 두 배열의 값이 같다면 strike수를 +1, ball -1을 하는 방식으로 힌트를 주는 방식으로 구성했다.

      ex) 정답 : 256, 유저 입력 : 261

      1. 유저 값이 정답에 "6","2"가 겹치므로 [ 2 ball ]
      2. 두 값을 저장한 배열에서 각 순서대로 값을 비교 "2"가 같은 자리 strike +1, ball -1
      3. 계산 결과 < 1 strike, 1 ball >
  • 정답 값과 유저 값이 정확히 일치하게 된다면 게임 종료
    • 정답 값과 유저의 값이 맞는지 판별하면서 답이 맞을 때까지 반복 즉, while문을 이용해 strike값이 정답의 길이인 "3"이 될 때까지 반복하도록 구성했다.

🎯 트러블 슈팅

  • # 1. 에러처리를 위해 do try catch를 썼을 당시에 오류를 발생할 수 있는 메서드를 정의한 안에서 함수를 호출하는 재귀함수로 코드를 처음에 작성해 무한루프에 빠지게 되는 불상사가 일어나게 되었다. 재귀함수에 대해서 부족하게 알고 있다가 발생한 문제였다.

    이 문제는 재귀함수로 썼던 do try catch문을 함수를 호출하는 부분으로 옮겨 수정했다. (아래의 코드로 이동)

  • # 2. 에러 처리에 do try catch문을 적용하는데 미리 정의한 Error를 나열한 enum 케이스를 모두 다 구현했지만 나타나는 오류가 있었다.

    이 오류는 알고보니 모든 에러처리를 하더라도 혹시나 미리 정의한 에러케이스를 벗어나 발생할 수 있는 걸 대비해 아래와 같이 모든 에러를 받을 수 있는 catch문을 하나 더 생성해야 했다.

🛠️ 개선

  • 생성한 생성한 배열을 Set에 다시 넣으려고 for문을 이용해 하나하나 추가하는 방식(비효율)에서 나중에 알고보니 배열에서 형변환으로도 Set으로 생성할 수 있다는걸 알게되어 수정


# Lv.3

💡 0 ~ 9 까지의 서로 다른 임의의 3자릿 수로 변경, 맨 앞자리에 0이 오는 것은 불가능

📌 Point & 📝 개발 과정

  • 이전에 Lv.1에서 구현했던 정답을 구하는 메서드를 수정
    • 구현해 놓았던 랜덤 값의 범위를 1...9 에서 0...9를 범위를 수정
  • 생성한 랜덤 값을 정답 배열에 추가할 때 첫번째로 들어가는 수가 0인지 판별
    • 이전에 방식에서 첫번째 값이 0인지 판별 후 다른 값을 넣으려고 했지만 구현하는 과정에서 이미 Set값은 3자리이기에 다시 값을 생성할 순 없어서 로직을 바꾸게 되었다.
    • for문을 활용해 정답 값이 3개의 서로 다른 임의의 수가 될 때까지 반복하며
      -> 변수를 하나 생성해 변수에 랜덤 값을 넣고 변수를 정답 배열에 추가하는데
      -> 만약 배열의 넣을 위치가 첫번째자리인데 변수가 0인지 확인후 아니라면 추가,
      -> 맞다면 다시 변수에 랜덤 값을 대입 후 비교하는 방식

🎯 트러블 슈팅

  • 위에 언급했듯이 초기에 구성한 방식으로 구현한 결과 계속 로직이 꼬여 제대로 된 동작을 하지 않아서 수정

< 초기 >

< 수정 >


# Lv.4

💡 초기 앱이 시작 되었을 때 기능을 선택할 수 있는 안내문구를 생성, 게임의 정답을 맞춘 경우 종료 후 다시 앱의 초기화면으로 이동

ex) 환영합니다! 원하시는 번호를 입력해주세요.
1. 게임 시작하기 2. 게임 기록 보기 3. 종료하기

📌 Point & 📝 개발 과정

  • 이전엔 바로 게임을 시작했지만 이번에는 옵션을 선택할 수 있게 앱 초기 화면을 구현
    • Lv.2에서 바로 게임이 시작되고 구현한 게임을 정답이 맞을 때까지 반복하도록 했던 걸 초기화면을 구성한 후 게임을 시작하도록 호출하는 방식으로 변경
  • 게임이 끝나면 앱이 종료되었지만, 다시 앱의 초기화면으로 돌아가 게임을 다시하거나 다른 옵션을 선택할 수 있게 구현
    • 이전에 게임의 답을 맞추면 종료되었지만 이번에는 while문을 이용해 앱의 초기화면을 호출하고 switch문을 활용해 옵션을 선택할 수 있게 case를 나눠서 선택된 옵션이 호출되게 하였다. 1번 게임 시작하기를 눌러 게임이 끝나면 다시 앱의 초기화면을 호출했다.

🎯 트러블 슈팅

  • 게임을 다시 시작했을 때 정답이 초기화되지 않음
    • 게임 초기화에서 배열을 다시 초기화해서 해결
  • 게임을 다시 시작했지만 게임이 생성되지 않고 초기 모드가 호출
    • 게임의 종료 조건으로 strike수가 정답의 갯수와 동일해진 경우이기에 strike수를 초기화 하지 안한 부분을 게임 초기화에서 다시 초기화해서 해결

# Lv.5

💡 게임을 몇번 했는지, 게임안에서 몇번만에 정답을 맞췄는지 기록을 확인하는 기능을 추가

환영합니다! 원하시는 번호를 입력해주세요
1. 게임 시작하기 2. 게임 기록 보기 3. 종료하기
2 // 2번 게임 기록 보기 입력
< 게임 기록 보기 >
1번째 게임 : 시도 횟수 - 14
2번째 게임 : 시도 횟수 - 9
3번째 게임 : 시도 횟수 - 12

📌 Point & 📝 개발 과정

  • 게임 시작을 몇번 했는지를 카운트, 한 게임당 몇번을 시도했는지 카운트
    • 우리가 일전에 생성한 (초기화면-게임시작) while 문에서 게임 횟수를 카운트
    • 게임 시작 후 strike 수가 3이 될때까지 반복하는 while 문에서 시도 횟수를 카운트
    • 하나의 배열을 만들어 게임이 끝나면 배열에 시도 횟수를 추가하는 방식으로 구성

# Lv.6

💡 앱 초기 화면에서 3번 종료하기의 경우 프로그램이 종료되도록 구현, 옵션 1,2,3 외의 값이 들어오면 오류 메세지로 알림

📌 Point & 📝 개발 과정

  • 3번 case문에 앱의 초기화면으로 진입하지 못하도록 호출하지 않으면 게임이 종료 후 돌아기지 않는다.
    • if문을 활용해 처음 런타임을 가지면 진입하는 부분에서 게임의 끝나는 포인트를 변수로 만들고 0은 으로 앱의 초기화면으로 진입하도록 호출, 1이면 거짓으로 앱의 초기화면을 부르지 않고 게임이 종료되도록 구성해 3번에 해당하는 케이스에서 이 변수를 1로 변경하도록 만들었다.
  • 옵션을 선택하는 범위로 입력 값을 받고 이외의 값은 에러 메세지를 보여준다.
    • readLine으로 값을 입력받는데 이 값이 옵셔널값이기에 이 부분에서 범위를 정해 1~3까지는 옵셔널 바인딩을 거쳐 제대로 출력하고 이외의 값이 들어오면 기본값인 0을 출력하도록 바꿔 switch문에서 default를 실행하게 구성했다.

마치며..

이번 과제를 시작하면서 저번에는 무작정 개발을 시작했다면 이번엔 내가 이 앱의 흐름을 직접 글로 적어서 만들어보았다. 이 흐름도를 이용해 내가 어디까지 개발했는지, 어느 부분에서 내가 생각한 로직대로 작동하지 않는지 등 개발하는 과정에서 길잡이처럼 도움이 되었다. 그리고 단계별로 나누어 기능을 어떤식으로 추가를 해야할지 왜 앱의 구조와 흐름을 잘 구성해야하는지 어떻게해야 나중에 유지보수와 기능 추가를 할 때 기존의 코드에 영향이 가지 않을지에 대해 한번 더 생각해보게 된거 같다.

profile
기본에 충실한 개발자가 목표!

6개의 댓글

comment-user-thumbnail
2024년 11월 8일

오... guard let이랑 throw를 이용하면 저렇게 깔꼼하게 에러처리가 가능하군요... 저도 연습해야겠습니다

1개의 답글
comment-user-thumbnail
2024년 11월 8일

나두 두 캣츼 했지롱!

1개의 답글
comment-user-thumbnail
2024년 11월 9일

흐름도가 눈에 잘 들어오고 좋네요. 하 나도 아이패드 있었으면 코딩하기 전에 흐름도를 그려보는 멋진 개발자가 되었을텐데

1개의 답글