본문 바로가기

개발 이것저것

코딩으로 몬티홀 딜레마 간파하기

 

머리로 이해가 안 되면 직접 해보면 된다. 하지만 확률 문제에 한해서는 law of probability 안에서 law of large number가 정의하듯이 무식하게 많이 해봐야 실제 확률과 비슷한 근삿값을 얻을 수 있다. 문을 만 번씩 열기는 너무 귀찮기에 코딩으로 선택을 바꾸었을 때 차가 당첨될 확률을 계산해보도록 하자.


import java.util.*;
public class monty
{
    public static void main(String[] args)
    {   
        Scanner console = new Scanner(System.in);
        System.out.print("How many runs? >>> ");
        double cases = console.nextInt();
        boolean car = false;
        double successes = 0;
        for(int i=0; i<cases; i++)
        {
            car = run();
            if(car)
            {
                successes++;
            }
        }
        System.out.println(successes/cases*100+"%");
    }

 

이 코드는 4개의 파트로 이루어져 있는데 첫번째로 메인 클래스는 시뮬레이션을 몇 번 돌리고 싶은지 물어보고 다른 클래스들을 호출하여 처음 선택을 바꿨을 때 차를 얻을 확률을 계산한다.


 public static boolean run()
    {
        boolean[] doors = new boolean[3];
        Random rand = new Random(); 
        int car_is_at = rand.nextInt(3);
        doors[car_is_at] = true;
        //car is at doors[car_is_at]
        int first_guess = rand.nextInt(3);
        //first_guess is the guess
        int revealed_to_be_sheep = reveal_sheep(first_guess, doors);
        //one of the non guess is opened to be a sheep
        int final_guess = final_choice_decider(first_guess,revealed_to_be_sheep);
        if(doors[final_guess]==true)
        {
            return true;
        }
        return false;
    }

Run 클래스는 doors라는 boolean array를 생성하는데 이때 칸은 3개이고 처음에는 다 false로 채워진다.

그 후 랜덤 클래스를 이용해 3칸중 한 곳에 차를 넣는다(true로 바꾼다).

첫 번째 선택을 0~2까지 랜덤으로 정한다.


public static int reveal_sheep(int first_guess, boolean[] doors)
    {
        Random rand = new Random(); 
        int revealed_to_be_sheep = rand.nextInt(3);
        if(revealed_to_be_sheep!=first_guess && doors[revealed_to_be_sheep]==false)
        {
            return revealed_to_be_sheep;
        }
        return reveal_sheep(first_guess,doors);
    }

reveal_sheep 클래스를 통해 첫 번째 선택을 뺀 나머지 두 선택지 중 한 가지는 무조건 양이 있기 때문에, 그 선택지를 보여준다(코딩상에서는 그 선택지를 배제하는 조건으로 코딩하면 된다).

여기서 랜덤 클래스를 이용했기 때문에 조건에 안 맞을경우 재귀(recursion) 클래스를 이용해 조건에 맞을 때까지 리턴을 못하게 하면 된다.


public static int final_choice_decider(int first_guess, int revealed_to_be_sheep)
    {
        Random rand = new Random(); 
        int final_choice = rand.nextInt(3);
        if(final_choice!=first_guess && final_choice!=revealed_to_be_sheep)
        {
            return final_choice;
        }
        return final_choice_decider(first_guess,revealed_to_be_sheep);
    }
}

final_choice_decider 클래스는 간단히 첫번째 선택지랑 양이 있는 선택지를 배제한 마지막 선택지를 리턴하게 된다. 여기에서도 조건에 부합하지 않는다면 재귀 클래스로 조건에 부합할 때까지 리턴 못하게 하면 된다. 


이제 run 클래스에서 차를 찾았다면 true, 아니면 false를 메인 클래스에 리턴하게 된다. 메인 클래스는 처음에 시뮬레이션 숫자만큼 위 과정을 반복하고, 마지막에 차를 찾은 확률을 계산한다.

 

 How many runs? >>> 10000
67.13%

 10,000번 실행 할시 67.13%라고 계산하였고

 How many runs? >>> 100000
66.632%

100,000번 실행 할시 66.632%로 계산하였다.


 

코딩을 통해 답인 2/3(66.6666..%) 매우 근사한 값을 계산 해냈다!

 

 

 

'개발 이것저것' 카테고리의 다른 글

고1때 만든 프로그램 다시 보기 #1  (2) 2018.12.30