본문 바로가기
C# 콘솔 & 윈도우폼

[C#] 숫자야구 게임 구현하기

by 17번 일개미 2022. 7. 5.
728x90

숫자야구란?

  • 사용되는 숫자는 0에서 9까지 서로 다른 숫자이다. 경우에 따라 0은 사용하지 않기도 한다.
  • 숫자는 맞지만 위치가 틀렸을 때는 볼.
  • 숫자와 위치가 전부 맞으면 스트라이크.
  • 숫자와 위치가 전부 틀리면 아웃. "틀렸다"는 게 중요하다. 의외로 아웃이 제일 좋은 수인데, 틀린 숫자만 제끼고 남은 숫자끼리 조합하면 되므로 경우의 수가 팍팍 줄어들기 때문. 볼, 스트라이크는 숫자는 맞는 게 있으나 무슨 숫자가 맞았는지를 알 수가 없어 경우의 수를 더 생각해봐야 하지만 아웃은 틀린 숫자만 제거한 나머지만 생각해보면 어렵지 않기 때문. 2아웃이 나오면 더욱 좋다. 작정하고 숫자 예측을 이상하게 하지 않는 이상 3아웃 이상은 절대로 나오지 않는다.
  • 물론 무엇이 볼이고 스트라이크인지는 알려주지 않는다.
  • 두 숫자가 중복되면 경우의 수가 많아져서 그런지 중복 숫자는 잘 사용하지 않는다.

숫자야구 - 나무위키 (namu.wiki)

 

숫자야구 - 나무위키

간단하게 내기삼아 할 수 있는 게임이며 연필 및 종이 게임이다. 원제는 Bulls and Cows 이다. Bulls and Cows는 상업적으로 판매되는 보드 게임 마스터마인드보다 앞서 두 명 이상의 플레이어를 위한 오

namu.wiki


수정

1. 숫자는 1 ~ 9 까지 중복되지 않는 랜덤한 숫자를 사용한다.

2. 입력이 모두 틀리면 "안타!" 를 출력한다.

3. 하나라도 볼, 스트라이크에 해당되면 볼 : x 개 스트라이크 : x 개 로 갯수를 알려준다.

4. 총 입력기회는 10회이다.

5. 10번안에 맞추지 못하면 컴퓨터의 승리로 종료된다.

 


구현 코드

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Class
    {
        static void Main()
        {
            const char space = ' '; // 공백
            int strike = 0; // 스트라이크 카운트
            int ball = 0; // 볼 카운트
            int count = 10; // 입력 기회
            int[] number = new int[3]; // 적의 번호
            int[] player = new int[3]; // 플레이어의 번호

            bool isGaming = true; // 게임 중 여부

            string str; // 문자열을 입력받고
            string[] strarr; // 공백을 제거한 문자열을 저장

            //=======중복 없는 난수 생성=====================================================================//
            Random rand = new Random(); // 랜덤을 생성하기 위함.
            for (int i = 0; i < 3; i++) // 일단 랜덤 숫자 생성
            {
                number[i] = rand.Next(1, 10);
            }
            // 중복 제거
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++) // 서로 비교하면서
                {
                    if (i != j && number[i] == number[j]) // 자기 자신과는 비교 안함
                    {
                        number[j] = rand.Next(1, 10); // 중복이면 새 수 입력
                        j = 0; // 다시 재검사를 하기 위해 0으로 돌아감
                    }
                }
            }
            //=======플레이어에게 숫자를 입력받기==================================================================//

            while (isGaming)
            {
                Console.Write("숫자 3개를 입력하세요 : ");
                str = Console.ReadLine();
                if (!string.IsNullOrEmpty(str))
                {
                    strarr = str.Split(space, StringSplitOptions.RemoveEmptyEntries);
                    for (int i = 0; i < 3; i++) // 플레이어 입력
                    {
                        player[i] = int.Parse(strarr[i]);
                    }
                }
                //=======입력받은 숫자 판정하기 ==================================================================//
                for (int i = 0; i < 3; i++) // 공 체크
                {
                    if (player[i] == number[i]) // 스트라이크 체크
                    {
                        strike++;
                    }
                }
                // 볼 체크
                for(int i = 0; i < 3; i++)
                {
                    for(int j = 0; j < 3; j++)
                    {
                        if(i != j && player[i] == number[j])
                        {
                            ball++;
                        }
                    }
                }
                //=======판정한 결과에 따른 결과를 출력==================================================================//

                count--; // 기회 차감

                if (strike == 0 && ball == 0) // 다 못 맞추면
                {
                    Console.WriteLine("안타! | 남은 기회 : {0}\n", count);
                }
                else Console.WriteLine("스트라이크 : {0}, 볼 : {1} 남은기회 : {2}\n", strike, ball, count); // 뭐라도 있으면

                //=======게임 종료=======================================================================================//
                if (strike == 3 && count >= 1)
                {
                    isGaming = false;
                    Console.WriteLine("플레이어 승리!");
                    return;
                }
                else if(count <= 0)
                {
                    isGaming = false;
                    Console.WriteLine("컴퓨터 승리!");
                    return;
                }
            }
        }
    }
}

코드 상세 설명

선언부

