가위, 바위, 보
문제
다음 조건을 만족하는 가위바위보 게임을 작성하시오.
사용자는 바위, 가위, 보, 종료 중 하나를 숫자로 입력한다.
게임은 사용자가 종료를 입력할 때까지 반복된다.
컴퓨터는 가위, 바위, 보 중 하나를 임의로 선택한다.
사용자의 선택과 컴퓨터의 선택을 비교하여 승리, 패배, 무승부를 출력한다.
유효하지 않은 값을 입력하면 유효하지 않은 입력임을 출력하고 다시 입력을 받는다.
풀이
가위, 바위, 보는 반복문과 조건문으로 풀 수 있는 단순한 문제이다.
하지만 가독성을 위해 enum을 도입하거나, 승패를 판단하는 규칙을 더 명확하게 정리해 볼 여지가 있는 문제이기도 하다.
하드 코딩
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
srand((unsigned int)time(NULL));
while (1)
{
int user_choice;
printf("Rock(1), Scissors(2), Paper(3), Exit(0): ");
if (scanf("%d", &user_choice) != 1)
{
int buffer_char;
while ((buffer_char = getchar()) != '\n' && buffer_char != EOF)
;
printf("Please enter a number.\n");
continue;
}
if (user_choice == 0)
break;
if (user_choice < 1 || user_choice > 3)
{
printf("Invalid choice. Please choose 1, 2, or 3.\n");
continue;
}
int computer_choice = rand() % 3 + 1;
printf("User: ");
if (user_choice == 1)
printf("Rock");
else if (user_choice == 2)
printf("Scissors");
else
printf("Paper");
printf(", Computer: ");
if (computer_choice == 1)
printf("Rock");
else if (computer_choice == 2)
printf("Scissors");
else
printf("Paper");
printf("\n");
if (user_choice == 1)
{
if (computer_choice == 1)
printf("Draw.\n");
else if (computer_choice == 2)
printf("You win.\n");
else
printf("You lose.\n");
}
else if (user_choice == 2)
{
if (computer_choice == 1)
printf("You lose.\n");
else if (computer_choice == 2)
printf("Draw.\n");
else
printf("You win.\n");
}
else
{
if (computer_choice == 1)
printf("You win.\n");
else if (computer_choice == 2)
printf("You lose.\n");
else
printf("Draw.\n");
}
}
return 0;
}
입력값을 0, 1, 2, 3 같은 숫자 리터럴만으로 다루면 user_choice == 2를 보았을 때 2가 무엇을 의미하는지 바로 떠올리기 어렵다.
또한 지금 코드는 사용자가 가위인 경우, 바위인 경우, 보인 경우를 각각 나누고, 그 안에서 컴퓨터의 선택을 다시 비교해 승패를 판단한다.
즉 승패 판단에 필요한 경우의 수를 일일이 나열하는 형태라 코드가 길어지고 읽기 어려워진다.
enum 활용
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
enum Choice
{
CHOICE_EXIT = 0,
CHOICE_ROCK = 1,
CHOICE_SCISSORS = 2,
CHOICE_PAPER = 3
};
int main(void)
{
srand((unsigned int)time(NULL));
while (1)
{
int input_value;
printf("Rock(1), Scissors(2), Paper(3), Exit(0): ");
if (scanf("%d", &input_value) != 1)
{
int buffer_char;
while ((buffer_char = getchar()) != '\n' && buffer_char != EOF)
;
printf("Please enter a number.\n");
continue;
}
if (input_value == CHOICE_EXIT)
break;
if (input_value < CHOICE_ROCK || input_value > CHOICE_PAPER)
{
printf("Invalid choice. Please choose 1, 2, or 3.\n");
continue;
}
enum Choice user_choice = (enum Choice)input_value;
enum Choice computer_choice = (enum Choice)(rand() % 3 + 1);
printf("User: ");
if (user_choice == CHOICE_ROCK)
printf("Rock");
else if (user_choice == CHOICE_SCISSORS)
printf("Scissors");
else
printf("Paper");
printf(", Computer: ");
if (computer_choice == CHOICE_ROCK)
printf("Rock");
else if (computer_choice == CHOICE_SCISSORS)
printf("Scissors");
else
printf("Paper");
printf("\n");
if (user_choice == computer_choice)
printf("Draw.\n");
else if ((user_choice == CHOICE_ROCK && computer_choice == CHOICE_SCISSORS) ||
(user_choice == CHOICE_SCISSORS && computer_choice == CHOICE_PAPER) ||
(user_choice == CHOICE_PAPER && computer_choice == CHOICE_ROCK))
printf("You win.\n");
else
printf("You lose.\n");
}
return 0;
}
enum을 사용하면 숫자 리터럴 대신 의미 있는 이름으로 값을 비교할 수 있다.
Lookup Table 활용
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define INPUT_EXIT 0
enum Hand
{
HAND_ROCK,
HAND_SCISSORS,
HAND_PAPER,
HAND_COUNT
};
int main(void)
{
const char* hand_names[HAND_COUNT] = {
"Rock",
"Scissors",
"Paper"
};
const char* result_table[HAND_COUNT][HAND_COUNT] = {
/* Rock Scissors Paper */
/* Rock */ {"Draw.", "You win.", "You lose."},
/* Scissors */ {"You lose.", "Draw.", "You win."},
/* Paper */ {"You win.", "You lose.", "Draw."}
};
srand((unsigned int)time(NULL));
while (1)
{
int input_value;
printf("Rock(1), Scissors(2), Paper(3), Exit(0): ");
if (scanf("%d", &input_value) != 1)
{
int buffer_char;
while ((buffer_char = getchar()) != '\n' && buffer_char != EOF)
;
printf("Please enter a number.\n");
continue;
}
if (input_value == INPUT_EXIT)
break;
int hand_index = input_value - 1;
if (hand_index < HAND_ROCK || hand_index > HAND_PAPER)
{
printf("Invalid choice. Please choose 1, 2, or 3.\n");
continue;
}
enum Hand user_hand = (enum Hand)hand_index;
enum Hand computer_hand = (enum Hand)(rand() % HAND_COUNT);
printf("User: %s, Computer: %s\n",
hand_names[user_hand],
hand_names[computer_hand]);
printf("%s\n", result_table[user_hand][computer_hand]);
}
return 0;
}
가위바위보는 사용자의 선택 3가지와 컴퓨터의 선택 3가지를 조합하면 가능한 경우의 수가 9개로 정해진다.
따라서 각 조합의 결과를 표처럼 정리할 수 있고, 이를 2차원 배열에 미리 저장해 두면 인덱스로 바로 조회할 수 있다.
사용자 입력은 1, 2, 3으로 받지만 result_table 배열은 0부터 시작하는 인덱스를 사용한다.
그래서 input_value - 1을 통해 입력값을 0, 1, 2로 변환한 뒤 배열의 인덱스로 사용한다.
패 이름도 마찬가지로 배열에서 조회한다.
덕분에 조건문으로 길게 나열하던 코드를 훨씬 간결하게 만들 수 있다.