#!/usr/bin/perl 
use 5.014 ; use warnings ;
use Getopt::Std ; getopts 'i:~.:2:g:s:y:' => \my %o ; #or HELP_MESSAGE () ;
use Term::ANSIColor qw[ :constants ] ; $Term::ANSIColor::AUTORESET = 1 ; 
use feature qw [ say ] ;
# 乱数を生成する関数設定
sub rand_gen ( ) ; 

my $osep = $o{i} // "\t" ; # 出力の横方向の区切り文字
my ($r,$c) ; # 列数 と 行数
my ($d,$u) ; # 下限 と 上限

& init ; 
& main ;
& info ;
exit 0 ;

sub init ( ) {
    # 乱数シードの指定
    $o{s} = defined $o{s} ? srand $o{s} : srand ; 

     # 列数と行数
    ( $r, $c ) = split /[,x]+/o , $o{g} // '' , 2 ; 
    $c //= 1 ; # 列数の未指定値
    $r //= 12 ; # 行数の未指定値
    ( $r, $c ) = ( $c, $r ) if $o{'~'} ; 

    # 生成する乱数の範囲
    ( $d , $u ) = split /(?:,|\.\.)/ , $o{y} // '' , 2 ;
    $d //= 6 ;  # さいころの目の最大値 数の指定が1個もない場合もある。
    ($d,$u) = (defined$o{'.'}?0:1, $d) if ! defined $u ; # 範囲指定がd..uの形式で無いなら -uのユニフォーム指定に従い0..nまたは1..n
    # 使用する乱数生成関数の設定
    * rand_gen = defined $o{'.'}? * rand_gen_unif_fmt : * rand_gen_int ; 
    sub rand_gen_int { state $base=$d; state $range = $u-$d+1 ; $base + int rand $range } ; 
    sub rand_gen_unif { state $base=$d; state $range =  $u-$d ; $base + rand $range } ; 
    sub rand_gen_unif_fmt { state $fmt="% 0.$o{'.'}f" ; sprintf $fmt , rand_gen_unif } ; 
}

sub main ( ) {
    for ( 1 .. $r ) { 
        say join $osep , map { rand_gen } 1 .. $c ;
    }
}