char space = ' '; // 공백
            int strike = 0; // 스트라이크 카운트
            int ball = 0; // 볼 카운트
            int count = 10; // 입력 기회
            int[] number = new int[3]; // 적의 번호
            int[] player = new int[3]; // 플레이어의 번호

            bool isGaming = true; // 게임 중 여부

            string str; // 문자열을 입력받고
            string[] strarr; // 공백을 제거한 문자열을 저장

Console.ReadLine() 은 입력을 문자열의 형태로 받는다.

따라서 숫자 3개를 입력받기 위해 변환이 필요하고, 그 과정에서 필요한 변수 (space, str, strarr) 를 선언한다.

 

이외에 strike, ball 의 갯수를 저장할 변수, 전체 게임 기회를 저장할 count, 플레이어의 입력 player[] 와

컴퓨터의 숫자 number[] 를 선언한다.

 

중복 없는 난수 생성

//=======중복 없는 난수 생성=====================================================================//
            Random rand = new Random(); // 랜덤을 생성하기 위함.
            for (int i = 0; i < 3; i++) // 일단 랜덤 숫자 생성
            {
                number[i] = rand.Next(1, 10);
            }
            // 중복 제거
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++) // 서로 비교하면서
                {
                    if (i != j && number[i] == number[j]) // 자기 자신과는 비교 안함
                    {
                        number[j] = rand.Next(1, 10); // 중복이면 새 수 입력
                        j = 0; // 다시 재검사를 하기 위해 0으로 돌아감
                    }
                }
            }

Random 클래스를 활용하여 난수를 생성할 수 있다.

 

우선, 배열의 3 원소를 모두 난수를 생성하여 준다.

그 후, 이중 반복문을 돌며, 나를 제외한 다른 숫자들과 비교하면서

 

만약에 같은 숫자라면 새로운 난수를 대입하여 준다.

다시 중복이 발생하지 않았는지 처음으로 돌아가 체크하기 위해 j = 0을 대입해 처음부터 체크한다.


숫자 입력 받기

Console.Write("숫자 3개를 입력하세요 : ");
                str = Console.ReadLine();
                if (!string.IsNullOrEmpty(str))
                {
                    strarr = str.Split(space, StringSplitOptions.RemoveEmptyEntries);
                    for (int i = 0; i < 3; i++) // 플레이어 입력
                    {
                        player[i] = int.Parse(strarr[i]);
                    }
                }

str 에 ReadLine() 을 활용하여 문자열을 입력받는다.

strarr 에는 Split 함수를 사용하여 공백을 제거한 문자열을 다시 대입한다.

이 때, 처음에 미리 선언했던 char space = ' '; 를 활용한다.

 

공백을 제거하기 위해

string[] str = Console.ReadLine().Split(' ');

더 짧게는 이 방법도 활용할 수 있다.

 

숫자 판정 하기

//=======입력받은 숫자 판정하기 ==================================================================//
                for (int i = 0; i < 3; i++) // 공 체크
                {
                    if (player[i] == number[i]) // 스트라이크 체크
                    {
                        strike++;
                    }
                }
                // 볼 체크
                for(int i = 0; i < 3; i++)
                {
                    for(int j = 0; j < 3; j++)
                    {
                        if(i != j && player[i] == number[j])
                        {
                            ball++;
                        }
                    }
                }

먼저 스트라이크 여부를 체크한다. 스트라이크는 각 자리와 각 자리에 해당하는 숫자가 같으면 스트라이크 이므로,

조건에 맞게 작성한다.

 

두 번째로 볼체크를 한다. 볼은 자리는 다르지만 특정 값이 다른 자리에 존재하면 볼이다.

이중 반복문을 돌면서 나를 제외한 자리와 값을 비교하여 볼에 해당되면 ball 을 1씩 증가 시켜준다.


결과 출력하기

//=======판정한 결과에 따른 결과를 출력==================================================================//

                count--; // 기회 차감

                if (strike == 0 && ball == 0) // 다 못 맞추면
                {
                    Console.WriteLine("안타! | 남은 기회 : {0}\n", count);
                }
                else Console.WriteLine("스트라이크 : {0}, 볼 : {1} 남은기회 : {2}\n", strike, ball, count); // 뭐라도 있으면

                //=======게임 종료=======================================================================================//
                if (strike == 3 && count >= 1)
                {
                    isGaming = false;
                    Console.WriteLine("플레이어 승리!");
                    return;
                }
                else if(count <= 0)
                {
                    isGaming = false;
                    Console.WriteLine("컴퓨터 승리!");
                    return;
                }

판정 이후, strike 와 ball 이 모두 0 이라면 아무것도 맞추지 못한 것이므로,

"안타!" 를 출력하고 남은 기회(count) 를 알려준다.

 

둘 중 하나라도 1 이상이면 해당하는 스트라이크, 볼의 갯수를 출력한다.

 

루프를 돌다가, count 가 남아있는 상태에서 3 strike가 나올 경우,

플레이어의 승리로 판단하여 "플레이어 승리!" 를 출력한다.

 

count가 모두 소진될 경우 플레이어의 패배로 처리되며  "컴퓨터 승리!" 를 출력한다.

728x90