最近のあなごる

あなごるサーバーにサブミットすると時々、IO error だったか、connection できないといったエラーが返る時がある。しばらくすると、あなごるサーバーが完全にダウンしたりしていた。今年になって2度ほどあったように思う。
2月初めには東証のシステムダウンがあった。ニュースによると、F さんらしいが、他人事とも思えない。現場は大変だろうな。
去年買ったスマホ、遅いし、インターネットのリンクは、タッチした(つもりの)ところとは隣のリンク先に飛んだり、文字入力は面倒、さらには、時々動きがおかしいこともある。全然『スマート』だと思ったことがない。
1月下旬からちょっと大きなトラブル対応にあたっている。同僚が担当していたプロジェクトで製品トラブルがあり、その対応で私も参画することになった。問題を特定することができ、その製品がちょっと簡単には治らないことから、代替製品に置き換えることになった。サービスインの日程を満たすために、緊急対応していたのだが、この代替製品、こんどは、こいつがトラぶった。また、問題判別を行い、原因を特定して、さらに厳しいスケジュールの中、サービスイン目指して頑張っている。

     ソフトウェア、未だまともに動かず


この業界、もう何年ソフトウェアを作ってるんだ。アセンブラFortran、C、COBOLC++Java、なんとかスクリプト、LL だのと、言語だのテクノロジーだの、新しモノを排出するのはいいが、バグは全然消えない。そもそも言語設計者はバグを減らすということをデザインに盛り込んだということがあったのだろうか。無いということが現在の現実が証明していると思う。言語なんて、単に自分に気持ちのいいシンタックス天下り的に出して、うけるかうけないかだけだという気がする。
テストや開発プロセス、これらも破綻しているんじゃないか?腐ったものをテストしても新鮮にはならない。
なんだかそういった意味で、この業界に長くいても、業界に貢献できていない自分が不甲斐ない。
さて、重たい話をしてしまったが、コンピュータ言語なんて、所詮、ゴルフのためにあるんだ、と思うと気が楽というか楽しくなる。ゴルフは、ほんと、いい息抜きだな。
そういえば、大学受験勉強をしていたころ、よく、文章を簡潔にまとめる練習をした気がする。試験でも、「200字以内にまとめよ」っといったものはよくあったと思う。これって、ゴルフか?

Four Number Game

C

トップは、130B@inaniwa さん

A[];*p;main(){for(;~scanf("%d %d %d %d\n",A,A+1,A+2,A+3);puts(""))for(;vprintf()-8|A[3];)for(p=A;p-A<4;*p++=abs(*p-p[1]))p[4]=*p;}

私も含め、他の方々は、134B で、各項を別々に計算しているのに対し、上述 inaniwa さんの解は、ループで計算することで縮めている。以前の日記でも述べたとおり、vprintf() は、配列との相性もよく、ここではそれが活用されている。見事。

Groovy

Groovyはトップを取れた。

System.in.eachLine{for(s='';s?c+d:1;s+="$a $b $c $d\n")(a,b,c,d)=s?[b-a,c-b,d-c,a-d]*.abs():it.split()*.toLong();println s}

ポイントは、

[b-a,c-b,d-c,a-d]*.abs()

この部分だろう。絶対値を求めるのは、Java では、Math.abs() だが、Groovy の Number Class には、instance method として abs() がある。自然だし、便利は便利だが、節操がない気もする。メソッドをオブジェクトに持たせるべきかどうかの判断基準は何か?Number オブジェクトに、2倍を求めるメソッド、3倍を求めるメソッド、log() を求める、sin() を求める、、、なんてきりがない。abs() はいるけど、sin() はいらない、ってだれか明確に説明できるだろうか。

Alphabet

C で cheat っぽい解答でトップをとった。公開後、nai さんにより 1B 縮められた。

main(){puts(l64a(0)-22901);}   // 28B@nn
main(){puts(l64a(0)-'Yu');}    // 27B@nai

この問題、単に、"AB...Z" を出力するというもの。C だと、puts() でリテラルを出力するか、putchar() で一文字ずつ出力するか、という解がが考えられるが、何かもっと短くできないかと考えていた時に、"A..Z" という文字列は、nl_langinfo() あたりにありそうだな、っと思った。そこで、以下のようなコードを書いて探したところ、すぐに見つかった。ラッキー。

main(){
    char*p=nl_langinfo(0);
    for(;;p++){
        if(strcmp(p,"ABCDEFGHIJKLMNOPQRSTUVWXYZ")==0){
            printf("%08x\n",p);
            break;
        }
    }
}

で、上記で出力されたアドレスを以下のようにプログラムした。

main(){puts(0xXXXXXXXX);}

