人気ブログランキング | 話題のタグを見る
- 北の空からみなみへ -
exblog staff

<< コマンドプロンプトの1行ベンチマーク 砂場遊び(1行FizzBuzz) >>
砂場遊び(1行FizzBuzz)/後片付け
2018年 03月 08日
砂場遊び(1行FizzBuzz)

bugmacotoとも言うべきお間抜けコードを前投稿(more欄)で晒した。Windows実機でちゃんと動くコードに直したので再掲する。
なお、ちょこっとずつ解説入れておこう。(自分でも後から可読する自信はないらしい)

まずは、最短(なんちゃってなので105までカウントアップが突っ走り)なBizzBuzz方言版

cmd/q/v:on/c "for /L %a in (0,1,6) do for %A in (1 2 i 4 u i 7 8 i u B i D E izzBu) do if %A gtr f (echo.B%Azz) else set/a $=15*%a+0x%A&echo."
142 ↑ byte
    cmdのオプション
  • /q : echo off状態で起動
  • /v:on : 変数の遅延展開を有効にした状態で起動
    バッチで SETLOCAL ENABLEEXTENSIONS 宣言下と同じ状態
  • /c : 残り全部を引用符で囲まれたパラメータ(引数)を続けると、最初と最後の引用符が外されてコマンドライン上で実行される感じになる。
    (マイクロソフトのcmd.exeの文字列を扱う実装は、ちょっとずつ状況に応じて変化する=一貫性はない感じ。
     BASIC時代から、対称性の破れみたいな実装を好んでいる感じがする。)
    遅延展開有効下での例 : 比較文字として キャレットで「|」と引用符「"」を比較
    引用符にキャレットって無効では?(なんと有効でした。むしろ \" なんて書くとエラーします)

    > if ^| gtr ^" echo !time: =0!
    20:00:00.00

    > if ^| gtr ^" echo.!time: =0!
    !time: =0!

    echoの後ろに、空白区切りとピリオド区切りとで、変数の拡張展開されたり、されずにそのまま文字列表示になったり。

次に16進アイデアを温存したままで、方言ではないFizzBuzzへの対応版
無理やりな文字列比較をして動くようになったバージョン
なお、16進コードの A~F は大文字でも小文字でもいいらしい。
さらには、引用符あっても(0x"F" と書くとそれは 15 になる)OKという実装。

cmd/q/v:on/c "for /L %a in (0,1,6) do for %A in (1 2 Fi 4 Bu Fi 7 8 Fi Bu "b" Fi "d" "e" FizzBu) do if %A gtr "f" (echo.%Azz) else set/a $=15*%a+0x%A&echo."
156 ↑ byte
    if での比較は、記号 < 数字 < 文字
    (同じ文字なら大文字が大きいが、大文字の A は小文字の b より小さいという定義 )
  • 例 :
    >if b gtr A echo
    ECHO は <ON> です。
  • set/a での変数へ代入する計算結果はバッチ内では結果は表示されないが、コマンドライン上では表示される。
    なお、改行はされない。
    (echo ではなく set/p<nul= で出力したのと同様な吐き出し方をしてる)
  • set/a $= : $は仮変数(ダミー)
    昨日の寝ぼけた式は間違いで、こちらがちゃんとしたカウントアップ。
  • &echo. : 数値は吐き出されても改行はされていない。なので空改行を入れている
    (echo だけでは 「ECHO は <ON> です。」が出るのはおなじみ)

文字比較式があんまりなので、16進数のアイデアを放棄したらむしろ短くなった。
これでかなりすっきりして、分かりやすくなった。

cmd/q/v:on/c "for /L %a in (0,1,6) do for %A in (1 2 Fi 4 Bu Fi 7 8 Fi Bu 11 Fi 13 14 FizzBu) do if %A gtr a (echo.%Azz) else set/a $=15*%a+%A&echo."
149 ↑ byte
  • >ここでは、gtr で 最小の英文字 a と文字比較している。
    より一般的にするなら、if %A geq a とすることで、変数%Aに代入された全ての文字(記号と数字以外)が処理対象となる。
    結果、else 以降は数字処理に専念となる。
  • %A=Fi : 後ろに zz で Fizz
  • %A=Bu : 後ろに zz で Buzz
  • %A=FizzBu : 後ろに zz で FizzBuzz

最後に仕上げ。

FizzBuzz問題は、1から100 という条件なので、それに対応する IF文を加える。
cmdの /c スイッチに続くのが引用符つきのパラメータの場合は、直後の空白を削っても正しく解釈されるのでそうした。

cmd/q/v:on/c"for /L %a in (0,1,6) do for %A in (1 2 Fi 4 Bu Fi 7 8 Fi Bu 11 Fi 13 14 FizzBu) do if %a11==6%A (exit) else if %A gtr a (echo.%Azz) else set/a $=15*%a+%A&echo."
173 ↑ byte
    遅延変数展開下とはいっても、%変数%の形式はしっかり有効なまま。
    (改行するまでは、展開=反映されない変数として普通の環境同様に扱われる)
  • if %a11==6%A (exit) ← これはOK
  • if %a%A==611 (exit) ← これNG
  • ※ なぜなら %a% という変数展開を優先されてしまうので 下の例では
    「%a%A」という4文字を 611 と比較する式に解釈される。
    そこで、たすき掛けにしてやるとまともに動いた。


(more欄のスクリーンショットは撤廃)→ 反復実行の前後時間から平均所要時間を算定の 1行ベンチマークテスト については次の投稿で。
by bucmacoto | 2018-03-08 21:13 | &Tips;&code; | Comments(0)
名前
URL
削除用パスワード
<< コマンドプロンプトの1行ベンチマーク 砂場遊び(1行FizzBuzz) >>
<< コマンドプロンプトの1行ベンチマーク 砂場遊び(1行FizzBuzz) >>