function snakes ( )

%*****************************************************************************80
%
%% snakes() tests snakes_and_ladders_simulation().
%
%  Licensing:
%
%    This code is distributed under the MIT license.
%
%  Modified:
%
%    12 January 2025
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'snakes():\n' );
  fprintf ( 1, '  MATLAB/Octave version %s\n', version ( ) );
  fprintf ( 1, '  Test snakes_and_ladders_simulation().\n' );
%
%  Do a batch of N games, measure game lengths.  Do this M times.
%
  m = 10;
  n = 1000;
  snakes_stats ( m, n );
%
%  Do N games, and histogram the game lengths.
%
  n = 1000;
  snakes_histogram ( n );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'snakes():\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  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

function snakes_histogram ( n )

%*****************************************************************************80
%
%% snakes_histogram() makes a game-length histogram for Snakes and Ladders.
%
%  Discussion:
%
%    For histograms, we plot the raw data, whereas for bar charts, we
%    plot the tallies.
%
%  Licensing:
%
%    This code is distributed under the MIT license.
%
%  Modified:
%
%    17 July 2017
%
%  Author:
%
%    John Burkardt
%
%  Input:
%
%    integer N, the number of games to play.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'snakes_histogram():\n' );
  fprintf ( 1, '  Simulate N one-player games of Snakes and Ladders.\n' );
  fprintf ( 1, '  Use the simulation data to create histograms\n' );
  fprintf ( 1, '  of the estimated PDF and CDF of the game length.\n' );
%
%  Simulate N games.
%
  steps = zeros ( n, 1 );

  for game = 1 : n
    [ steps(game) ] = snakes_one_game ( );
  end
%
%  Report data.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Number of trials was n =    %d\n', n );
  fprintf ( 1, '  Minimum number of steps was %d\n', min ( steps ) );
  fprintf ( 1, '  Mean number of steps was    %g\n', mean ( steps ) );
  fprintf ( 1, '  Maximum number of steps was %d\n', max ( steps ) );
  fprintf ( 1, '  Standard deviation was      %g\n', std ( steps ) );
%
%  Histogram the PDF.
%
  figure ( 1 );
  histogram ( steps, 'Normalization', 'pdf' );
  grid ( 'on' );
  title ( sprintf ( 'Game length PDF for %d Games of Snakes and Ladders', n ) );

  filename = 'snakes_pdf.png';
  fprintf ( 1, '  Graphics saved as "%s"\n', filename );
  print ( '-dpng', filename );
%
%  Histogram the CDF.
%
  figure ( 2 );
  histogram ( steps, 'Normalization', 'cdf' );
  grid ( 'on' );
  title ( sprintf ( 'Game length CDF for %d Games of Snakes and Ladders', n ) );

  filename = 'snakes_cdf.png';
  fprintf ( 1, '  Graphics saved as "%s"\n', filename );
  print ( '-dpng', filename );

  return
end
function [ snake, ladder ] = snakes_ladder_setup ( )

%*****************************************************************************80
%
%% snakes_ladder_setup() defines the snakes and ladders for the game.
%
%  Discussion:
%
%    The two vectors could be merged into one.
%
%  Licensing:
%
%    This code is distributed under the MIT license.
%
%  Modified:
%
%    17 July 2016
%
%  Author:
%
%    John Burkardt
%
%  Output:
%
%    integer SNAKE(101,1), LADDER(101,1), define the snakes and
%    ladders.  If a player lands on square I, then if SNAKE(I) is not I,
%    the player is immediately moved to a previous square whose index
%    is SNAKE(I).  Similarly, if LADDER(I) is not I, then player is
%    immediately taken to a later square whose index is LADDER(I).
%
  O = 1;

  ladder = zeros ( 101, 1 );

  ladder(0+O:100+O) = 0+O:100+O;

  ladder(1+O) = 38+O;
  ladder(4+O) = 14+O;
  ladder(9+O) = 31+O;
  ladder(21+O) = 42+O;
  ladder(28+O) = 84+O;
  ladder(36+O) = 44+O;
  ladder(51+O) = 67+O;
  ladder(71+O) = 91+O;
  ladder(80+O) = 100+O;

  snake = zeros ( 101, 1 );

  snake(0+O:100+O) = 0+O:100+O;

  snake(16+O) = 6+O;
  snake(48+O) = 26+O;
  snake(49+O) = 11+O;
  snake(56+O) = 53+O;
  snake(62+O) = 19+O;
  snake(64+O) = 60+O;
  snake(87+O) = 24+O;
  snake(93+O) = 73+O;
  snake(95+O) = 75+O;
  snake(98+O) = 78+O;

  return
