부트캠프/사전캠프

[내일배움 사전캠프_2025JUN16] 콘솔 행맨 게임

Young_A 2025. 6. 16. 17:59

콘솔 행맨 게임

 

원래 계획은 유니티 2주차를 진행하는 거였으나...

어제 노트북 업데이트 중에 살짝 충격이 갔었는데 그걸로 문제가 생겼는지, 노트북이 이상해졌다.

너무 느려서 일단 저녁에 다시 업데이트를 진행해보는 걸로 하고, 당장 쓸 수 있는 비주얼스튜디오로 행맨 게임을 만들어보았다.

 

행맨은... 다들 알겠지만 정해진 영어 단어를 한 글자씩 제시하며 맞추는 게임이다.

일단 완성 코드는 아래와 같다.

string secretWord = "Hangman";
char[] guessWord = new char[secretWord.Length];
char guessLetter;
int attempts = 6;
bool wordGuessed  = false;

for (int i = 0; i < guessWord.Length; i++)
{
    guessWord[i] = '_';
}


do
{
    Console.Write($"문자를 제시하세요.({attempts}회 남음)   {string.Concat(guessWord)}   :");
    guessLetter = Console.ReadKey(true).KeyChar;
    Console.WriteLine(guessLetter);


    for (int i = 0; i < guessWord.Length; i++)
    {
        if (char.ToLower(guessLetter) == secretWord[i] || char.ToUpper(guessLetter) == secretWord[i])
        {
            guessWord[i] = secretWord[i];
        }
    }

    if (secretWord == string.Concat(guessWord))
    {
        wordGuessed = true;
        Console.WriteLine("정답을 맞추셨습니다!");
        break;
    }
    else
    {
        attempts--;
        if (attempts == 0)
        {
            Console.WriteLine($"정답은 {secretWord} 이었습니다...");
        }
    }

} while (!wordGuessed || attempts != 0);

처음에는 char[] 를 출력하려고 guessWord.ToString을 이용해서 출력했는데 자꾸 저렇게 나왔다.

System.Char[] 대신에 ______ 혹은 han_man 과 같이 현재 단어 진행 상황이 표현되어야 맞다.

알고보니 char[].ToString()은 char 배열의 내용을 반환하는 것이 아니라, 배열의 타입 정보를 문자열로 반환하기 때문. 

Console.Write($"문자를 제시하세요.({attempts}회 남음)   {string.Concat(guessWord)}   :");

Concat(char[])는 char 배열을 매개변수로 받아 배열의 모든 문자들을 하나의 문자열로 합쳐서 반환하므로 내가 원하는 결과가 나올 수 있었다.


게임은 잘 진행되는데 위와 같이 대문자 H와 소문자 h를 구분하는 문제를 발견했다.

대소문자 구분을 안하는 것이 게임의 진행 맥락 상 맞을 것 같아서 아래와 같이 입력값의 소문자와 대문자를 || 연산자를 이용하여 비교했다.

if (char.ToLower(guessLetter) == secretWord[i] || char.ToUpper(guessLetter) == secretWord[i])
{
	guessWord[i] = secretWord[i];
}

그 결과 소문자 'h'를 입력해도 맞은 걸로 출력이 되고 있다.


 

하지만 또 다른 문제점이 발생되었는데, 바로 "hangman"과 "Hangman"은 아래와 같은 비교연산자를 사용했을때 다른 결과값이 나온다는 것이다.

if (secretWord == string.Concat(guessWord)) //"Hangman"과 "hangman"은 서로 달라서 정답처리가 될 수 없음...
{
    wordGuessed = true;
    Console.WriteLine("정답을 맞추셨습니다!");
    break;
}

 

내 머릿 속에 떠오른 방법들은,

1. 정답을 확인할때마다 string.ToLower(secretWord), string.ToLower(string.Concat(guessWord) 이 둘을 비교하는 것

   (기각) 매번 ToLower()가 두번이나 실행되므로 비효율적이고 일단 코드가 안예쁘다.

2. 반복문 실행 전에 secretWord = string.ToLower(secretWord)로 대문자를 소문자로 변환하고, letter를 입력 받을 때마다 ToLower()를 이용하여 대문자를 입력을 차단(소문자로 변환)하는 것.

   (기각) 지금이야 "Hangman" 한 단어지만, "New Zealand"와 같은 대문자 표기가 필요한 경우가 생길 수도 있다!

3. (채택) 정답을 맞췄을 때 아래와 같이 guessWord[i]에 secretWord[i]를 대입할 것. 즉 대문자일지 소문자일지 모르는 인풋을 정답에 넣는 것이 아니라 애초에 보기좋게 셋팅되어있는 secretWord에서 글자를 따와 정답지에 적어주면 된다.

//    guessWord[i] = guessLetter;
    guessWord[i] = secretWord[i];

이제 정답을 맞출 수 있게 되었다!


참고로 이번 행맨 게임에서는 Console.ReadLine()이 아니라 Console.ReadKey(true).KeyChar를 사용했다.

단어를 입력 받는 것이 아니라, 글자(letter)를 입력 받는 게임 진행 상 이게 조금 더 맥락에 맞을 것 같다고 판단했기 때문이다.

Console.ReadKey()는 사용자가 키를 누를 때까지 대기하며, 누른 키에 대한 정보를 ConsoleKeyInfo 구조체로 반환한다고 한다.

여기에 KeyChar 속성을 이용해서 현재 입력된 키의 문자 값을 나타낼 수 있다.


느낀점

코드를 짜면서 보완하거나 추가하면 괜찮을 것 같은 기능들이 떠올랐는데 막상 정리하려고 하니 생각이 안난다.

특정 단어들을 조합한 string 배열에서 random하게 단어를 뽑아 게임을 시작할 수 있도록 하기...?

문자만 입력 받을 수 있도록 제한하기...?

책상 위에 노트를 두고 생각날때마다 메모하면서 진행했어야했는데, 현재 개발 환경이... 아직 앉은뱅이 책상이라서... :(

 

노트북 속도가 매우 느려서, 시간을 날렸다는 생각이 크게 들었다.

본체를 얼른 조립하고 사용해야하는데, 책상을 둘 방에 콘센트가 없다. 벽지 작업을 하고나서 마무리를 안한게... 이게... 몇년째야~!~!


내일 학습 할 것은 무엇인지

내일은 오늘 하지 못한 유니티 2주차를 끝낼 수 있다면 끝내보려고 한다.

안된다면 역시나 팀플용으로 남겨두었던 숫자야구게임을 진행할 것이다.