
function monty_hall ( )

%*****************************************************************************80
%
%% monty_hall() tests monty_hall_simulation().
%
%  Licensing:
%
%    This code is distributed under the MIT license. 
%
%  Modified:
%
%    12 January 2025
%
%  Author:
%
%    Original Python code by Christian Hill.
%    This version by John Burkardt
%
%  Reference:
%
%    Christian Hill,
%    Learning Scientific Programming With Python,
%    Second Edition,
%    Cambridge University Press, 2020
%    ISBN: 978-1-108-74591-8
%
  timestamp ( );

  fprintf ( 1, '\n' );
  fprintf ( 1, 'monty_hall():\n' );
  fprintf ( 1, '  MATLAB/Octave version %s\n', version ( ) );
  fprintf ( 1, '  monty_hall_simulation() simulates the Monty Hall\n' );
  fprintf ( 1, '  prize winning game, in which a prize is hidden behind\n' );
  fprintf ( 1, '  one of several doors.\n' );
  fprintf ( 1, '\n' );
  ntrials = 100000;
  fprintf ( 1, '  Number of trials = %d\n', ntrials );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'Doors  No-switch winning      Switch winning\n' );
  fprintf ( 1, '       Observed  Predicted  Observed  Predicted\n' );
  fprintf ( 1, '   n                 1/n              n-1/n-2 * 1/n\n' );
  fprintf ( 1, '' );

  for ndoors = 3 : 10

    switch_doors = false;
    wins_noswitch = 0;
    for i = 1 : ntrials
      win = monty_hall_simulation ( switch_doors, ndoors );
      if ( win ) 
        wins_noswitch = wins_noswitch + 1;
      end
    end
    ratio_noswitch = wins_noswitch / ntrials;

    switch_doors = true;
    wins_switch = 0;
    for i = 1 : ntrials
      win = monty_hall_simulation ( switch_doors, ndoors );
      if ( win )
        wins_switch = wins_switch + 1;
      end
    end
    ratio_switch = wins_switch / ntrials;

    [ prob_noswitch, prob_switch ] = monty_hall_probabilities ( ndoors );

    fprintf ( 1, '  %2d  %8.4g  %8.4g  %8.4g  %8.4g\n', ...
      ndoors, ratio_noswitch, prob_noswitch, ratio_switch, prob_switch );

  end
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'monty_hall():\n' );
  fprintf ( 1, '  Normal end of execution.\n' );

  timestamp ( );

  return
end
function [ prob_noswitch, prob_switch ] = monty_hall_probabilities ( ndoors )

%*****************************************************************************80
%
%% monty_hall_probabilities() returns Monty Hall winning probabilities.
%
%  Discussion:
%
%    For no switch, you have 1/ndoors chance of picking the prize door.
%
%    For switch, you have 1/ndoors chance of switching from the prize door,
%    so a (ndoors-1)/ndoors chance of having a second chance at the prize.
%    In this second chance, there are ndoors-2 doors, and so you have a
%    1/(ndoors-2) chance of success.  Thus, overall, you have a
%    (ndoors-1)/ndoors * 1/(ndoors-2) chance of rejecting a nonprize 
%    initial selection and successfully choosing the prize on your
%    second guess.
%
%  Licensing:
%
%    This code is distributed under the MIT license. 
%
%  Modified:
%
%    26 August 2019
%
%  Author:
%
%    John Burkardt
%
%  Input:
%
%    integer ndoors: the number of doors.
%
%  Output:
%
%    real prob_noswitch, prob_switch: the probability of winning the 
%    Monty Hall game with no-switch or switch strategies.
%
  prob_noswitch = 1.0 / ndoors;
  prob_switch = ( ndoors - 1 ) / ndoors / ( ndoors - 2 );

  return
end

function win = monty_hall_simulation ( switch_doors, ndoors )

%*****************************************************************************80
%
%% monty_hall_simulation() simulates the Monty Hall prize game.
%
%  Licensing:
%
%    This code is distributed under the MIT license. 
%
%  Modified:
%
%    26 August 2022
%
%  Author:
%
%    Original Python version by Christian Hill.
%    This version by John Burkardt.
%
%  Reference:
%
%    Christian Hill,
%    Learning Scientific Programming With Python,
%    Second Edition,
%    Cambridge University Press, 2020
%    ISBN: 978-1-108-74591-8
%
%  Input:
%
%    boolean switch_doors: True if the user plans to switch.
%
%    integer ndoors: the number of doors.  Usually 3.
%    Must be at least 3.
%
%  Output:
%
%    boolean WIN: TRUE if the user chose the prize, FALSE otherwise.
%
  if ( ndoors < 3 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'monty_hall_simulation(): Fatal error!\n' );
    fprintf ( 1, '  Number of doors must be at least 3!\n' );
    error ( 'monty_hall_simulation(): Fatal error!\n' );
  end
%
%  Randomly choose prize_door, the door hiding the prize.
%
  prize_door = randi ( [ 1, ndoors ], 1 );
%
%  The user chooses a door at random.
%
  chosen_door = randi ( [ 1, ndoors ], 1 );
%
%  List all the doors which could be revealed.
%  This excludes the door choose by the user,
%  and the prize door (which could be the same).
%
  revealable_door = [];
  revealable_num = 0;

  for door = 1 : ndoors
    if ( ( door ~= chosen_door ) && ( door ~= prize_door ) )
      revealable_door = [ revealable_door, door ];
      revealable_num = revealable_num + 1;
    end
  end
%
%  Choose one of the revealable doors.
%
  revealed_index = randi ( [ 1, revealable_num ], 1 );
  revealed_door = revealable_door(revealed_index);
%
%  If the user's strategy is to switch, choose one of the unchosen 
%  unrevealed doors at random.
%
  if ( switch_doors )

    available_door = [];
    available_num = 0;

    for door = 1 : ndoors
      if ( ( door ~= chosen_door ) && ( door ~= revealed_door ) )
        available_door = [ available_door, door ];
        available_num = available_num + 1;
      end
    end

    available_index = randi ( [ 1, available_num ], 1 );
    chosen_door = available_door(available_index);

  end
%
%  The user wins if the chosen door was hiding the prize.
%
  win = ( chosen_door == prize_door );

  return
end
function timestamp ( )

%*****************************************************************************80
%
%% timestamp() prints the current YMDHMS date as a timestamp.
%
%  Licensing:
%
%    This code is distributed under the MIT license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  t = now;
  c = datevec ( t );
  s = datestr ( c, 0 );
  fprintf ( 1, '%s\n', s );

  return
end