これで、25B ゲット!っと思いきや、うまくいかない。なんと、あの、main() の第二引数のように、実行のたびにアドレスが変わってしまうのだ。このまま上記をサブミットし続けると、いつかは 25B が得られるだろうと思ったが、それでは、Random 解で、時間の無駄遣い。やる気は起きない。で、ちょっと調べると、そのアドレスは、nl_langinfo() のリターンからの相対位置は変わらないことが分かった。なので、以下でOK。

main(){puts(nl_langinfo(0)+55722);}

ただ、残念なことに、これだと、35B で全然短くない。で、何か、nl_langinfo() のようなアドレスを返す関数が無いかなぁっと、いつも見ている man page (http://linux.die.net/man/3/) を上から見ていたところ、なんと、4番目に怪しい関数、a64l() が。これは、itoa() の仲間か?と思ってみてみると、対となる関数、l64a() が char* を返す。やった、っと思い、nl_langinfo() のリターンとの距離を調べたら、常に固定。なので、上述の 28B が得られた。nai さんの 27B は数値リテラルを文字リテラルに置き換えたもの。確かに。そのテクはすっかり忘れていた。
その後なんと、tails さんによるアドレス決め打ち 21B 解が。ちょっとびっくり。何回くらいサブミットしたんだろう。

delayed echo

過去の、Remenber Previous Input と同じ問題。同じ問題はやめませんか。
で、"more delayed echo" という問題を作成し投稿した。が、はねられてしまった。どういう問題かというと、1問目の入力を3問目の出力とするもの。ところが、2問目の出力(だったか?)を空にすると、あなごるサーバーは正しい問題として受け付けてくれなかった。

Reverse Bits FIXED

C

C は、まぁ、最近確立されてきた、read()/write() のストリーム処理テクだ。ファイルディスクリプタの値でループを制御するところも、最近では驚きが減ってきた。C ゴルフにおいては、もはや、教科書にでも載りそうな方法だ。
もう一点面白いのは、文字出力は 8bit 出力なので、それより上位のビットは無視される点だ。JavaScript解でも同じだが、これもちょっとしたテクだ。

Groovy

私の 68B

(S=System).in.any{b->8.times{b=2*b|b>>it*2&1};S.out.out.out.write b}

OutputStream を close しないため、System.out はバッファーリングされて、すべてが出力されない。なので、System.out.out.out で、おおもとの OutputStream オブジェクトを取り出して使った。
トップteebee さんの 55B

(z=System).out<<(byte[])z.in.collect{0.reverse(it<<24)}

なんと、Java の Integer クラスに、reverse() 関数が定義されていて、これは、ビットを反転(reverse)するものだ。これも、節操無い関数だなぁっと思ったが、そういえば C にも、ntohs()/htons() といったネットワークアドレス表現を扱う関数があったな、っと思い試したが、ビットの反転はしてくれなかった。残念。

追記
(S=System).in.each{b->8.times{b=2*b|b>>it*2&1};S.out<<(byte[])[b]}
(S=System).in.each{b->8.times{b=2*b|b>>it*2&1};S.out<<(byte)b}
(S=System).in.each{b->8.times{b=2*b|b>>it*2&1};S.out<<b as byte}

上記のような3通りを試してみたところ、1番目だけがうまくいき、2番目と3番目は期待する答えが得られない。多分、InputStream クラスの、

void write(byte[]b);
void write(int b);

のどちらに解決するかによる違いなのだろう。(byte)b や b as byte は、int b にプロモートされてしまうということらしい。なぜ、write(byte b) を足さないのか。そもそも、<< みたいなシンタックスいらないのでは?これもバグのもと。

さらに追記
(S=System).in.each{b->8.times{b=2*b|b>>it*2&1};S.out<<[b]as byte[]}
(S=System).in.each{b->8.times{b=2*b|b>>it*2&1};S.out<<([b]as byte[])}

これも前者は、うまくいかず、後者はOK。as 〜 より、<< の方が強いということか。ますます、<< が嫌いになった。

Self Numbers

面白い問題だと思う。ある数とその数の各桁の数値を足して表せる数ではない数をSelf Number という。たとえば、135 に対して、135 + 1 + 3 + 5 = 144 なので、144 は Self Number ではない。この手のは、JavaScript では、割とストレートに表現し、ふるいにかける方法で、66B ができた。

for(i=0;v=++i,i<3e3;it[v]=it[i]||~print(i))for each(k in''+i)v+=+k

しかしながら、C ではそう簡単にはいかず、縮まらなかったため出さずじまい。
C トップ nai さんの解@69B は、これまた、飛んでる。

main(i){for(;i<3e3;i+=i%1001%101>7?11:i%94%33?2:15)printf("%d\n",i);}

1001, 101, 11 の数の出所は、まぁ、わかるが、それ以外はなんなんだ。理解できず。すげぇ。