122333
122333 が先ほど終了した。なかなかの良問だ。おもしろかった。ただ、Sample Input #3 が、たぶん、8bit の立った右ページのコードを含んでいるようだ。そのため、Groovy では、#3 だけうまく扱えず、解答できずじまい。
C
C は 63B 出したとき、勝った!と思ったんだが、甘かった。
58B@naiさん
c;main(i){for(;read(i*=--i>-atoi(&c),&c,1);write(c!=48));}
この問題の場合、やはり、read()/write() にたどり着く。ちょっと前の、Excess3 と似たパターンだが、入力と出力が同じなので、write() を使うことで、read() との引数の同一性から、第2、第3引数を省略できる。とはいえ、こんな引数の省略なんて尋常じゃないけどな、、、、今では、みんな普通にやる定石と化している。
さて、上の nai さんの解答は、まず、write() のファイルディスクリプタに c != 48 を入れているところ、なるほど、理に適っているな。'0' 以外は出力するということだ。あとは、何回出力すれば良いかは、read() のファイルディスクリプタの値でコントロールしている。トップの hinoe さんも、同じロジックだ。
i;main(n){for(;read(i-=i+n-50<8u?:i,&n,1);)write(n!=48);}
まず、nai さんの方から行くと、atoi() は、'1'〜'9' 以外では、0 を返す。'1'〜'9' では、1〜9 を返す。read() が成功した時は、i == 0 となるので、write() を読んだ後、i がデクリメントされ、-atoi() を比較される。i は前置 -- でデクリメントされるので、c == '2'〜'9' 以外の時は、不等号が成立せず、直ちに次の文字を読みにいくことになる。read() が成功した直後に、1回は、write() しているので、それで、OK だ。c == '0' のケースだけ、write(c!=48) で無出力としている。c == '2'〜'9' の場合は、適切な回数ループするまで、i はゼロにならない。見事だな。因みに、
i*=--i>-atoi()
としていて、
i*=++i<atoi()
としていない理由は、正のファイルディスクリプタは、いくつか read() が 0 を返し、ループを抜けてしまうからだ。たとえば、
c;main(i){ for(i=-5;i<15;i++)printf("%d %d\n",i,read(i,&c,1)); }
こんなコードを実行すると、
-5 -1 -4 -1 -3 -1 -2 -1 -1 -1 0 1 1 -1 2 -1 3 -1 4 0 5 -1 6 -1 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0
といった感じだ。ファイルディスクリプタ 4 は本当にオープンされているのかもしれないが、7 以降はなんでなんだろう。オープンされているとは思えないが。。。
さて、話をもとに戻すと、read() のファイルディスクリプタが 0 になるタイミングをうまく調整して write() の呼ばれる回数をコントロールしているということだ。
問題の終了・公開後、hinoe さんにより、nai さんの解答ベースにした、56B がでた。以下の通りだ。
i;main(n){for(;read(i*=--i+n-49<8u,&n,1);)write(n!=48);}
nai さんの解答との違いは、数値判定法。atoi() を使わなくても、unsigned で計算することにより、あるアスキーレンジだけをうまく取り出すことができる。つまり、
n-48<10u
とやることで、n が '0'〜'9' の時のみ true となるのだ。
しかし、この問題、当初、68B あたりから戦いが始まった。よく縮まるものだ。
sed
sedもなかなか面白かった。sed の場合は、効率よく置換することで、縮まった。tails さんとは、何度か battle したが、最後は何とかトップをゲットできた。しかし、tails さんも最終的には、同率トップで、62B だが、解答は結構ちがうな。
nn: s/0//g s/[3569]/&&&/g s/[478]\|99/&&&&/g s/[268]\|55\|777/&&/g tails: s/[367]\|\([4-9]\)/0&&&\1/g s/[26-9]/&&/g s/0[579]/&&/g s/0//g
tails さんのは、結構技巧的だな。よくこんなの思いつくな。すごい。
1.3 or 6 or 7 なら、0xxx に展開し、4 or 5 or 8 or 9 なら、0xxxx に展開する。
2.2 or 6〜9 なら、dup する。つまり、この時点で、
2 => 22 3 => 0333 4 => 04444 5 => 05555 6 => 0666666 7 => 0777777 8 => 088888888 9 => 099999999
3.次に、05 or 07 or 09 はdup する。
2 => 22 3 => 0333 4 => 04444 5 => 0505555 6 => 0666666 7 => 070777777 8 => 088888888 9 => 09099999999
4.最後に 0 を消せば、目的通りになる。
〜〜〜〜〜〜〜〜
さて、endless 問題がいくつか出題された。
sin curve
微妙。embed 解答になりそう。vi / gs はそれっぽい。
BuzzFib
こちらは、FizzBuzz と Fibonacci Numbers の解答を混ぜたらできあがった。ただ、C は、FizzBuzz の最短解を得ていないので、とりあえず、投稿はやめておこう。
〜〜〜〜〜〜〜〜
さて(その2)、
あなごるサーバーが引越しし、かつ、言語のバージョンがアップされた。JavaScript がちょっと影響が大きかった。というのは、かつては、RegExp の exec() 関数は、簡便に、
/foo/(s)
などと書けた。ところが、これができなくなってしまった。今後は、
/foo/.exec(s)
と書かなければならない。なんでも、かつては、
typeof /foo/ === 'function'
だったのが、
typeof /foo/ === 'object'
になったのだそうだ。ゴルフ的には残念だ。
また、SpiderMonkey の API で、read() が追加された。これは、ファイルを読むものだ。ただ、あまり、ファイルを読み込む問題はあなごるでは出題されていない。print file や Check for brainwave activity などがファイルを扱う数少ない例なので、とりあえず、更新しておいた。
Groovy も 1.6 から 1.8 に上がったので、新しい機能がある。ゴルフ的には、Slashy String が使えるケースがあるかも。正規表現用の文字列構築として、
/foo bar baz/
という文字列リテラルが書けるが、これが複数行にまたがることができるようになった。つまり、
s=/foo bar baz/
などと書ける。そんなには有用でないかな(ゴルフ的に)。
2011/11/03 追記
JavaScript の Version Up による影響が他にもあった。かつて、文字列の長さは、
'abcdef'[-1] // -> 6
として得られたが、これも使えなくなった。今は、undefined が返る。
'abcdef'.length // -> 6
とする必要がある。