end
function [ i, d ] = snakes_move ( i, snake, ladder )

%*****************************************************************************80
%
%% snakes_move() takes one move in a game of Snakes and Ladders.
%
%  Licensing:
%
%    This code is distributed under the MIT license.
%
%  Modified:
%
%    17 July 2016
%
%  Author:
%
%    John Burkardt
%
%  Input:
%
%    integer I, the current location.
%
%    integer SNAKE(101,1), LADDER(101,1), define the snakes and
%    ladders.  If a player lands on square I, then if SNAKE(I) is not I,
%    the player is immediately moved to a previous square whose index
%    is SNAKE(I).  Similarly, if LADDER(I) is not I, then player is
%    immediately taken to a later square whose index is LADDER(I).
%
%  Output:
%
%    integer I, the current location.
%
%    integer D, the value of the die roll, between 1 and 6.
%

%
%  O is the offset, which is 1 for 1-based languages.
%
  O = 1;
%
%  Roll the die.
%
  d = randi ( [ 1, 6 ], 1 );
%
%  Move from I to I + D.
%
  i = i + d;
%
%  Your position can't exceed 100.
%
  i = min ( i, 100 );
%
%  If we landed on a snake, we slide down.
%
  i = snake ( i + O ) - O;
%
%  If we landed on a ladder, we climb up.
%
  i = ladder ( i + O ) - O;

  return
end

function step = snakes_one_game ( )

%*****************************************************************************80
%
%% snakes_one_game() plays Snakes and Ladders once.
%
%  Licensing:
%
%    This code is distributed under the MIT license.
%
%  Modified:
%
%    17 July 2016
%
%  Author:
%
%    John Burkardt
%
%  Output:
%
%    integer STEP: the number of steps required for a random simulated
%    one-player game of Snakes and Ladders.
%

%
%  Define the snakes and ladders.
%
  [ snake, ladder ] = snakes_ladder_setup ( );
%
%  Begin the simulation.
%
  step = 0;
  i = 0;

  while ( i < 100 )

    step = step + 1;
    [ i, d ] = snakes_move ( i, snake, ladder );

  end

  return
end
function snakes_stats ( m, n )

%*****************************************************************************80
%
%% snakes_stats() reports minimum, average and maximum game lengths.
%
%  Licensing:
%
%    This code is distributed under the MIT license.
%
%  Modified:
%
%    10 January 2025
%
%  Author:
%
%    John Burkardt
%
%  Input:
%
%    integer M, the number of batches of games to play.
%
%    integer N, the number of games in each batch.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'snakes_stats():\n' );
  fprintf ( 1, '  Simulate N = %d one-player games of Snakes and Ladders,\n', n );
  fprintf ( 1, '  report minimum, mean, and maximum game lengths.\n' )
  fprintf ( 1, '  Do this M = %d times.\n', m )
%
%  Simulate N games.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Batch    Min   Mean   Max    Std\n' );
  fprintf ( 1, '\n' );

  for batch = 1 : m

    steps = zeros ( n, 1 );

    for game = 1 : n
      steps(game) = snakes_one_game ( );
    end
%
%  Report data.
%
    fprintf ( 1, '     %2d  %5d  %8.2f  %5d  %8.2f\n', ...
      batch, min ( steps ), mean ( steps ), max ( steps ), std ( steps ) );

  end

  return
end

