だいぶ遅くなってしまいましたが、先日東京Ruby会議10で行われたコードゴルフの結果発表を行いたいと思います!(パチパチ

コードゴルフ

問題は、「引数を二つ受け取って(最小値と最大値)、その間の数字に対してFizzBuzz問題を解いてください」というものでした。

例えばこういうことですね。
$ ruby fizzbuzz.rb 1 5
1
2
Fizz
4
Buzz

東京Ruby会議10「コードゴルフに挑戦!」〜最終順位発表 - blog.code.iq│CodeIQにて、景品プレゼントのために上位の方にはメールを送っていただき、その結果、1位がttakuru88さん、2位がtmtmsさんと決まりました(3位は該当者なし)。おめでとうございます!!

そこでせっかくなのでこのお二人とあとは特別解としてhokacchaさんの解答を紹介したいと思います。コードゴルフに参加した方も参加してない方も、ぜひ参考にしてみてください〜

まず1位のttakuru88さん。
eval(ARGV*'..').each{|i|puts"#{i}\r#{[:Fizz][i%3]}#{[:Buzz][i%5]}"}

続いて2位のtmtmsさん。
puts eval($**'..').map{|k|a=[[:Fizz][k%3],[:Buzz][k%5]]*'';a==''?k:a}

お二人とも最初に引数を配列で受け取ってそれに '..' という文字列を掛けています。何が行われているかわかるでしょうか。

実はArrayクラスで*メソッドを利用すると数値か文字列かによって挙動が変わるのです。
# 数値を渡した場合
[1, 2, 3] * 3
=> [1, 2, 3, 1, 2, 3, 1, 2, 3]

# 文字列を渡した場合
[1, 2, 3] * '3'
=> "13233" # [1, 2, 3].join('3') と同じ挙動

joinを使った方が(圧倒的に)わかりやすいですが、コードゴルフということでこんな書き方になっているんですね。

また、お二人引数の受け取り方が微妙に書き方が違いますが、実は引数を受け取る ARGV は $* でも同じ意味になります。これを使えばttakuru88さんのコードももっと短くなりますね :)

さらにこのようなコードが書かれてることに気付きます。
[:Fizz][i % 3]

これは :Fizz という要素をひとつだけ持つ配列に対してインデックスを指定しています。
[:Fizz][0 % 3] # => :Fizz
[:Fizz][1 % 3] # => nil
[:Fizz][2 % 3] # => nil
[:Fizz][3 % 3] # => :Fizz

コードゴルフは普段使わないような記法を使ったりするけど、頭の体操みたいで面白いですね!そんな書き方出来るのかー!!みたいな発見がきっとあると思います。

最後に特別解のhokacchaさん。http://690.jp/24にアクセスすると…w
eval `curl -sL 690.jp/24`
このエントリーをはてなブックマークに追加