C++로 구현하는 가위바위보 승패 판정 로직

가위바위보는 전 세계적으로 인기 있는 손 게임입니다. 단순하면서도 심리전 요소가 있어 많은 사람에게 사랑받고 있습니다. 이 게임의 규칙은 다음과 같습니다:

  • 가위는 보를 이깁니다.
  • 바위는 가위를 이깁니다.
  • 보는 바위를 이깁니다.

주어진 입력에 따라 두 플레이어(Player1, Player2)의 가위바위보 게임 결과를 판별하는 프로그램을 작성해야 합니다.

입력 형식

첫 줄에는 총 게임 횟수를 나타내는 정수 N (1 ≤ N ≤ 100)이 주어집니다.

이어지는 N개의 각 줄에는 Player1과 Player2가 낸 선택이 공백으로 구분되어 주어집니다. 선택은 "Rock", "Scissors", "Paper" 중 하나이며, 대소문자를 구분합니다.

N
S1 S2
...

출력 형식

N개의 줄에 걸쳐 각 게임의 승자를 출력합니다. Player1이 이기면 "Player1", Player2가 이기면 "Player2"를 출력합니다. 비기면 "Tie"를 출력합니다.

입력 예시

3
Rock Scissors
Paper Paper
Rock Paper

출력 예시

Player1
Tie
Player2

이 문제는 다양한 방식으로 해결할 수 있으며, 코드를 점진적으로 개선하는 과정을 통해 C++ 프로그래밍 기법을 익힐 수 있습니다.

접근 방식 1: 단순 조건문 활용

가장 직관적인 방법은 모든 가능한 경우의 수를 직접 비교하는 것입니다. 승리 조건, 무승부 조건, 그리고 그 외의 패배 조건을 순서대로 검사할 수 있습니다. 예를 들어, Player1이 이기는 세 가지 경우를 먼저 확인하고, 그 다음 무승부 조건을 확인한 후, 나머지 경우는 Player2의 승리로 처리할 수 있습니다.

#include <iostream>
#include <string> // std::string을 사용하기 위해 포함

int main() {
    std::ios_base::sync_with_stdio(false); // 입출력 속도 향상
    std::cin.tie(NULL); // std::cin과 std::cout의 동기화 해제

    int gameCount;
    std::cin >> gameCount;

    for (int i = 0; i < gameCount; ++i) {
        std::string player1Move, player2Move;
        std::cin >> player1Move >> player2Move;

        // Player1이 이기는 경우
        if ((player1Move == "Rock" && player2Move == "Scissors") ||
            (player1Move == "Scissors" && player2Move == "Paper") ||
            (player1Move == "Paper" && player2Move == "Rock")) {
            std::cout << "Player1\n";
        }
        // 무승부인 경우
        else if (player1Move == player2Move) {
            std::cout << "Tie\n";
        }
        // 그 외 모든 경우 (Player2 승리)
        else {
            std::cout << "Player2\n";
        }
    }
    return 0;
}

접근 방식 2: 문자열 첫 글자 비교

이전 방식에서 문자열 전체를 비교하는 대신, 각 선택의 첫 글자만 비교하여 효율성을 높일 수 있습니다. "Rock", "Scissors", "Paper"는 모두 다른 첫 글자(R, S, P)를 가지고 있으므로 이 방법이 유효합니다.

#include <iostream>
#include <string>

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int numGames;
    std::cin >> numGames;

    for (int i = 0; i < numGames; ++i) {
        std::string p1Choice, p2Choice;
        std::cin >> p1Choice >> p2Choice;

        char p1Initial = p1Choice[0];
        char p2Initial = p2Choice[0];

        // Player1 승리 조건 (첫 글자 비교)
        if ((p1Initial == 'R' && p2Initial == 'S') ||
            (p1Initial == 'S' && p2Initial == 'P') ||
            (p1Initial == 'P' && p2Initial == 'R')) {
            std::cout << "Player1\n";
        }
        // 무승부 조건
        else if (p1Initial == p2Initial) {
            std::cout << "Tie\n";
        }
        // Player2 승리 조건
        else {
            std::cout << "Player2\n";
        }
    }
    return 0;
}

접근 방식 3: 함수를 이용한 모듈화

코드의 가독성을 높이고 재사용성을 위해 게임 결과 판별 로직을 별도의 함수로 분리할 수 있습니다. 메인 함수는 입력과 출력을 담당하고, 승패 판정은 다른 함수에 위임합니다.

#include <iostream>
#include <string>

// 게임 결과를 판별하여 정수형으로 반환하는 함수
// 0: Tie, 1: Player1 승리, 2: Player2 승리
int determineWinner(const std::string& p1Choice, const std::string& p2Choice) {
    char p1Initial = p1Choice[0];
    char p2Initial = p2Choice[0];

    if ((p1Initial == 'R' && p2Initial == 'S') ||
        (p1Initial == 'S' && p2Initial == 'P') ||
        (p1Initial == 'P' && p2Initial == 'R')) {
        return 1; // Player1 승리
    } else if (p1Initial == p2Initial) {
        return 0; // 무승부
    } else {
        return 2; // Player2 승리
    }
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int numGames;
    std::cin >> numGames;

    for (int i = 0; i < numGames; ++i) {
        std::string player1Move, player2Move;
        std::cin >> player1Move >> player2Move;

        int result = determineWinner(player1Move, player2Move);

        if (result == 1) {
            std::cout << "Player1\n";
        } else if (result == 2) {
            std::cout << "Player2\n";
        } else {
            std::cout << "Tie\n";
        }
    }
    return 0;
}

