소연의_개발일지
article thumbnail

 

토너먼트 승률 계산해보기

 

개발계획서

제출일
2023년 4월 9일
참여인원
박소연
프로젝트 소개
승률 계산해보는 코드 만들기
활동일시
04/07(금)
주요 주제
다른 팀 가치를 가진 8개의 팀이 토너먼트를 1만번 했을 때, 우승확률을 구하여라
개발목적
조건문과 제어문, 반복문을 연습
개발환경
Visual Studio Code / Window OS / C언어
요구사항
[ 문제 규칙 ]
A부터 H까지 팀이 존재. 각 팀은 다른 팀 가치를 가짐.
A: 5, B: 12, C: 8, D: 15, E: 20, F: 4, G: 17, H: 3
각 가치는 수가 높을수록 가치가 높음.


예를 들어 A와 D가 경기하면, A는 5/20의 확률로 A팀이 승리함. 15/20확률로 D가 승리함.
매번 랜덤으로 팀 구성하여 토너먼트를 진행하여 최종 우승을 결정하는 과정을 1회차 토너먼트로 함. 1만회차의 토너먼트 결과 각 팀의 최종 확률을 구하시오.
구현기능
- 각 팀별 승리 확률 출력

코드

(주석추가버전)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int val_a = 5, val_b = 12, val_c = 8, val_d = 15, val_e = 20, val_f = 4, val_g = 17, val_h = 3; // 각 알파벳의 숫자를 선언해줌

int test_function(int num)
{
    /*랜덤으로 뽑은 순서에 알파벳의 값을 넣어준다.
    예를 들어 1이면 a의 값, 2이면 b의 값, 3이면 c의 값... 이런 순으로 대입해주는 함수*/
    if (num == 1)
    {
        return val_a;
    }
    else if (num == 2)
    {
        return val_b;
    }
    else if (num == 3)
    {
        return val_c;
    }
    else if (num == 4)
    {
        return val_d;
    }
    else if (num == 5)
    {
        return val_e;
    }
    else if (num == 6)
    {
        return val_f;
    }
    else if (num == 7)
    {
        return val_g;
    }
    else if (num == 8)
    {
        return val_h;
    }
}
// compare_number(int random_number, int num1, int num2) //이 함수는 수정중... 더 줄일 수 있을것이라고 생각했는데 고민해봐야 될 것같아 적용이 안됨
// {
//     if (random_nubmer <= num1)
//     {
//         return num1;
//     }
//     else
//     {
//         return num2;
//     }
// }

