function lights_out_test ( )

%*****************************************************************************80
%
%% lights_out_test() tests lights_out().
%
%  Licensing:
%
%    This code is distributed under the MIT license.
%
%  Modified:
%
%    11 November 2024
%
%  Author:
%
%    John Burkardt
%
  addpath ( '../lights_out' );

  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'lights_out_test():\n' );
  fprintf ( 1, '  MATLAB/Octave version %s\n', version ( ) );
  fprintf ( 1, '  lights_out() examines the 5x5 Lights Out game.\n' );
%
%  Randomly initialize the random number generator.
%
  rng ( 'shuffle' );
%
%  Set the game size.
%
  m = 5;
  n = 5;
%
%  Initialize the board to a random state
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  lo_initialize_random(m,n,k) randomly initializes\n' );
  fprintf ( 1, '  the board with k lights turned on.\n' );

  illum = 15;
  L = lo_initialize_random ( illum );
  label = sprintf ( '  Random board with %d lights illuminated.', illum );
  lo_print ( L, label );
%
%  Initialize the board to a solvable state
%
  push = 5;
  fprintf ( 1, '\n' );
  fprintf ( 1, '  lo_initialize_solvable(m,n,push) randomly initializes\n' );
  fprintf ( 1, '  the board with push = %d button pushes.\n', push );

  L = lo_initialize_solvable ( push );
  illum = sum ( sum ( L ) );
  label = sprintf ( '  Solvable board with %d lights illuminated', illum );
  lo_print ( L, label );
%
%  Press button (i,j).
%
  i = 2;
  j = 3;
  fprintf ( 1, '\n' );
  fprintf ( 1, '  lo_update(L,i,j) updates the board after button\n' );
  fprintf ( 1, '  (i,j) = (%d,%d) was pushed.\n', i, j );

  push = push + 1;
  L = lo_update ( L, i, j );
  illum = sum ( sum ( L ) );
  label = sprintf ( '  Updated board with %d lights illuminated', illum );
  lo_print ( L, label );
%
%  Print solvability matrices.
%
  [ N1, N2 ] = lo_solvability_matrices ( );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  lo_solvability_matrices() returns matrices N1 and N2\n' );
  fprintf ( 1, '  which test a board configuration for solvability.\n' );

  label = sprintf ( '  Solvability matrix N1' );
  lo_print ( N1, label );
  label = sprintf ( '  Solvability matrix N2' );
  lo_print ( N2, label );
%
%  Test Dot product mod 2.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  lo_dot() computes the dot product modulo 2\n' );
  fprintf ( 1, '  of two board configurations.\n' );

  [ N1, N2 ] = lo_solvability_matrices ( );

  dot = lo_dot ( N1, N2 );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Dot product of N1 and N2 is %g\n', dot );

  push = 8;
  L1 = lo_initialize_solvable ( push );
  dot = lo_dot ( L1, N1 );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Dot product of L1 and N1 is %g\n', dot );
  dot = lo_dot ( L1, N2 );
  fprintf ( 1, '  Dot product of L1 and N2 is %g\n', dot );

  illum = 13;
  L2 = lo_initialize_random ( illum );
  dot = lo_dot ( L2, N1 );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Dot product of L2 and N1 is %g\n', dot );
  dot = lo_dot ( L2, N2 );
  fprintf ( 1, '  Dot product of L2 and N2 is %g\n', dot );
%
%  Solvability test.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  lo_solvable(L) determines whether configuration L\n' );
  fprintf ( 1, '  is solvable.\n' );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Test lo_initialize_solvable() configurations\n' );
  for test = 1 : 5
    push = randi ( [ 0, 15 ], 1, 1 );
    L = lo_initialize_solvable ( push );
    solvable = lo_solvable ( L );
    fprintf ( 1, '  Solvable?  %s\n', mat2str ( solvable ) );
  end

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Test lo_initialize_random() configurations\n' );
  for test = 1 : 5
    illum = randi ( [ 0, 25 ], 1, 1 );
    L = lo_initialize_random ( illum );
    solvable = lo_solvable ( L );
    fprintf ( 1, '  Solvable?  %s\n', mat2str ( solvable ) );
  end
%
%  lo_light_chase()
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  lo_light_chase(L) pushes buttons to shut off all\n' );
  fprintf ( 1, '  lights above the bottom row.\n' );

  push = randi ( [ 0, 15 ], 1, 1 );
  L0 = lo_initialize_solvable ( push );
  label = sprintf ( '  Initial configuration L0' );
  lo_print ( L0, label );

  L1 = lo_light_chase ( L0 );
  label = sprintf ( '  After light chasing:' );
  lo_print ( L1, label );
%
%  lo_light_chase_top()
%
  fprintf ( 1, '\n' );
  fprintf ( 1, '  lo_light_chase_top(L) examines a Lights Out configuration\n' );
  fprintf ( 1, '  after the light chase algorithm has been completed.\n' );
  fprintf ( 1, '  It reports whether the problem is completed, unsolvable,\n' );
  fprintf ( 1, '  or solvable.\n' );
  fprintf ( 1, '  For solvable problems, it suggests which buttons to push\n' );
  fprintf ( 1, '  on the top row, so that restarting the light chase algorithm\n' );
  fprintf ( 1, '  will solve the problem.\n' );

  push = randi ( [ 0, 15 ], 1, 1 );
  L0 = lo_initialize_solvable ( push );
  label = sprintf ( '  Initial configuration L0' );
  lo_print ( L0, label );

  L1 = lo_light_chase ( L0 );
  label = sprintf ( '  After light chasing:' );
  lo_print ( L1, label );

  top = lo_light_chase_top ( L1 );

  fprintf ( 1, '\n' );
  if ( isempty ( top ) )
    fprintf ( 1, '  This configuration is not solvable.\n' );
  elseif ( all ( top == 0 ) )
    fprintf ( 1, '  This configuration has been solved.\n' );
  else
    fprintf ( 1, '  This configuration is solvable.\n' );
    fprintf ( 1, '  Pushing these buttons in top row:\n' );
    disp ( top )
    fprintf ( 1, '  Then do a second round of light chasing.\n' );

    L2 = L1;
    i = 1;
    for j = 1 : 5
      if ( top(j) )
        L2 = lo_update ( L2, i, j );
      end
    end

    label = sprintf ( '  After pushing top row buttons:' );
    lo_print ( L2, label );

    L3 = lo_light_chase ( L2 );
    label = sprintf ( '  After second round of light chasing:' );
    lo_print ( L3, label );
  end
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'lights_out_test():\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  rmpath ( '../lights_out' );

  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

