사전캠프/달리기반

달리기반 Lv.3 행맨 게임

서보훈 2024. 8. 23. 16:23
  • 사용자로부터 문자를 입력받아 숨겨진 단어를 맞추는 행맨 게임을 작성하세요. 사용자가 단어의 모든 문자를 맞추거나 주어진 기회 내에 맞추지 못할 때까지 반복합니다.
    • 게임 설명: 행맨 게임은 사용자가 단어를 추측하는 게임입니다. 사용자는 알파벳을 하나씩 입력하고, 맞출 때마다 단어의 해당 위치에 문자가 표시됩니다. 틀릴 경우, 기회가 줄어듭니다.
    • 배열 사용: char[] 배열을 사용하여 단어를 저장하고, 추측된 문자를 저장합니다.
    • 반복문 사용: 게임은 사용자가 단어를 맞추거나 기회가 끝날 때까지 반복됩니다.
    • 조건문 사용: 각 입력된 문자가 단어에 포함되는지 확인합니다.

사용 변수 설명

  • secretWord: 맞춰야 할 단어입니다. 예제에서는 "hangman"으로 설정되어 있습니다.
  • guessWord: 사용자가 맞춘 문자를 저장하는 문자 배열로, 초기에는 언더스코어(_)로 채워져 있습니다.
  • attempts: 사용자가 틀릴 수 있는 기회의 수로, 초기에는 6으로 설정되어 있습니다.
  • wordGuessed: 사용자가 단어를 모두 맞췄는지를 나타내는 불리언 변수입니다.

 

행맨 게임을 작성해야합니다.

문자열을 문자의 배열처럼 사용할 수 있음을 응용하여 게임을 만들어 줄 수 있습니다.

 

게임의 흐름은 다음과 같습니다

  1. 정답 문자가 지정됨
  2. 플레이어가 정답문자의 길이를 알고, 문자를 추측해서 입력함
  3. 입력한 문자와 정답문자 각각의 자리를 비교해서, 같은자리에 같은 알파벳이면 해당 자리의 알파벳이 공개됨
  4. 기회를 모두 쓰거나 문자를 맞출때까지 반복
  5. 기회를 모두 사용하면 패배, 그 전에 문자를 맞추면 승리함

게임 흐름의 2 ~ 4번은 게임이 끝날때까지 반복되게 됩니다.

즉, 이 게임을 코드로 만들면서 2 ~ 4번의 코드가 반복문으로 처리하게 됩니다.

 

이를 기반으로 코드의 흐름을 분석해보면

  1. 정답문자열 string 변수 선언
  2. 비교 결과를 저장할 문자 배열 char[] 선언 및 초기화
  3. 시도 횟수 int 변수 선언
  4. 정답 여부 bool 변수 선언
  5. 게임에 사용할 반복문
  6. 게임 결과 출력

이러한 흐름으로 코드가 진행되게 됩니다

5번의 반복문에 게임의 흐름 2 ~ 4가 진행되도록 만들어주면 됩니다.

 

코드를 짜보도록 하겠습니다.

먼저, 각 변수들을 선언해주겠습니다.

{
    //정답 문자열
    string secretWord = "hangman";
            
    //플레이어의 추측 문자 배열
    char[] guessWord = new char[secretWord.Length];
    
    //입력 시도 횟수
    int attempts = 6;
    //정답판정, 정답시 true
    bool isGuessed = false;
}

 

추측 문자 배열은 정답 문자열의 길이만큼 만들어 주었지만, 배열에 값을 할당해주지 않은 상태 입니다.

여기에 초기값으로 모두 _ 를 대입해주도록 하겠습니다.

//추측 문자 배열 초기화
for(int i = 0; i < secretWord.Length; i++)
{
    // 정답 문자열의 길이만큼, _로 초기화
    guessWord[i] = '_';
}

 

변수의 선언과 초기화가 종료되었습니다.

 

이제, 본 게임이 진행될 반복문을 만들어주도록 하겠습니다.

//정답일때까지, 반복한다.
while (!isGuessed)
{

}

while 문은 명제가 true일때 계속 반복됩니다.

지금은 isGuessed 가 true 일 때 반복을 멈춰야하기 때문에, NOT 연산자인 ! 를 붙여서 isGuessed가 ture일 때 while에 false가 입력되도록 만들어주겠습니다.

 

게임에 사용될 게임 판을 만들어주겠습니다.

이 게임판은, 게임이 종료될때 까지 반복해서 출력될 예정입니다.

//정답일때까지, 반복한다.
while (!isGuessed)
{
    //게임판...
    Console.WriteLine($"-----Hangman Game-----");
    for (int j = 0; j < guessWord.Length; j++)
    {
        Console.Write(guessWord[j]);
    }
    Console.WriteLine();

    Console.WriteLine($"Left Attempts : {attempts}");
    Console.WriteLine($"Enter Your Guess - {secretWord.Length} letters");
    //사용자의 문자 입력
    string input = Console.ReadLine();
}