int main() // 메인 함수 시작
{
    srand((unsigned)time(NULL));                                                                                // 스레드 타임 지정
    int random_number = rand() % 8 + 1;                                                                         // 랜덤 값 지정. 1부터 8까지의 숫자만 나오게
    int match_round = 100000;                                                                                   // 몇 번 돌릴지 지정
    int count_a = 0, count_b = 0, count_c = 0, count_d = 0, count_e = 0, count_f = 0, count_g = 0, count_h = 0; // 승리횟수 카운트 해주는 변수들
    for (int j = 0; j < match_round; j++)                                                                       // for문 시작
    {
        int team_1 = random_number, team_2 = random_number, team_3 = random_number, team_4 = random_number, team_5 = random_number, team_6 = random_number, team_7 = random_number, team_8 = random_number;
        int random_match_1 = 0, random_match_2 = 0, random_match_3 = 0, random_match_4 = 0, random_match_5 = 0, random_match_6 = 0, random_match_7 = 0; // 각각의 매치 변수. 8명의 팀은 7번 경기하게 됨
        int first_match_1, first_match_2, first_match_3, first_match_4;                                                                                 // 첫번째 라운드. 2명씩 4번 경기하게 됨
        int second_match_1, second_match_2;                                                                                                             // 두번째 라운드. 1라운드에서 이긴 4명이 2명씩 2번 경기하게 됨
        int final_match;                                                                                                                                // 마지막 라운드. 2라운드에서 이긴 2명이 2명씩 1번 경기하게 됨
        while (team_2 == team_1)                                                                                                                        // 중복 숫자 걸러주는 while문 시작. 팀 2와 1의 숫자가 다를때까지 돈다.
        {
            team_2 = rand() % 8 + 1;
        }
        while (team_3 == team_2 || team_3 == team_1) // 이하 동일
        {
            team_3 = rand() % 8 + 1;
        }
        while (team_4 == team_3 || team_4 == team_2 || team_4 == team_1)
        {
            team_4 = rand() % 8 + 1;
        }
        while (team_5 == team_4 || team_5 == team_3 || team_5 == team_2 || team_5 == team_1)
        {
            team_5 = rand() % 8 + 1;
        }
        while (team_6 == team_5 || team_6 == team_4 | team_6 == team_3 || team_6 == team_2 || team_6 == team_1)
        {
            team_6 = rand() % 8 + 1;
        }
        while (team_7 == team_6 || team_7 == team_5 | team_7 == team_4 || team_7 == team_3 || team_7 == team_2 || team_7 == team_1)
        {
            team_7 = rand() % 8 + 1;
        }
        while (team_8 == team_7 || team_8 == team_6 | team_8 == team_5 || team_8 == team_4 || team_8 == team_3 || team_8 == team_2 || team_8 == team_1)
        {
            team_8 = rand() % 8 + 1;
        } // 중복함수 걸러주는 while문 끝
 
        team_1 = test_function(team_1); // while문에서 뽑아진 난수(1~8)의 숫자에 알파벳의 값을 넣어줌. 위에 함수에서 적용함
        team_2 = test_function(team_2); // 이하 동일
        team_3 = test_function(team_3);
        team_4 = test_function(team_4);
        team_5 = test_function(team_5);
        team_6 = test_function(team_6);
        team_7 = test_function(team_7);
        team_8 = test_function(team_8);

        random_match_1 = rand() % (team_1 + team_2) + 1; // 첫번째 라운드. 경기할 두 팀의 값을 더해서 난수를 만들어 줌
        random_match_2 = rand() % (team_3 + team_4) + 1; // 이하 동일
        random_match_3 = rand() % (team_4 + team_5) + 1;
        random_match_4 = rand() % (team_7 + team_8) + 1;

        /*예를 들어, 5의 값을 가진 A와 15의 값을 가진 B가 대결한다고 한다.
        그럼 A와 B는 각각 5/20, 15/20의 승리확률을 가진다.
        우리는 누가 이길지 결정하기 위해 20중 하나의 숫자를 랜덤으로 뽑는다.
        그 숫자가 5보다 작으면 A가 이기고, 아니면 B가 승리함.  <== 여기서 나는 무조건 작은 수를 왼쪽으로 정렬해줘야 한다고 생각해서 시간이 오래 걸렸다. 비교를 해 줄 필요가 없다. 그냥 '상대값'만 비교하면 되는 거니까.*/

        if (random_match_1 <= team_1) // 두 수를 비교해서 뽑힌 수가 team1보다 작으면 team1이 승리하게 됨
        {
            first_match_1 = team_1;
        }
        else
        {
            first_match_1 = team_2;
        }
        if (random_match_2 <= team_3) // 이하 동일
        {
            first_match_2 = team_3;
        }
        else
        {
            first_match_2 = team_4;
        }
        if (random_match_3 <= team_5)
        {
            first_match_3 = team_5;
        }
        else
        {
            first_match_3 = team_6;
        }
        if (random_match_4 <= team_7)
        {
            first_match_4 = team_7;
        }
        else
        {
            first_match_4 = team_8;
        }

        random_match_5 = rand() % (first_match_1 + first_match_2) + 1; // 두번째 매치. 각각의 난수값을 뽑음
        random_match_6 = rand() % (first_match_3 + first_match_4) + 1;

        if (random_match_5 <= first_match_1) // 첫번째 승리한 팀의 수보다 난수값이 작으면 첫번째 팀 승리
        {
            second_match_1 = first_match_1;
        }
        else
        {
            second_match_1 = first_match_2; // 아니면 두번째 팀 승리
        }
        if (random_match_6 <= first_match_3) // 이하 동일
        {
            second_match_2 = first_match_3;
        }
        else
        {
            second_match_2 = first_match_4;
        }

        random_match_7 = rand() % (second_match_1 + second_match_2); // 마지막 라운드. 두번째 승리한 두 팀의 숫자를 더해 난수를 뽑아줌

        if (random_match_7 <= second_match_1) // 뽑은 수가 second_match_1보다 작으면 second_team_1승리
        {
            final_match = second_match_1;
        }
        else // 아니면 second_team_2가 승리
        {
            final_match = second_match_2;
        }
        // 비교 끝. second_match_1과 2에서 승리한 사람은 final_match에 저장됨

        if (final_match == val_a) // 마지막 승리한 사람의 값을 초기 알파벳 값과 비교해줘서 수를 카운트해준다.
        {
            count_a++;
        }
        else if (final_match == val_b) // 이하 동일
        {
            count_b++;
        }
        else if (final_match == val_c)
        {
            count_c++;
        }
        else if (final_match == val_d)
        {
            count_d++;
        }
        else if (final_match == val_e)
        {
            count_e++;
        }
        else if (final_match == val_f)
        {
            count_f++;
        }
        else if (final_match == val_g)
        {
            count_g++;
        }
        else if (final_match == val_h)
        {
            count_h++;
        } // 숫자 세기 끝
    }
 
    // 결과 출력
    printf("Team A's win rate: %.2f%%\n", (float)count_a / match_round * 100); // %는 %%으로 표시해야 됨.
    printf("Team B's win rate: %.2f%%\n", (float)count_b / match_round * 100); // %.2f는 소수점 두번째 자리수까지 출력되게 함
    printf("Team C's win rate: %.2f%%\n", (float)count_c / match_round * 100); // int형 자료를 나눴으므로 float을 앞에 추가해줌
    printf("Team D's win rate: %.2f%%\n", (float)count_d / match_round * 100);
    printf("Team E's win rate: %.2f%%\n", (float)count_e / match_round * 100);
    printf("Team F's win rate: %.2f%%\n", (float)count_f / match_round * 100);
    printf("Team G's win rate: %.2f%%\n", (float)count_g / match_round * 100);
    printf("Team H's win rate: %.2f%%\n", (float)count_h / match_round * 100);

    return 0;
} // main함수 끝
 

