[내일배움캠프 사전캠프 과제 - Stage3. 각자 속도에 맞춰 나아가기]
달리기반 Lv3의 마지막 과제이다!!
(25/01/15) 팀원들과 서로의 코드를 피드백한 내용을 추가하였다. 진행 후에 추가할 것이다.
- 숫자 야구 게임 설명
- 나의 풀이
- 플레이 모습
- 나의 코드 피드백 & 후기
- 피드백 반영한 코드
8. 숫자 야구 게임 ⚾
숫자 야구 게임을 작성하세요.
컴퓨터가 3자리의 숫자를 선택하면 사용자가 그 숫자를 맞추는 게임을 구현하세요.
각 자리의 숫자를 비교하여 스트라이크와 볼의 개수를 출력합니다.
숫자 야구 게임 설명
숫자 야구 게임은 3자리의 숫자를 맞추는 게임입니다.
컴퓨터가 고른 3자리 숫자는 모두 다른 숫자로 이루어져 있습니다.
사용자는 3자리 숫자를 입력하고, 컴퓨터는 입력한 숫자와 자릿수를 비교하여 스트라이크와 볼의 개수를 알려줍니다.
- 스트라이크 : 숫자와 자릿수가 모두 맞는 경우
- 볼 : 숫자는 맞지만 자릿수가 다른 경우
예를 들어, 컴퓨터가 813을 선택하고 사용자가 123을 입력했을 때, 1은 맞지만 자릿수가 다르므로 1 볼, 3은 자리도 맞으므로 1 스트라이크가 된다. 이 과정은 사용자가 정확한 숫자를 맞출 때까지 반복된다.
사용 변수 설명
- targetNumber : 컴퓨터가 선택한 3자리의 숫자를 저장하는 배열입니다.
- userGuess : 사용자가 추측한 숫자를 저장하는 배열입니다.
- strikes : 자릿수와 숫자가 모두 맞는 경우의 개수를 저장합니다.
- balls : 자릿수는 맞지 않지만 숫자가 포함된 경우의 개수를 저장합니다.
- guessedCorrectly : 사용자가 숫자를 정확히 맞췄는지를 나타내는 불리언 변수입니다.
나의 풀이
(글의 맨 아래에 수정한 코드도 봐주세요!)
using System.Linq;
int[] targetNumber = new int[3];
int[] userGuess = new int[3];
int strikes = 0, balls = 0, attempts = 0;
bool guessedCorrectly = false;
// targetNumber 초기 설정
HashSet<int> targets = new HashSet<int>(); // target의 숫자 종류 갖고 있기
Random random = new Random();
int idx = 0;
while (idx < 3)
{
int r = random.Next(0, 10);
if (targets.Contains(r)) continue; // 이미 있는 숫자는 넣지 않음
targetNumber[idx++] = r;
targets.Add(r);
}
// 맞추는 로직
while (!guessedCorrectly)
{
++attempts;
// 초기화
strikes = 0;
balls = 0;
// 입력받기
Console.Write("Enter your guess (3 digits) : ");
int userNum = int.Parse(Console.ReadLine());
ConvertIntToGuessArray(userNum);
// 숫자 비교
for(int i = 0; i < 3; i++)
{
// i번째 숫자가 target에 존재하는 경우
if (targets.Contains(userGuess[i]))
{
if (userGuess[i] == targetNumber[i])
{
strikes++;
}
else
{
balls++;
}
}
}
// 결과 출력
Console.WriteLine($"{strikes} Strike(s), {balls} Ball(s)");
if (strikes == 3) guessedCorrectly = true;
}
Console.WriteLine($"Congratulations! You've guessed the number in {attempts} attemps.");
// int를 userGuess에 한 자릿수씩 넣어주는 함수
void ConvertIntToGuessArray(int num)
{
int idx = 2;
while(num > 0)
{
userGuess[idx] = num % 10;
num = num / 10;
idx--;
}
// 모든 자릿수 돌았는데 idx가 남아있으면 앞자리가 0
if(idx == 0)
{
userGuess[idx] = 0;
}
}
숫자 야구 게임 플레이
풀면서 겪은 문제
◆ 타겟 넘버와 사용자가 입력한 숫자를 비교할 때와, 컴퓨터가 랜덤 숫자를 정할 때 모두 겹치는 숫자가 있는지 비교하는 로직이다. 이때 편리하게 비교하기 위해 C++이었다면 std::set을 사용했을 것이다. 그래서 C#의 HashSet을 찾아내서 사용했다.!
나의 코드 피드백 & 후기
팀원분들과 서로의 코드 리뷰를 진행했다.
- 우선 나는 사용자가 입력한 문자열의 유효성을 검수하는 코드를 딱히 넣지 않았는데, 다른 팀원분들은 입력된 값이 숫자가 맞는지, 세 자릿수가 맞는지 확인하셨다. 정말 문제에 적혀있는 것만 코딩한 나... 부끄럽다!!!
- 자릿수를 구할 때 나는 while문을 돌며 10으로 나눈 나머지를 하나씩 넣어줬는데, 입력문자열[i] - '0'로 구하는 방법이 훨씬 깔끔해 보였다.
- 어떤 팀원분은 Linq를 사용하셨다. 랜덤한 숫자를 뽑는 과정에서 배열에 0부터 9까지의 숫자를 넣어놓고 Guid.NewGuid()를 기준으로 OrderBy 하여 Take(3) 하셨다. Guid.NewGuid()는 처음 봤는데 고유한 식별자를 생성해 주는 메서드라고 한다. Guid.NewGuid() 말고 Random을 써도 된다. 좋은 방법이라고 생각했다.
아래는 내가 받은 피드백이다. 역시나 이번에도 배워가는 점이 많았다.
🗨️ "컴퓨터의 랜덤 숫자를 뽑는 과정에서 HashSet의 Contains 대신 Add를 사용하는 것이 효율적이다."
아주 좋은 정보를 주셨다. HashSet의 Add함수가 Add를 성공했는지 중복되는 게 있어서 실패했는지를 bool값으로 반환해 주기 때문에 Contains 대신 Add를 쓰는 것이 좋아 보인다. 짱피드백.!!
🗨️ "Linq를 쓰지 않았는데 using문이 들어가있다?"
이게 왜 있는지 몰랐는데 사용하지도 않고 있었길래 지웠다. 처음에는 HashSet이 Linq인가 했다..
피드백을 반영한 코드
피드백을 반영하고, 문자열 유효성을 검수하는 코드를 추가해 보았다.
- 입력된 문자열의 길이로 3글자인지 확인했다.
- ConvertIntToGuessArray 함수에서 숫자 이외의 것을 입력했다면 false를 반환하도록 했다.
- 함수 내부의 코드를 아예 수정했는데, 숫자를 각 자리에 분리할 때 더 깔끔해 보인다고 생각하는 입력문자열[i] - '0' 코드를 사용했다.
int[] targetNumber = new int[3];
int[] userGuess = new int[3];
int strikes = 0, balls = 0, attempts = 0;
bool guessedCorrectly = false;
// targetNumber 초기 설정
HashSet<int> targets = new HashSet<int>(); // target의 숫자 종류 갖고 있기
Random random = new Random();
int idx = 0;
while (idx < 3)
{
int r = random.Next(0, 10);
if (!targets.Add(r)) continue; // 이미 있는 숫자는 넣지 않음
targetNumber[idx++] = r;
}
// 맞추는 로직
while (!guessedCorrectly)
{
++attempts;
// 초기화
strikes = 0;
balls = 0;
// 입력받기
Console.Write("Enter your guess (3 digits) : ");
string input = Console.ReadLine();
if (input.Length != 3) continue;
if (!ConvertIntToGuessArray(input)) continue;
// 숫자 비교
for(int i = 0; i < 3; i++)
{
// i번째 숫자가 target에 존재하는 경우
if (targets.Contains(userGuess[i]))
{
if (userGuess[i] == targetNumber[i])
{
strikes++;
}
else
{
balls++;
}
}
}
// 결과 출력
Console.WriteLine($"{strikes} Strike(s), {balls} Ball(s)");
if (strikes == 3) guessedCorrectly = true;
}
Console.WriteLine($"Congratulations! You've guessed the number in {attempts} attemps.");
// int를 userGuess에 한 자릿수씩 넣어주는 함수, 숫자가 아닌 것을 입력하면 false를 반환
bool ConvertIntToGuessArray(string _input)
{
for(int i = 0; i < 3; i++)
{
if (_input[i] < '0' && _input[i] > '9') return false;
userGuess[i] = _input[i] - '0';
}
return true;
}
수정한 코드가 훨씬 마음에 든다!
'공부 기록 > C#' 카테고리의 다른 글
[C#] 기초 문법 톺아보기 (2) - 클래스, 상속, 인터페이스, 추상 클래스, 가상 메서드, 인덱서 (0) | 2025.01.09 |
---|---|
[C#] 기초 문법 톺아보기 (1) - 입력과 출력, 배열, 필드와 프로퍼티 (0) | 2025.01.08 |
[C#] 행맨 게임 만들기 (달리기반 Lv3) (0) | 2025.01.06 |
[C#] 내일배움캠프 사전캠프 과제 - 달리기반 Lv2. 기초 문법 활용해보기 (팩토리얼 계산, 숫자 맞추기 게임, 구구단 출력, 배열 최댓값 최솟값 찾기, 정렬) (0) | 2025.01.03 |
[C#] 내일배움캠프 사전캠프 과제 - 달리기반 Lv1. 기초 문법 파헤치기 (홀수 출력, 배열 합계 및 평균 계산) (0) | 2025.01.02 |