첫줄에 게임타이틀, 두번째줄에 현재까지 맞춘 글자를 표기하고 세번째줄에 시도횟수를, 네번째줄에 정답문자의 글자수와 같은 글자수의 단어를 입력하도록 유도해주었습니다.

 

여기서 사용된 for문의경우, 배열을 전부 출력하는 역할만을 하기 때문에 foreach문을 사용해줄 수 도 있습니다.

foreach (char c in guessWord)
{
    Console.Write(c);
}

 

입력 후의 행동을 만들어주겠습니다.

먼저, 입력한 문자열의 길이가 적당하지 않을경우 다시 시도하도록 만들어주겠습니다.

//문자열의 길이 측정
if(input.Length == secretWord.Length)
{

}
else
{
    //글자수가 안맞을경우, 시도 횟수를 줄이지 않고 경고
    Console.Clear();
    Console.WriteLine($"No... It's {secretWord.Length} letters word");
    Console.WriteLine($"You entered {input.Length} letters word... Try again");
}

이 if문이 종료된 후, 다시 while 문이 반복되기 때문에 else의 시작에서 지금까지 콘솔에 출력한 값을 모두 지워준후 글자수가 맞지 않다는 경고를 출력하도록 만들어주었습니다.

 

글자수가 정확할때, 이제 입력한 값에 따라 문자열을 변경해주도록 하겠습니다.

//정답시, 연산을 하지 않음
if (input == secretWord)
{
    //입력을 시도하였기 때문에, 시도 횟수를 줄임
    attempts--;
    //정답 처리
    isGuessed = true;
    //게임판 지우기
    Console.Clear();
}
else
{
    //모든 배열에 접근하기위한 반복문
    for (int k = 0; k < secretWord.Length; k++)
    {
        //같은 위치의 배열끼리 비교
        if (input[k] == secretWord[k])
        {
            //input과, secretWord 배열의 같은경우, guessWord의 내용을 변경
            guessWord[k] = input[k];
        }
    }
    //시도 횟수 줄이기
    attempts--;
    //게임판 지우기
    Console.Clear();
}

입력한 문자열과 정답 문자열이 완전히 같을경우 즉시 정답처리를 해주었습니다.

단, 입력을 시도하였기 때문에 남은 입력횟수를 저장하고있는 attempts 변수를 1 줄여줍니다.

 

이후 else 문에서 각 자리에 입력된 문자가 정답과 같은지 비교해서, 입력 문자열을 바꿔줍니다.

 

else문의 마지막에 여기서도 시도횟수를 줄이고 게임판을 지워서 다음 반복을 준비해줍니다.

aaaaaaa를 입력한 후의 결과입니다.

문자 표기가 변하고, 남은 시도횟수 표기가 줄어든것을 볼 수 있습니다.

 

while문 전체를 보도록 하겠습니다.

//정답일때까지, 반복한다.
while (!isGuessed)
{
    //게임판...
    Console.WriteLine($"-----Hangman Game-----");
    
    for (int j = 0; j < guessWord.Length; j++)
    {
        Console.Write(guessWord[j]);
    }
    Console.WriteLine();

    Console.WriteLine($"Left Attempts : {attempts}");
    Console.WriteLine($"Enter Your Guess - {secretWord.Length} letters");
    //사용자의 문자 입력
    string input = Console.ReadLine();

    //문자열의 길이 측정
    if(input.Length == secretWord.Length)
    {
        //정답시, 연산을 하지 않음
        if (input == secretWord)
        {
            //입력을 시도하였기 때문에, 시도 횟수를 줄임
            attempts--;
            //정답 처리
            isGuessed = true;
            //게임판 지우기
            Console.Clear();
        }
        else
        {
            //모든 배열에 접근하기위한 반복문
            for (int k = 0; k < secretWord.Length; k++)
            {
                //같은 위치의 배열끼리 비교
                if (input[k] == secretWord[k])
                {
                    //inputArr과, secretWord 배열의 같은경우, guessWord의 내용을 변경
                    guessWord[k] = input[k];
                }
            }
            //시도 횟수 줄이기
            attempts--;
            //게임판 지우기
            Console.Clear();
        }
    }
    else
    {
        //글자수가 안맞을경우, 시도 횟수를 줄이지 않고 경고
        Console.Clear();
        Console.WriteLine($"No... It's {secretWord.Length} letters word");
        Console.WriteLine($"You entered {input.Length} letters word... Try again");
    }
}

 

이 반복문에서 빠져나가기 위해서는 정답을 맞추어 isGuessed가 true가 되어야만 합니다.

그런데 시도 횟수를 모두 사용했을경우, 추측에 실패하여 게임이 종료되어야만 합니다.

 

시도 횟수가 0이 되었을때 게임을 종료하도록 만들어주겠습니다.