sub info ( ) {
    exit 0 if 0 eq ($o{2}//'') ;
    $0 =~ s|.*/||;
    say STDERR BOLD DARK ITALIC CYAN 
      "Used random seed = $o{s}  [$0 -g ${r}x${c} -y $d..$u" .  (defined $o{'.'} ? " -. $o{'.'}" : '' ) ."]" ;
}

## ヘルプとバージョン情報
BEGIN {
  our $VERSION = 0.24 ;
  $Getopt::Std::STANDARD_HELP_VERSION = 1 ; 
  grep { m/--help/} @ARGV and *VERSION_MESSAGE = sub {} ; 
    # 最初は 0.21 を目安とする。
    # 1.00 以上とする必要条件は英語版のヘルプをきちんと出すこと。
    # 2.00 以上とする必要条件はテストコードが含むこと。
   # 0.22 : 英文マニュアルをPOD形式にする。
   # 0.23 : 英文マニュアルのPOD形式の部分をさらに増やした。
   # 0.24 : 英文マニュアルを少し書き加え。
}  
sub HELP_MESSAGE {
    use FindBin qw[ $Script $Bin ] ;
    sub EnvJ ( ) { $ENV{LANG} =~ m/^ja_JP/ ? 1 : 0 } ; # # ja_JP.UTF-8 
    sub en( ) { grep ( /^en(g(i(sh?)?)?)?/i , @ARGV ) ? 1 : 0 } # English という文字列を先頭から2文字以上を含むか 
    sub ja( ) { grep ( /^jp$|^ja(p(a(n?)?)?)?/i , @ARGV ) ? 1 : 0 } # jp または japan という文字列を先頭から2文字以上を含むか 
    sub opt( ) { grep (/^opt(i(o(ns?)?)?)?$/i, @ARGV ) ? 1 : 0 } # options という文字列を先頭から3文字以上含むから
    sub noPOD ( ) { grep (/^no-?p(od?)?\b/i, @ARGV) ? 1 : 0 } # POD を使わないと言う指定がされているかどうか
    my $jd = "JapaneseManual" ;
    my $flagE = ! ja && ( en || ! EnvJ ) ; # 英語にするかどうかのフラグ
    exec "perldoc $0" if $flagE &&  ! opt ; #&& ! noPOD   ; 
    $ARGV[1] //= '' ;
    open my $FH , '<' , $0 ;
    while(<$FH>){
        s/\Q'=script='\E/$Script/gi ;
        s/\Q'=bin='\E/$Bin/gi ;
        if ( s/^=head1\b\s*// .. s/^=cut\b\s*// ) { 
            if ( s/^=begin\s+$jd\b\s*// .. s/^=end\s+$jd\b\s*// xor $flagE ) {
                print $_ if ! opt || m/^\s+\-/  ; 
            }
        } 
    }
    close $FH ;
    exit 0 ;
}

=encoding utf8 

=head1 NAME

saikoro 

=head1 VERSION 

0.24 (2018-07-10)

=head1 SYNOPSIS

saikoro B<[-g N1[,N2]] [-y N3[..N4]]>   # N1, N2, N3 and N4 are all numbers.

=head1 DESCRIPTION

A random number(matrix) generator from uniform distributions.
Generates random uniform variable. Discrete/uniform can be specified.

=head1 OPTION

=over 4

=item B<-g N1>

Get N1 random variables. N1 is a positive interger.

=item B<-g N1,N2>

Get N1 times N2 variables. N1 for vertical, N2 for horizontal.
The form "B<-g N1xN2>" is allowed.

=item B<-~   >

The number specifications N1 and N2 are reversed, so N1 for horizontal, N2 for vertical.

=item B<-y N3,N4>

Limit the values into the number interval [N3,N4]. 
The form "B<-y N3..N4>" is also allowed. 

=item B<-y N3> 

Similar to -y 1..N3. When -. N is simultaneously set, similar to -y 0..N3. 

=item B<-. N>

N digits after decimal points by rounding(, switching from merely discrete integers to continuous). 
If N=0, the outputs are integers.

=item B<-2 0>

Switch to no secondary information that would be output to STDOUT. 

=item B<-s N>

Random seed specification. Essentially the residual divided by 2**32 is used.

=item B<-i char>

Specifies the horizontal separator character.

=item B<--help>

Print this online help manual of this command "saikoro". Similar to "perldoc `which [-t] saikoro` ".

=item B<--help opt>

Only shows the option helps. It is easy to read when you are in very necessary.

=item B<--help ja>

Shows Japanese online help manual. 

=item B<--help nopod>

Print this online manual using the code insdide this program without using the function of Perl POD.

=item --version 

Outputs version information of this program.

=back

=head1 EXAMPLES

=over 4

=item saikoro     

# Outputs 12 random numbers from {1,2,3,4,5,6} horizontally.

=item saikoro B< -~ >

# Outputs 12 random numbers from {1,2,3,4,5,6} vertically.

=item saikoro B< -g 5,8 >

# 5 x 8 matrix whose elements are from {1,2,..,6}.

=item saikoro -g 5,8 B<-y 0,100>

# 5 x 8 matrix whose elements are from {0, 1, 2,..,100}.

=item saikoro -g 5,8 B< -. 3 >

# Continuous random variables with 3 digits after decimal points.

=back

=head1 AUTHOR

Toshiyuki Shimono
  bin4tsv@gmail.com

=head1 HISTORY

This program has been made since 2016-03-04 (Fri)
as a part of TSV hacking toolset for table data.

=begin JapaneseManual 

  プログラム名 : saikoro  ('=bin=')

    '=script=' -g 列数,行数  -y 下限,上限

    乱数または乱数行列を生成。各要素は 1以上で上限を超えない整数になる。

 オプション:  
   -g N     ; 乱数をN行1列の形で出力する。
   -g N1,N2 ; 乱数をN1行N2列の形で出力する。区切り文字は , の代わりに、xでも良い。 (Get)
   -~       ; 出力する行数と列数の指定を反転する。
   -y N1,N2 ; 乱数の値をn1とn2の範囲とする。 -y N1..N2 の形式も許容される。

   -. N     : 出力は整数ではなく、連続型の一様乱数になる。小数点以下N桁が出力される。四捨五入(sprintfに依存)。
   -s N     : ランダムシードの指定。2^32 (約43億<10^10) で割った剰余が渡される。

   -2 0     : ランダムシードの情報を出力しない。
   -i char  : 出力の(横方向の)区切り文字の指定

  --help : この $0 のヘルプメッセージを出す。  perldoc -t saikoro | cat でもほぼ同じ。
  --help opt : オプションのみのヘルプを出す。opt以外でも options と先頭が1文字以上一致すれば良い。
  --help en : 英語版のオンラインヘルプマニュアルを出力。Online help in English version. 
  --version : バージョン情報の出力

 例:

  '=script=' -i, -g 1,10  # 横に10個並べる。コンマ区切りで。
  '=script=' -y 1000 -g 5,8  # 縦8行 横5列で要素が 1 から 1000 までの整数の一様乱数の 乱数行列を生成する。
  '=script=' -20 -g 2,3 -y1..5   # -20 (-2 0と同等)によりランダムシードの情報を表示しない。
  '=script=' -. 6         # 実数(整数とは限らない) 一様乱数の出力。(6は小数点以下の桁数)
  '=script=' -s 123 -.50 -g10,1 -y1 ; # 小数点以下50桁表示されるはず。2進数48桁で内部が動く事が分かる。

  # このブログラムは 2016年3月4日(金)から表形式データに対する道具作りの一環として、下野寿之が作成したものである。
=end JapaneseManual   
=cut