코드실행화면

 


오류 수정 및 고민

1) Arithmetic exception 에러

특정 팀의 승리 횟수 변수가 초기화 되지 않았거나, 계산식에서 잘못된 변수를 사용하거나, 또는 match_round 변수가 0이라면, 나누는 값이 0이 되어 코드에서 이런 에러가 뜬다고 한다.

처음에 작은 수를 왼쪽으로 해야한다고 생각해서 한 변수에 계속 숫자를 대입하다 보니 나누는 과정에서 0이 나온게 아닌가 싶다.

 

2) 값 비교연산자(==) 와 값 대입연산자(=) 헷갈림

코드에서 == 연산자를 사용할 때, 값을 비교하고자 하는 것이 아닌 값을 대입하고자 했기 때문에 문제가 발생했다.

→대입연산자(=)로 바꾸고 해결 완

 

문제 자체에 대한 접근방식과 고민은 실패보고서(4/7)와 학습일지(4/8) 에 작성해 놓았다.


개발일지/회고

이제 모든 과제를 끝낸 것 같아서 후련한 기분이지만

왠지 c언어를 알아가다가 보내주는 것 같아서 영 아쉽기 그지없다.

육개장 맛나게 먹으려고 젓가락 뜨는 와중에 멈추고 참깨라면 먹으려 물끓이러 가야하는 이 기분..

하지만 파이썬을 만나면 이 고민도 해결될것이라 믿는다. 잘있어라 씨언어.

 

그리고 함수 사용을 온전히 이해못하고 하고 있는 것 같은 기분이 든다.

이번 과제에서도 사용하긴 했으나 적당히 부분적으로만 적용했다.

함수 적용 방식을 더 연습해야겠다.

 

profile

소연의_개발일지

@ssoyxon

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!