9.プログラムをスマートに




『スマートにって?』
ある仕様のプログラムを作るにも、使われるプログラム手法は人それぞれでしょう。最終的に仕様通りのものが出来れば文句は無いでしょう。しかし、採用したプログラム手法によっては、品質が悪かったり、将来のバージョンアップが大変になったりと、困った事が起こったりします。
数行のプログラムであるのならば大した問題では無いのでしょうが、大規模なプログラムの開発(ちなみにLGPはC言語で17000行位です)であったり、仕事上でのプログラム開発ではNGとなります。
前章までに作ってきたプログラムはスマートでしょうか?私的にはNGです。では、どこがスマートではないのでしょうか?これはプログラマーの趣味になるところが大きいのですが、私には、数字の処理の部分が気に入りません。
次に、前章までに作ってきたプログラムの内、数字の処理の一部を切り出しましたので、よく見てください。

    IF BT == 79 THEN          //ボタン「1」
      SUU = SUU * 10 + 1
    ENDIF
    IF BT == 80 THEN          //ボタン「2」
      SUU = SUU * 10 + 2
    ENDIF
    IF BT == 81 THEN          //ボタン「3」
      SUU = SUU * 10 + 3
    ENDIF


青い部分が異なるだけで、他の部分はまったく同じ作り(全部で10個所)である事に気が付くでしょう。もしこの部分が一つに纏まれば、プログラム量が10分の1になるので、作業量が10分の1になりますし、不良を作り込む可能性も10分の1になります。

『スマートにするには』
上の異なる部分を見てみると「変数BTが79なら1を加える」「変数BTが80なら2を加える」というように、各ボタンの番号に対応した加える数字を見つけて加算してあげれば良いのではと考え付いた。具体的には、「ボタンの番号」と「加える値」を対応した表を用意しておき、「ボタンの番号」から「加える値」を見つけるのだ。
対応表を次に示す。(上下が対となる)

ボタンの種類”0””1””2””3””4””5””6””7””8””9”
ボタンの番号82798081757677717273
加える値


この表をプログラムで用意するのに配列を使う。配列は10個の要素を持ち、各要素に順番に「ボタンの番号」を代入する。

DIM  BTNSUU( 10 )
ARRAY BTNSUU( 0 ) = ( 82 , 79 , 80 , 81 , 75 , 76 , 77 , 71 , 72 , 73 )


ここで「ボタンの種類と加える値も必要なのではないか?」と思われるかもしれないが、必要はない。「ボタンの種類」と「加える値」を良く見ると「0,1,2、・・・・、7,8,9」というように規則正しい値である事が分かるが、配列の要素番号も「0,1,2、・・・・、7,8,9」であり、同じである事が分かる。
つまり、配列の要素番号が分かれば、「ボタンの種類」と「加える値」はおのずと分かる事になります。
今回作るプログラムでは、「ボタンの番号」から「加える値」を見つけるのに、配列を要素番号で順番にたどり、押されたボタンの番号と一致する要素番号を見つけるようにするので、要素番号は分かっている事になります。

まず、配列を要素番号で順番にたどる部分を作るのですが、要素番号は0〜9へと順番に上げて行くので、FOR〜NEXT命令を使うとよいでしょう。
変数 Iが要素番号です。

    FOR I = 0 TO 9                      //配列をたどる
      〜処理〜
    NEXT


次に押されたボタンの番号と配列の要素との比較は次のようになります。

    FOR I = 0 TO 9                      //配列をたどる
      IF BTNSUU( I ) == BT THEN         //ボタンの種類を配列から調べる
        〜処理〜
      ENDIF
    NEXT


押されたボタンの番号と配列の要素が一致したら、(既に要素番号が分かったので)FOR〜NEXT命令から抜けます。
このFOR〜NEXT命令から抜けるにはBREAK命令を使います。

    FOR I = 0 TO 9                      //配列をたどる
      IF BTNSUU( I ) == BT THEN         //ボタンの種類を配列から調べる
        BREAK                           //ボタンが分かったのでFOR〜NEXTを抜ける
      ENDIF
    NEXT


ここまでで、押されたボタンの番号と配列の要素が一致した場合には、変数 I に要素番号が代入されます。後は変数 I を桁処理で加算してあげれば良いのですが、数字以外が押された場合も考えられるので考慮をします。
押されたか、押されていないかを見分けるにはどうしたら良いでしょうか?
ここでちょっとしたテクニックですが、FOR〜NEXT命令をBREAK命令で強制的に抜けずに最後まで回り切った時、変数 Iには上限(今回は「9」)のプラス1である「10」が入っているところに目を付け、変数 Iが「10」ならば押されていないと考える事にします。
(BREAK命令で抜けた時には、変数 Iには抜けた時の数字になります。)

    FOR I = 0 TO 9                      //配列をたどる
      IF BTNSUU( I ) == BT THEN         //ボタンの種類を配列から調べる
        BREAK                           //ボタンが分かったのでFOR〜NEXTを抜ける
      ENDIF
    NEXT                                //最後まで見つからなければI=10で終わる
    IF I < 10 THEN                      //「I<10」ならば数字が押された
      SUU = SUU * 10 + I                //桁の処理
    ENDIF


ここまでのプログラムを纏めてみます。

DIM  BTNSUU( 10 )
ARRAY BTNSUU( 0 ) = ( 82 , 79 , 80 , 81 , 75 , 76 , 77 , 71 , 72 , 73 )
CH=G@SETUP(320,240,16,1)                 //画面の準備
CH2=G@CHRLOAD("DENTAKU.BMP")            //電卓の画像を読み込み
G@COLOR(0,0,1)                          //文字を黒色にする
SUU = 0                                 //画面に表示する数字
LOOP
  G@CHRCOPY( CH2 , CH , 0 , 0 )         //電卓の画像を画面に貼る
  I@KEYGET2( )                          //キーボートのチェック
  IF I@KEYBTN2( 1 ) == 1 THEN           //ボタンは押された
    BT = I@KEYBTN2( 0 )                 //ボタンの種類を変数BTに代入
    FOR I = 0 TO 9                      //配列をたどる
      IF BTNSUU( I ) == BT THEN         //ボタンの種類を配列から調べる
        BREAK                           //ボタンが分かったのでFOR〜NEXTを抜ける
      ENDIF
    NEXT                                //最後まで見つからなければI=10で終わる
    IF I < 10 THEN                      //「I<10」ならば数字が押された
      SUU = SUU * 10 + I                //桁の処理
    ENDIF
  ENDIF
  G@PRINT( CH , 32 , 8 , STR( SUU ) )   //数字を表示する
  G@FLIP( )                             //画面を更新
ENDLOOP