접근 방식 4: 수치화 및 모듈로 연산 활용

가위바위보 게임은 순환적인 특징을 가집니다. 이를 수치화하여 모듈로(%) 연산을 통해 승패를 판정할 수 있습니다. 예를 들어, 바위=0, 가위=1, 보=2와 같이 값을 할당합니다. Player1의 선택 값에서 Player2의 선택 값을 뺀 후 3으로 나눈 나머지를 통해 결과를 예측할 수 있습니다.

여기서 중요한 규칙은 `(Player1_값 - Player2_값 + 3) % 3` 입니다:

  • 결과가 0이면 무승부 (Player1_값 == Player2_값)
  • 결과가 1이면 Player2 승리
  • 결과가 2이면 Player1 승리
#include <iostream>
#include <string>

// 가위바위보 선택을 정수 값으로 변환하는 함수
// Rock: 0, Scissors: 1, Paper: 2
int getMoveValue(const std::string& choice) {
    char initial = choice[0];
    if (initial == 'R') return 0; // Rock
    if (initial == 'S') return 1; // Scissors
    return 2; // Paper
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int numRounds;
    std::cin >> numRounds;

    for (int i = 0; i < numRounds; ++i) {
        std::string move1, move2;
        std::cin >> move1 >> move2;

        int val1 = getMoveValue(move1);
        int val2 = getMoveValue(move2);

        // Player1과 Player2의 값 차이를 이용한 승패 판정
        // (Player1_값 - Player2_값 + 3) % 3
        // 결과 0: Tie, 1: Player2 승리, 2: Player1 승리
        int outcome = (val1 - val2 + 3) % 3;

        if (outcome == 0) { // 무승부
            std::cout << "Tie\n";
        } else if (outcome == 2) { // Player1 승리
            std::cout << "Player1\n";
        } else { // outcome == 1, Player2 승리
            std::cout << "Player2\n";
        }
    }
    return 0;
}

접근 방식 5: 결과 메시지 배열 활용

이전 방식에서 도출된 모듈로 연산 결과를 인덱스로 사용하여 미리 정의된 결과 메시지 배열에서 직접 출력값을 가져올 수 있습니다. 이렇게 하면 조건문을 줄이고 코드를 더욱 간결하게 만들 수 있습니다.

#include <iostream>
#include <string>
#include <vector> // std::vector를 사용하기 위해 포함

// 가위바위보 선택을 정수 값으로 변환하는 함수
// Rock: 0, Scissors: 1, Paper: 2
int getMoveNumericalValue(const std::string& choice) {
    char initial = choice[0];
    if (initial == 'R') return 0; // Rock
    if (initial == 'S') return 1; // Scissors
    return 2; // Paper
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int totalGames;
    std::cin >> totalGames;

    // (val1 - val2 + 3) % 3 결과에 따른 메시지 배열
    // 인덱스 0: Tie
    // 인덱스 1: Player2 승리
    // 인덱스 2: Player1 승리
    std::vector<std::string> gameResults = {"Tie\n", "Player2\n", "Player1\n"};

    for (int i = 0; i < totalGames; ++i) {
        std::string firstPlayerMove, secondPlayerMove;
        std::cin >> firstPlayerMove >> secondPlayerMove;

        int firstVal = getMoveNumericalValue(firstPlayerMove);
        int secondVal = getMoveNumericalValue(secondPlayerMove);

        int resultIndex = (firstVal - secondVal + 3) % 3;
        std::cout << gameResults[resultIndex];
    }
    return 0;
}

접근 방식 6: STL `std::map` 활용

문자열로 된 선택을 정수 값으로 변환하는 작업을 `std::map`을 사용하여 더욱 유연하게 처리할 수 있습니다. 이는 특히 매핑할 문자열이 많거나 복잡할 때 유용합니다. `std::map`은 키-값 쌍을 저장하며, 키(여기서는 가위바위보 선택 문자열)를 통해 값(해당하는 정수)을 빠르게 찾을 수 있습니다.

#include <iostream>
#include <string>
#include <map>     // std::map을 사용하기 위해 포함
#include <vector>  // std::vector를 사용하기 위해 포함

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int roundCount;
    std::cin >> roundCount;

    // 가위바위보 선택 문자열을 정수 값으로 매핑
    std::map<std::string, int> moveMap;
    moveMap["Rock"] = 0;
    moveMap["Scissors"] = 1;
    moveMap["Paper"] = 2;

    // 결과 메시지 배열 (인덱스: 0=Tie, 1=Player2, 2=Player1)
    std::vector<std::string> finalOutcomes = {"Tie\n", "Player2\n", "Player1\n"};

    for (int i = 0; i < roundCount; ++i) {
        std::string p1Hand, p2Hand;
        std::cin >> p1Hand >> p2Hand;

        int p1Val = moveMap[p1Hand];
        int p2Val = moveMap[p2Hand];

        // (Player1_값 - Player2_값 + 3) % 3 결과에 따른 인덱스 계산
        int outcomeIdx = (p1Val - p2Val + 3) % 3;
        std::cout << finalOutcomes[outcomeIdx];
    }
    return 0;
}

태그: C++ algorithm competitive programming string manipulation Modulo Arithmetic

10월 6일 19:55에 게시됨