IBM i (旧AS400）の自己学習メモ　RPG Ⅳプログラミング編０９　１桁の乱数を生成して表示する

# 自己学習メモインデックス

[IBM i (旧AS400）の自己学習メモ　インデックス](https://qiita.com/You_name_is_YU/items/3964849e7803c8eaf767)

# 概要

フリーフォーマットでもないRPGⅣの定位置記入方式の環境において、乱数を生成することが困難だという話しを小耳に挟んだ。
完全に定位置記入方式を突き詰めることはできないけども、一部フリーフォーマットのRPGプログラムを利用し、FUNCTIONのように利用して乱数を生成し、CALLやDSPLYは定位置側のRPGⅣプログラム側で実行できればいいかなと思い、技術検証した内容をまとめました。

ここでの乱数は１桁の数値です。
本来はもう少し桁数が必要かもしれませんが、サンプルプログラムの変数のサイズ（INZ）を変更することで対処可能です。

# サンプルコード

## フリーフォーマットのRPGプログラムと組み合わせた乱数のサンプル

`QRPGLESRC/GET_RANDOM`のソースを新規で作り、この中では０〜９までの乱数を生成し、
返却用のパラメータ`P@RTCD`にセットする処理を行っています。

０〜９までの数値の設定としては、７行目〜８行目の`highno`と`lowno`のInzの値で制御可能です。

```shell:QRPGLESRC/GET_RANDOM(*SQLRPGLE)
 FMT H  HKeywords+++++++++++++++++++++++++++++++++++++++++++++++++++
        *************** Beginning of data **************************
0001.00 H DFTACTGRP(*NO) ACTGRP('QILE')                             
0002.00 D CEERAN0         PR                                        
0003.00 D seed                          10I 0                       
0004.00 D ranno                          8F                         
0005.00 D fc                            12A   options(*omit)        
0006.00                                                             
0007.00 D highno          s             10I 0 Inz(9)                
0008.00 D lowno           s             10I 0 Inz(0)                
0009.00 D seed            s             10I 0 inz(0)                
0010.00 D rand            S              8F                         
0011.00 D range           S             10I 0                       
0012.00 D result          S             10I 0                       
0013.00                                                             
0014.00  * パラメータ：リターンコード                             
0015.00 D P@RTCD          S              1S 0                       
0016.00  * パラメータリスト                                       
0017.00 C     *ENTRY        PLIST                                   
0018.00 C                   PARM                    P@RTCD          
0019.00  /free                                                      
0020.00      range = (highno - lowno) + 1;           
0021.00      CEERAN0( seed : rand : *omit );         
0022.00      result = %int(rand * range) + lowno;    
0023.00      P@RTCD = result;                        
0024.00  //  dsply result;                           
0025.00      return;                                 
0026.00  /end-free                                   
```

上記プログラムをCALLする、RPGⅣの定位置記入方式のRPGプログラムは以下のような感じです。
７行目でCALLして、リターンコード`P@RTCD`をDSPLYで画面表示しているだけです。

```shell:RPG94(*RPGLE)
 FMT *   *. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ..
        *************** Beginning of data **********************************
0001.00  * パラメータリストの定義                                         
0002.00 C     PL@PARAM      PLIST                                           
0003.00 C                   PARM                    P@RTCD            1     
0004.00                                                                     
0005.00  * 電話番号の正規表現チェック処理実行                             
0006.00 C                   EVAL      P@RTCD = '0'                          
0007.00 C                   CALL      'GET_RANDOM'  PL@PARAM                
0008.00 C     P@RTCD        DSPLY                                           
0009.00                                                                     
0010.00 C                   EVAL      *INLR = *ON                           
        ****************** End of data *************************************
```

作ったプログラムをコンパイルして実行すると以下のような感じになります。

![as400.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/6ba4ebff-19d4-88a7-2c7a-52fed820a0b3.gif)

## なんちゃっての乱数もどきのサンプル

定位置記入方式のRPGⅣのみを利用し、且つ１桁の乱数という条件であれば、
乱数もどきの動きをしてくれるプログラムを構築することが可能だと思ったので、そのサンプルも参考までに。
これが１０桁２０桁の乱数となると、このサンプルは全く利用価値がありませんのでご注意ください。

ここでやっているのは、タイムスタンプ（２０桁）を生成して、その一番右の桁（２０桁目）に該当するミリ秒の部分１桁を利用しているだけです。
ミリ秒なので、０〜９までが頻繁に入れ替わる１桁の乱数のように動いてくれると思って作りました。

```shell:RPG95(*RPGLE)
 FMT D  DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords++++++++++++++++++++++
        *************** Beginning of data **********************************
0001.00 D timestamp       s               Z                                 
0002.00 D Output          s             40A                                 
0003.00 D rand            s              1A                                 
0004.00                                                                     
0005.00  * 年月日時分秒ミリ秒のタイムスタンプを生成                       
0006.00 C                   EVAL      timestamp = %TIMESTAMP()              
0007.00 C                   EVAL      Output   = %char(timestamp:*iso0)     
0008.00  * タイムスタンプ文字列の一番右側の値を１文字だけ取得             
0009.00 C                   SUBST     Output:20     rand              1     
0010.00  * 上記数字を１桁のランダム数値として扱って表示                   
0011.00 C     rand          DSPLY                                           
0012.00                                                                     
0013.00 C                   EVAL      *INLR = *ON                           
        ****************** End of data *************************************
```

上記の動作結果は、以下のような感じになります。

![as400.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246556/4aca13f7-4c1f-e8d7-9f69-5bff601e6a6f.gif)