//정답일때까지, 반복한다.
while (!isGuessed)
{
    //... 생략

    //게임 종료, 추측에 실패시
    if(attempts <= 0 && isGuessed == false)
    {
        //강제로 반복을 종료함
        break;
    }
}

while문의 마지막줄에, if문을 추가하였습니다.

시도횟수가 0이하가 되면 break; 를 통해 강제로 반복문을 종료합니다.

 

while문이 종료되면, 게임 결과를 표기하도록 해주겠습니다.

//추측 성공시
if(isGuessed == true)
{
    //정답과 남은 시도횟수를 보여줌
    Console.WriteLine("You Win!!");
    Console.WriteLine($"SecretWord : {secretWord}");
    Console.WriteLine($"Your left attempts is {attempts}");
}
else
{
    Console.WriteLine("GameOver");
    Console.WriteLine($"SecretWord : {secretWord}");
}

isGuessed 의 상태에 따라 결과를 다르게 표기하였습니다.

추측에 성공하면, 승리 텍스트와 함께 정답과 남은 횟수를 출력합니다.

실패시 패배 텍스트와 함께 정답을 출력합니다.

 

 


여기서 문제가 하나 있습니다.

텍스트를 비교하는것은 대,소문자를 구분하기 때문에, 사용자가 대문자로 입력할경우 정답으로 처리하지 않게 됩니다.

 

여기에, 따로 소문자만 입력해 달라는 텍스트를 입력하기에는, 대문자를 입력했을때의 예외 처리등 추가로 해야하는 작업이 많아집니다.

 

string 변수에 사용할 수 있는 함수중, 대문자를 소문자로 변경하거나 소문자를 대문자로 변경해주는 기능이 존재합니다.

이 기능을 사용해 사용자가 입력한 알파벳을 전부 소문자로 변경해주도록 하겠습니다.

//사용자의 문자 입력
string input = Console.ReadLine();
//입력한 문자를, 모두 소문자로 변경
input = input.ToLower();

대문자가 입력되어도 문제없이 정답 처리되는것을 볼 수 있습니다.

 

전체 코드입니다.

namespace HangmanGame
{
    internal class Program
    {
        static void Main()
        {
            //정답 문자열
            string secretWord = "hangman";
            
            //플레이어의 추측 문자 배열
            char[] guessWord = new char[secretWord.Length];

            //입력 시도 횟수
            int attempts = 6;
            //정답판정, 정답시 true
            bool isGuessed = false;

            //추측 문자 배열 초기화
            for(int i = 0; i < secretWord.Length; i++)
            {
                // 정답 문자열의 길이만큼, _로 초기화
                guessWord[i] = '_';
            }

            //정답일때까지, 반복한다.
            while (!isGuessed)
            {

                //게임판...
                Console.WriteLine($"-----Hangman Game-----");
                
                for (int j = 0; j < guessWord.Length; j++)
                {
                    Console.Write(guessWord[j]);
                }
                Console.WriteLine();

                Console.WriteLine($"Left Attempts : {attempts}");
                Console.WriteLine($"Enter Your Guess - {secretWord.Length} letters");
                //사용자의 문자 입력
                string input = Console.ReadLine();

                input = input.ToLower();

                //문자열의 길이 측정
                if(input.Length == secretWord.Length)
                {
                    //정답시, 연산을 하지 않음
                    if (input == secretWord)
                    {
                        //입력을 시도하였기 때문에, 시도 횟수를 줄임
                        attempts--;
                        //정답 처리
                        isGuessed = true;
                        //게임판 지우기
                        Console.Clear();
                    }
                    else
                    {
                        //모든 배열에 접근하기위한 반복문
                        for (int k = 0; k < secretWord.Length; k++)
                        {
                            //같은 위치의 배열끼리 비교
                            if (input[k] == secretWord[k])
                            {
                                //inputArr과, secretWord 배열의 같은경우, guessWord의 내용을 변경
                                guessWord[k] = input[k];
                            }
                        }
                        //시도 횟수 줄이기
                        attempts--;
                        //게임판 지우기
                        Console.Clear();
                    }
                }
                else
                {
                    //글자수가 안맞을경우, 시도 횟수를 줄이지 않고 경고
                    Console.Clear();
                    Console.WriteLine($"No... It's {secretWord.Length} letters word");
                    Console.WriteLine($"You entered {input.Length} letters word... Try again");
                }

                //게임 종료, 추측에 실패시
                if(attempts <= 0 && isGuessed == false)
                {
                    //강제로 반복을 종료함
                    break;
                }
            }

            //추측 성공시
            if(isGuessed == true)
            {
                //정답과 남은 시도횟수를 보여줌
                Console.WriteLine("You Win!!");
                Console.WriteLine($"SecretWord : {secretWord}");
                Console.WriteLine($"Your left attempts is {attempts}");
            }
            else
            {
                Console.WriteLine("GameOver");
                Console.WriteLine($"SecretWord : {secretWord}");
            }
        }
    }
}