読者です 読者をやめる 読者になる 読者になる

No. 410 「出会い」ショートコード解説

はじめに

yukicoder コンテストで出題された問題 No. 410 「出会い」のショートコード(2016年8月13日現在)の解説です。

問題ページ: http://yukicoder.me/problems/no/410

ショートコード: http://yukicoder.me/submissions/110735

問題の概要

入力:

A B
C D

が与えられる(A,B,C,Dは整数)。(abs(A-C)+abs(B-D))*0.5 の値を出力せよ。

私の答案

tr - _|dc -e?sx?sy-d*vlxly-d*v+.5*p

35 bytes です。言語は Bash です。 tr と dc を呼び出しています。 dc は先日 yuki さんにお願いして導入してもらい、使えるようになりました。

dc とは?

逆ポーランド形式の無限精度の計算が行える卓上計算機」だそうです(出典: http://kazmax.zpp.jp/cmd/d/dc.1.html)。今日では、 RubyPython で精度を気にすることなく整数演算ができますが、かつて Perl の時代にはそういうわけにはいきませんでした。なまじっか Perl が使えてしまうせいで RubyPython を覚える気になれない私は、 dc にはまだまだお世話になっています。

コードの解説

まず、 tr - _ で、入力に含まれる - (マイナス)を全て _ (アンダースコア)に変換しています。これは、 dc の入力においては - (マイナス)は二項演算子であり、負号は _ (アンダースコア)で表すことになっているからです。(一方、出力においては負号は - (マイナス)です。つまり、 dc は自分が出力する数値を解釈できないという謎仕様です。)

次に、負号を変換した入力を dc に渡しています。 -e は perlruby の -e と同じで、スクリプトの直接指定です。そのスクリプトをトークンに分解すると、次のようになります。

? sx ? sy - d * v lx ly - d * v + .5 * p

? は、入力を1行読んで実行する、です。最初の ? で入力の A B が読まれ、次の ? で C D が読まれることになります。読まれた値は、スタックにプッシュされます。

sx は、スタックをポップして変数 x に格納する、です。最初の ? の実行後のスタックは A B ですので、 sx で x には B が入り、スタックは A だけになります。同様に、 sy で y には D が入り、スタックは A C になります。

- d * v という一連の命令が2回出てきます。 d はスタック先頭の値の複製、 v は(非負の)平方根です。つまり、スタック先頭の2つの値の差を2乗してその平方根を求めていますので、差の絶対値が得られます。

lx ly は、変数 x と y の値(つまり B と D )をスタックにプッシュします。

+ .5 * で、これらを足して 0.5 倍しています。 .5 *2 / のほうが短そうですが、デフォルトで商が整数になってしまうので、ここではうまくいきません。

p で結果を出力しています。

おわりに

解説の配信のとき、説明が必要っぽい雰囲気だと思ったので、書いてみましたが、いかがだったでしょうか。全く需要がない気もしますが、果たして最後まで読んでくれた人はいるのでしょうか。