code golf


久々にrubyでgolfをやってみた。
このサイトのgolfを試してみた。そのNo.902の1 2 32 4 512というものである。具体的には、2のn乗で1から100までの数字から始まるものを順に探して表示するというものである。まず、普通に書いてみたのが、

100.times{|i|r=1;r*=2 until r.to_s=~/^#{i+1}/;p r}

で50bytesである。そのすぐ後に、スペースを取り除けることに気が付き、

100.times{|i|r=1;r*=2until"#{r}"=~/^#{i+1}/;p r}
として、48bytesまでになった。ここから、いろいろな工夫をしてみたが、どうしても48を切ることができなかった。例えば、

1.upto(100){|i|r=1;r*=2until"#{r}"=~/^#{i}/;p r}
1.upto(100){|i|r=1;r*=2until"%s"%r=~/^#{i}/;p r}
1.upto(100){|i|r=1;r*=2until"#{r}"[/^#{i}/];p r}
1.upto(100){|i|r=1;$_="#{r*=2}"until/^#{i}/;p r}

などを作ったが、何をやっても48止まりだった。特に、最後のは1に対する答えが16になってしまうという欠点もあるし。ruby1.8なら、100の代わりに?dを使うという技を使えるのだが。その時、一位の人は46で二位が47だった。10bytesぐらい差をつけられていたら、もう諦めるのだが、数byteとかだと、なんとかなるのでは無いかと思ってしまう。散々考えていたら、昨晩、47に到達した。

($.+=r=1;r*=2until"#{r}"=~/^#$./;p r)until$.>99

というものである。行数を表す組み込み変数$.を使って、初期値の代入と#{}の括弧をなくしたり、最初に1を足すことによって、100の代わりに99を使えるようにして、なんとか1byte減らすことに成功した。これでなんとか二位には追いついたが、一位の46bytesはどうやっているのか、全く見当もつかない。

2015/6/30追記 二位の人は、ruby1.8流のやり方をしていた。これなら、1.9以降でも動く私のscriptの方が上とも言える。一位の人は、これに加えて、補数を求める~演算子を使っていた。なるほど、これなら100を99までで良くなるのでtimesが使えるし、行頭の^も省略できる。